├── .github ├── FUNDING.yml └── workflows │ ├── expo-build-test.yml │ ├── native-build-test.yml │ └── web-build-test.yml ├── .gitignore ├── OURS-EXPO ├── .github │ └── workflows │ │ └── publish.yml ├── README.md ├── assets │ ├── icon.png │ └── splash.png ├── documentation │ ├── expo-demo.jpg │ └── rnsk-logo.jpg └── src │ └── index.js ├── OURS-NATIVE ├── App.js ├── README.md ├── android │ └── app │ │ └── src │ │ └── main │ │ └── res │ │ ├── drawable-xxhdpi │ │ └── launch_screen.png │ │ └── layout │ │ └── launch_screen.xml ├── documentation │ ├── deploy.md │ ├── faqs.md │ ├── file-structure.md │ └── rnsk-logo.jpg ├── fastlane │ ├── Appfile │ ├── Fastfile │ ├── README.md │ ├── metadata │ │ └── android │ │ │ └── en-GB │ │ │ ├── full_description.txt │ │ │ ├── short_description.txt │ │ │ ├── title.txt │ │ │ └── video.txt │ └── update-app-version.sh ├── index.js ├── ios │ ├── Base.lproj │ │ └── LaunchScreen.xib │ └── Images.xcassets │ │ ├── AppIcon.appiconset │ │ ├── 120.png │ │ ├── 180.png │ │ └── Contents.json │ │ └── LaunchScreen.imageset │ │ ├── Contents.json │ │ ├── LaunchImage.png │ │ ├── LaunchImage2x.png │ │ └── LaunchImage3x.png └── src │ ├── components │ ├── About.js │ ├── Articles │ │ ├── Form.js │ │ ├── List.js │ │ └── Single.js │ └── UI │ │ ├── Error.js │ │ ├── Header.js │ │ ├── Loading.js │ │ ├── Messages.js │ │ ├── Spacer.js │ │ └── index.js │ ├── constants │ ├── config.js │ └── navigation.js │ ├── index.js │ ├── lib │ └── api.js │ ├── routes │ └── index.js │ ├── store │ └── index.js │ └── tests │ ├── __mocks__ │ └── @react-native-community │ │ └── async-storage.js │ └── components │ ├── Articles │ ├── List.test.js │ ├── Single.test.js │ └── __snapshots__ │ │ ├── List.test.js.snap │ │ └── Single.test.js.snap │ └── UI │ ├── Error.test.js │ ├── Header.test.js │ ├── Loading.test.js │ ├── Messages.test.js │ ├── Spacer.test.js │ └── __snapshots__ │ ├── Error.test.js.snap │ ├── Header.test.js.snap │ ├── Loading.test.js.snap │ ├── Messages.test.js.snap │ └── Spacer.test.js.snap ├── OURS-WEB ├── .github │ └── workflows │ │ └── publish.yml ├── README.md ├── documentation │ ├── rsk-logo.jpg │ └── web-demo.jpg ├── public │ ├── 404.html │ └── CNAME └── src │ ├── assets │ ├── images │ │ └── app-icon.png │ └── styles │ │ ├── _bootstrap.scss │ │ ├── components │ │ ├── _footer.scss │ │ ├── _forms.scss │ │ ├── _header.scss │ │ ├── _mobile-tab-bar.scss │ │ └── _tables.scss │ │ └── style.scss │ ├── components │ ├── About.js │ ├── Articles │ │ ├── Form.js │ │ ├── List.js │ │ └── Single.js │ ├── Templates │ │ ├── Dashboard.js │ │ └── Nothing.js │ └── UI │ │ ├── Error.js │ │ ├── Footer.js │ │ ├── Header.js │ │ ├── Loading.js │ │ ├── MobileTabBar.js │ │ ├── Notice.js │ │ ├── PageTitle.js │ │ ├── TablePagination.js │ │ └── index.js │ ├── constants │ └── config.js │ ├── index.js │ ├── lib │ ├── api.js │ ├── cookies.js │ ├── jwt.js │ └── service-worker.js │ ├── routes │ ├── PrivateRoute.js │ ├── Route.js │ └── index.js │ ├── setupTests.js │ ├── store │ └── index.js │ └── tests │ ├── components │ ├── Articles │ │ ├── Form.test.js │ │ ├── List.test.js │ │ ├── Single.test.js │ │ └── __snapshots__ │ │ │ ├── Form.test.js.snap │ │ │ ├── List.test.js.snap │ │ │ └── Single.test.js.snap │ └── UI │ │ ├── Error.test.js │ │ ├── Footer.test.js │ │ ├── Header.test.js │ │ ├── Loading.test.js │ │ ├── MobileTabBar.test.js │ │ ├── PageTitle.test.js │ │ ├── TablePagination.test.js │ │ └── __snapshots__ │ │ ├── Error.test.js.snap │ │ ├── Footer.test.js.snap │ │ ├── Header.test.js.snap │ │ ├── Loading.test.js.snap │ │ ├── MobileTabBar.test.js.snap │ │ ├── PageTitle.test.js.snap │ │ └── TablePagination.test.js.snap │ ├── constants │ └── config.test.js │ └── lib │ └── jwt.test.js ├── OURS ├── .editorconfig ├── .eslintrc.js ├── .github │ ├── FUNDING.yml │ └── workflows │ │ └── test.yml ├── .prettierrc.js ├── ISSUE_TEMPLATE.md ├── LICENSE ├── documentation │ ├── contributing.md │ ├── file-structure.md │ └── testing.md └── src │ ├── constants │ └── messages.js │ ├── containers │ ├── Articles │ │ ├── Form.js │ │ ├── List.js │ │ └── Single.js │ └── index.js │ ├── images │ ├── app-icon.png │ └── launch.png │ ├── lib │ ├── format-error-messages.js │ ├── images.js │ ├── pagination.js │ └── string.js │ ├── models │ ├── articles.js │ └── index.js │ ├── store │ └── articles.js │ └── tests │ ├── __mocks__ │ ├── react-native-gesture-handler.js │ ├── react-native-reanimated.js │ ├── react-native-tab-view.js │ ├── react-navigation-stack.js │ └── react-redux.js │ ├── lib │ ├── format-error-messages.test.js │ ├── images.test.js │ ├── pagination.test.js │ └── string.test.js │ └── models │ └── articles.test.js ├── README.md └── build.sh /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: mcnamee 2 | -------------------------------------------------------------------------------- /.github/workflows/expo-build-test.yml: -------------------------------------------------------------------------------- 1 | name: Expo Build + Test 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * MON' 6 | push: 7 | branches: 8 | - master 9 | pull_request: 10 | branches: 11 | - master 12 | 13 | jobs: 14 | build: 15 | runs-on: macOS-latest 16 | strategy: 17 | matrix: 18 | node-version: [14.x] 19 | 20 | steps: 21 | - uses: actions/checkout@v1 22 | - name: Use Node.js ${{ matrix.node-version }} 23 | uses: actions/setup-node@v1 24 | with: 25 | node-version: ${{ matrix.node-version }} 26 | - name: Get Commit Message 27 | run: | 28 | echo "::set-env name=COMMIT_MESSAGE::$(git log -1 --pretty=format:%s)" 29 | - name: Build a fresh Expo App 30 | run: | 31 | bash build.sh --name=ReactNativeExpoStarterKit --type=3 32 | - name: Lint 33 | run: | 34 | ./node_modules/.bin/eslint "src/**/*.js" 35 | - name: Jest Tests 36 | run: | 37 | ./node_modules/.bin/jest --silent -u 38 | env: 39 | CI: true 40 | - name: Commit files to React Native (Expo) Starter Kit repo 41 | run: | 42 | rm -rf .git 43 | git clone https://github.com/mcnamee/react-native-expo-starter-kit.git TEMP 44 | mv TEMP/.git .git 45 | rm -rf TEMP 46 | git config --local user.email "${{ secrets.GH_EMAIL }}" 47 | git config --local user.name "mcnamee/react-native-boilerplate-builder" 48 | git add -A 49 | git commit -m "$COMMIT_MESSAGE (RNBB Bot)" -a 50 | - name: Push files to React Native Starter Kit repo 51 | uses: ad-m/github-push-action@master 52 | with: 53 | github_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} 54 | repository: mcnamee/react-native-expo-starter-kit 55 | branch: master 56 | -------------------------------------------------------------------------------- /.github/workflows/native-build-test.yml: -------------------------------------------------------------------------------- 1 | name: Native Build + Test 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * MON' 6 | push: 7 | branches: 8 | - master 9 | pull_request: 10 | branches: 11 | - master 12 | 13 | jobs: 14 | build: 15 | runs-on: macOS-latest 16 | strategy: 17 | matrix: 18 | node-version: [14.x] 19 | 20 | steps: 21 | - uses: actions/checkout@v1 22 | - name: Use Node.js ${{ matrix.node-version }} 23 | uses: actions/setup-node@v1 24 | with: 25 | node-version: ${{ matrix.node-version }} 26 | - name: Build a fresh React Native App 27 | run: | 28 | bash build.sh --name=ReactNativeStarterKit --type=2 29 | - name: Lint 30 | run: | 31 | ./node_modules/.bin/eslint "src/**/*.js" 32 | - name: Jest Tests 33 | run: | 34 | ./node_modules/.bin/jest --silent -u 35 | env: 36 | CI: true 37 | - name: Commit files to React Native Starter Kit repo 38 | run: | 39 | rm -rf .git 40 | git clone https://github.com/mcnamee/react-native-starter-kit.git TEMP 41 | mv TEMP/.git .git 42 | rm -rf TEMP 43 | git config --local user.email "${{ secrets.GH_EMAIL }}" 44 | git config --local user.name "mcnamee/react-native-boilerplate-builder" 45 | git add -A 46 | git commit -m "RNBB Bot updates" -a 47 | - name: Push files to React Native Starter Kit repo 48 | uses: ad-m/github-push-action@master 49 | with: 50 | github_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} 51 | repository: mcnamee/react-native-starter-kit 52 | branch: master 53 | -------------------------------------------------------------------------------- /.github/workflows/web-build-test.yml: -------------------------------------------------------------------------------- 1 | name: Web Build + Test 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * MON' 6 | push: 7 | branches: 8 | - master 9 | pull_request: 10 | branches: 11 | - master 12 | 13 | jobs: 14 | build: 15 | runs-on: macOS-latest 16 | strategy: 17 | matrix: 18 | node-version: [14.x] 19 | 20 | steps: 21 | - uses: actions/checkout@v1 22 | - name: Use Node.js ${{ matrix.node-version }} 23 | uses: actions/setup-node@v1 24 | with: 25 | node-version: ${{ matrix.node-version }} 26 | - name: Get Commit Message 27 | run: | 28 | echo "::set-env name=COMMIT_MESSAGE::$(git log -1 --pretty=format:%s)" 29 | - name: Build a fresh React App 30 | run: | 31 | bash build.sh --name=ReactStarterKit --type=1 32 | - name: Lint 33 | run: | 34 | ./node_modules/.bin/eslint "src/**/*.js" 35 | - name: Jest Tests 36 | run: | 37 | yarn test -u 38 | env: 39 | CI: true 40 | - name: Commit files to React Starter Kit repo 41 | run: | 42 | rm -rf .git 43 | git clone https://github.com/mcnamee/react-starter-kit.git TEMP 44 | mv TEMP/.git .git 45 | rm -rf TEMP 46 | git config --local user.email "${{ secrets.GH_EMAIL }}" 47 | git config --local user.name "mcnamee/react-native-boilerplate-builder" 48 | git add -A 49 | git commit -m "$COMMIT_MESSAGE (RNBB Bot)" -a 50 | - name: Push files to React Starter Kit repo 51 | uses: ad-m/github-push-action@master 52 | with: 53 | github_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} 54 | repository: mcnamee/react-starter-kit 55 | branch: master 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # node.js 6 | # 7 | node_modules/ 8 | npm-debug.log 9 | yarn-error.log 10 | -------------------------------------------------------------------------------- /OURS-EXPO/.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Expo Publish 2 | on: 3 | push: 4 | branches: 5 | - master 6 | jobs: 7 | publish: 8 | name: Install and publish 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: actions/setup-node@v1 13 | with: 14 | node-version: 12.x 15 | - uses: expo/expo-github-action@v5 16 | with: 17 | expo-version: 3.x 18 | expo-username: ${{ secrets.EXPO_CLI_USERNAME }} 19 | expo-password: ${{ secrets.EXPO_CLI_PASSWORD }} 20 | - run: yarn install 21 | - run: expo publish 22 | -------------------------------------------------------------------------------- /OURS-EXPO/README.md: -------------------------------------------------------------------------------- 1 |
2 | React Native Expo Starter Kit 3 |

4 |

React Native (Expo) App

5 |

6 | React Native Expo Demo 7 |

8 | 9 | 10 | builds 11 | 12 | 13 | license 14 | 15 | 16 |
17 |

18 | What is this? 19 |   —   20 | Usage 21 |   —   22 | Docs 23 |   —   24 | Need help? 25 |

26 |
27 |
28 | 29 | --- 30 | 31 | ### Looking for something else? 32 | 33 | - [React Native Starter Kit (without Expo) / Boilerplate](https://github.com/mcnamee/react-native-starter-kit) 34 | - [React Starter Kit (web) / Boilerplate](https://github.com/mcnamee/react-starter-kit) 35 | - [Previous Version (React Starter Kit (Web + Native) w/ Firebase)](https://github.com/mcnamee/react-native-starter-kit/tree/archive/v3) 36 | 37 | --- 38 | 39 | ## 👋 Intro 40 | 41 | This project was bootstrapped with the [React Boilerplate Builder](https://github.com/mcnamee/react-native-boilerplate-builder) by [Matt McNamee](https://mcnam.ee). 42 | 43 | The project is _super_ helpful to kick-start your next project, as it provides a lot of the common tools you may reach for, all ready to go. Specifically: 44 | 45 | - __[Expo](https://expo.io/)__ - The fastest way to build an app 46 | - __Flux architecture__ 47 | - [Redux](https://redux.js.org/docs/introduction/) 48 | - Redux Wrapper: [Rematch](https://github.com/rematch/rematch) 49 | - __Routing and navigation__ 50 | - [React Native Router Flux](https://github.com/aksonov/react-native-router-flux) 51 | - __Data Caching / Offline__ 52 | - [Redux Persist](https://github.com/rt2zz/redux-persist) 53 | - __UI Toolkit/s__ 54 | - [Native Base](https://nativebase.io/) 55 | - __Code Linting__ with 56 | - [Airbnb's JS Linting](https://github.com/airbnb/javascript) guidelines 57 | 58 | --- 59 | 60 | ## 🚀 Getting Started 61 | 62 | - Install `eslint`, `prettier` and `editor config` plugins into your IDE 63 | - Ensure your machine has the Expo CLI Installed (`npm install -g expo-cli`) 64 | 65 | ```bash 66 | # Install dependencies 67 | yarn install 68 | 69 | # Start the App 70 | # - The Expo CLI will provide options to open in [web, android or iOS] 71 | yarn start 72 | ``` 73 | 74 | --- 75 | 76 | ## 📖 Docs 77 | 78 | - [Contributing to this project](documentation/contributing.md) 79 | - [Tests & testing](documentation/testing.md) 80 | - [Understanding the file structure](documentation/file-structure.md) 81 | 82 | --- 83 | 84 | ## 👊 Further Help? 85 | 86 | This repo is a great place to start. But...if you'd prefer to sit back and have your new project built for you or just need some consultation, [get in touch with me directly](https://mcnam.ee) and I can organise a quote. 87 | -------------------------------------------------------------------------------- /OURS-EXPO/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcnamee/react-native-boilerplate-builder/28076ec2c3426a6b65744ff7a843544153c40049/OURS-EXPO/assets/icon.png -------------------------------------------------------------------------------- /OURS-EXPO/assets/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcnamee/react-native-boilerplate-builder/28076ec2c3426a6b65744ff7a843544153c40049/OURS-EXPO/assets/splash.png -------------------------------------------------------------------------------- /OURS-EXPO/documentation/expo-demo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcnamee/react-native-boilerplate-builder/28076ec2c3426a6b65744ff7a843544153c40049/OURS-EXPO/documentation/expo-demo.jpg -------------------------------------------------------------------------------- /OURS-EXPO/documentation/rnsk-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcnamee/react-native-boilerplate-builder/28076ec2c3426a6b65744ff7a843544153c40049/OURS-EXPO/documentation/rnsk-logo.jpg -------------------------------------------------------------------------------- /OURS-EXPO/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import * as Font from 'expo-font'; 3 | import PropTypes from 'prop-types'; 4 | import { Provider } from 'react-redux'; 5 | import { Router, Stack } from 'react-native-router-flux'; 6 | import { PersistGate } from 'redux-persist/es/integration/react'; 7 | 8 | import { Root, StyleProvider } from 'native-base'; 9 | import getTheme from '../native-base-theme/components'; 10 | import theme from '../native-base-theme/variables/commonColor'; 11 | 12 | import Routes from './routes/index'; 13 | import Loading from './components/UI/Loading'; 14 | 15 | class App extends React.Component { 16 | constructor() { 17 | super(); 18 | this.state = { loading: true }; 19 | } 20 | 21 | async componentDidMount() { 22 | await Font.loadAsync({ 23 | Roboto: require('native-base/Fonts/Roboto.ttf'), 24 | Roboto_medium: require('native-base/Fonts/Roboto_medium.ttf'), 25 | Ionicons: require('@expo/vector-icons/build/vendor/react-native-vector-icons/Fonts/Ionicons.ttf'), 26 | }); 27 | 28 | this.setState({ loading: false }); 29 | } 30 | 31 | render() { 32 | const { loading } = this.state; 33 | const { store, persistor } = this.props; 34 | 35 | if (loading) { 36 | return ; 37 | } 38 | 39 | return ( 40 | 41 | 42 | } persistor={persistor}> 43 | 44 | 45 | {Routes} 46 | 47 | 48 | 49 | 50 | 51 | ); 52 | } 53 | } 54 | 55 | App.propTypes = { 56 | store: PropTypes.shape({}).isRequired, 57 | persistor: PropTypes.shape({}).isRequired, 58 | }; 59 | 60 | export default App; 61 | -------------------------------------------------------------------------------- /OURS-NATIVE/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Root from './src/index'; 3 | import configureStore from './src/store/index'; 4 | 5 | const { persistor, store } = configureStore(); 6 | 7 | export default function App() { 8 | return ; 9 | } 10 | -------------------------------------------------------------------------------- /OURS-NATIVE/README.md: -------------------------------------------------------------------------------- 1 |
2 | React Native Starter Kit 3 |

4 |

React Native App

5 |

6 | 7 | 8 | builds 9 | 10 | 11 | license 12 | 13 | 14 |
15 |

16 | What is this? 17 |   —   18 | Usage 19 |   —   20 | Docs 21 |   —   22 | Need help? 23 |

24 |
25 |
26 | 27 | --- 28 | 29 | ### Looking for something else? 30 | 31 | - [React Native Starter Kit (Expo) / Boilerplate](https://github.com/mcnamee/react-native-expo-starter-kit) 32 | - [React Starter Kit (web) / Boilerplate](https://github.com/mcnamee/react-starter-kit) 33 | - [Previous Version (React Starter Kit (Web + Native) w/ Firebase)](https://github.com/mcnamee/react-native-starter-kit/tree/archive/v3) 34 | 35 | --- 36 | 37 | ## 👋 Intro 38 | 39 | This project was bootstrapped with the [React Boilerplate Builder](https://github.com/mcnamee/react-native-boilerplate-builder) by [Matt McNamee](https://mcnam.ee). 40 | 41 | The project is _super_ helpful to kick-start your next project, as it provides a lot of the common tools you may reach for, all ready to go. Specifically: 42 | 43 | - __Flux architecture__ 44 | - [Redux](https://redux.js.org/docs/introduction/) 45 | - Redux Wrapper: [Rematch](https://github.com/rematch/rematch) 46 | - __Routing and navigation__ 47 | - [React Native Router Flux](https://github.com/aksonov/react-native-router-flux) for native mobile navigation 48 | - __Data Caching / Offline__ 49 | - [Redux Persist](https://github.com/rt2zz/redux-persist) 50 | - __UI Toolkit/s__ 51 | - [Native Base](https://nativebase.io/) for native mobile 52 | - __Code Linting__ with 53 | - [Airbnb's JS Linting](https://github.com/airbnb/javascript) guidelines 54 | - __Deployment strategy__ 55 | - [Both manual and automated strategies](documentation/deploy.md) 56 | - __Splash Screen + Assets__ 57 | - [React Native Splash Screen](https://github.com/crazycodeboy/react-native-splash-screen) 58 | 59 | --- 60 | 61 | ## 🚀 Getting Started 62 | 63 | - Install [React Native Debugger](https://github.com/jhen0409/react-native-debugger/releases) and open before running the app 64 | - Install `eslint`, `prettier` and `editor config` plugins into your IDE 65 | - Ensure your machine has the [React Native dependencies installed](https://facebook.github.io/react-native/docs/getting-started) 66 | 67 | ```bash 68 | # Install dependencies 69 | yarn install && ( cd ios && pod install ) 70 | ``` 71 | 72 | #### iOS 73 | 74 | ```bash 75 | # Start in the iOS Simulator 76 | npx react-native run-ios --simulator="iPhone 11" 77 | ``` 78 | 79 | #### Android 80 | 81 | ```bash 82 | # Start in the Android Simulator 83 | # - Note: open Android Studio > Tools > AVD > Run a device 84 | # - Example device specs: https://medium.com/pvtl/react-native-android-development-on-mac-ef7481f65e47#d5da 85 | npx react-native run-android 86 | ``` 87 | 88 | --- 89 | 90 | ## 📖 Docs 91 | 92 | - [Contributing to this project](documentation/contributing.md) 93 | - [FAQs & Opinions](documentation/faqs.md) 94 | - [Tests & testing](documentation/testing.md) 95 | - [Understanding the file structure](documentation/file-structure.md) 96 | - [Deploy the app](documentation/deploy.md) 97 | 98 | --- 99 | 100 | ## 👊 Further Help? 101 | 102 | This repo is a great place to start. But...if you'd prefer to sit back and have your new project built for you or just need some consultation, [get in touch with me directly](https://mcnam.ee) and I can organise a quote. 103 | -------------------------------------------------------------------------------- /OURS-NATIVE/android/app/src/main/res/drawable-xxhdpi/launch_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcnamee/react-native-boilerplate-builder/28076ec2c3426a6b65744ff7a843544153c40049/OURS-NATIVE/android/app/src/main/res/drawable-xxhdpi/launch_screen.png -------------------------------------------------------------------------------- /OURS-NATIVE/android/app/src/main/res/layout/launch_screen.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /OURS-NATIVE/documentation/deploy.md: -------------------------------------------------------------------------------- 1 | # 🚀 Deploying 2 | 3 | ## Setting up a new app: 4 | 5 | The following steps should be followed for new projects. Once completed for your project, you won't need these steps again. 6 | 7 | *General* 8 | 9 | 1. Ensure you have admin access to the destination Google Play and Apple/iTunesConnect Developer accounts 10 | 1. Ensure you've named your app correctly and set a unique bundle identifier: 11 | - Use [react-native-rename](https://www.npmjs.com/package/react-native-rename) 12 | - eg. `react-native-rename "Travel App" -b com.junedomingo.travelapp` 13 | - Open the project in Xcode and double check that the Bundle ID has been updated (if not, correct it) 14 | 1. In both Google Play and iTunes Connect: 15 | - Setup a new app 16 | - Use the _manual_ method below to build and deploy the app for the first time 17 | - _iOS Note: when you deploy the iOS app for the first time, you'll select 'Automatic Key Management'. Xcode will generate a private distribution key. Ensure you save this (eg. to a password safe) so that others can distribute the app too_ 18 | 19 | *Android* 20 | 21 | 1. Generate/configure Android key: 22 | - `( cd android/app && keytool -genkeypair -v -keystore android-release-key.keystore -alias jims-app-release-key -keyalg RSA -keysize 2048 -validity 10000 )` (note: change `jims-app-release-key` to your own alias) 23 | - Save the key to a secure password safe (don't commit it to the repo) 24 | 1. [Setup the Gradle variables](https://reactnative.dev/docs/signed-apk-android#setting-up-gradle-variables), using the alias and password/s (that you set in the previous command) in: `android/gradle.properties` 25 | 1. [Add the release signing config to your app's Gradle config](https://reactnative.dev/docs/signed-apk-android#adding-signing-config-to-your-apps-gradle-config) in: `android/app/build.gradle` 26 | 27 | *Fastlane* 28 | 29 | 1. Using the __account owner's__ login (i.e. we want to create the API credentials from the owner's account) - follow the [steps here](https://docs.fastlane.tools/actions/supply/#setup) to generate API credentials for Google Play. Download and place the json file here: `android/app/google-play-android-developer.json`. Save the key to a secure password safe (don't commit it to the repo) 30 | 1. Update the `package_name` and `itc_team_id` (App Store Connect Team ID) in `faslane/Appfile` to match the bundle of your app 31 | 1. Update the following in `fastlane/Fastfile`: 32 | - `app_identifier: com.app.bundle` - where com.app.bundle is your bundle id 33 | - `name.xcodeproj` - to the name of your Xcode project file 34 | - `scheme: 'name'` - where name is your scheme (eg. AppName) 35 | 1. Run `fastlane supply init` (which will download the meta data of the uploaded app, from the stores) 36 | 37 | --- 38 | 39 | ## Configuring your machine to deploy: 40 | 41 | The following steps are provided for developers who have the project setup on their machine, but have not yet deployed the app. Follow these once, and you won't need these steps again. 42 | 43 | 1. Android (Google Play): 44 | - Add the Android keys (found in the password safe) to your local project: 45 | - `android/app/android-release-key.keystore` 46 | - `android/app/google-play-android-developer.json` 47 | - [Android/Google dependencies](https://facebook.github.io/react-native/docs/getting-started#installing-dependencies-1) 48 | 1. iOS (Apple iTunes Connect): 49 | - In Xcode, login to the appropriate account to give you access to deploy 50 | - Install the appropriate distribution private key (found in your password safe) 51 | - Download the file and double click it to add to Keychain 52 | 1. Fastlane (for automated deployments on both platforms): 53 | - Install Fastlane - `brew cask install fastlane` 54 | - Install Xcode command line tools - `xcode-select --install` 55 | 56 | --- 57 | 58 | ## Deploying 59 | 60 | - Update the __app version__ - `bash fastlane/update-app-version.sh` 61 | - __Merge__ `develop` branch into `master` branch with a _merge commit_ 62 | - Git __Tag__ the master merge commit. The tag name should be the new version number 63 | - Bundle and deploy by the following: 64 | 65 | ### 1.0 (Automated) Fastlane 66 | 67 | Fastlane automatically builds and deploys the app to the app stores (TestFlight and Play Store Beta). 68 | 69 | 1. _Hint: Did you update the version number, merge to master and tag?_ 70 | 1. __iOS__: Deploy to Apple TestFlight - `fastlane ios beta` 71 | 1. __Android__: Deploy to Google Play Beta - `fastlane android beta` 72 | 73 | ### 2.0 Manual 74 | 75 | *2.2.1 iOS* 76 | 77 | _*Note: it may be required to use the legacy build system (XCode -> File -> Project Settings -> Change the build system to 'Legacy Build System')_ 78 | 79 | 1. _Hint: Did you update the version number, merge to master and tag?_ 80 | 1. Ensure you've changed the Xcode 'Build Config' to Release 81 | 1. Select 'Generic iOS Device' from devices 82 | 1. Product > Archive 83 | 1. Open Organiser 84 | - Find the archive and click 'Validate' to check that it's ok 85 | - Click the big 'Upload to App Store...' when ready (untick BitCode checkbox) 86 | 87 | *2.2.2 Android* 88 | 89 | 1. _Hint: Did you update the version number, merge to master and tag?_ 90 | 1. `( cd android && ./gradlew app:bundleRelease )` 91 | 1. Upload the generated file (`/android/app/build/outputs/bundle/release/app.aab`) to Google Play 92 | -------------------------------------------------------------------------------- /OURS-NATIVE/documentation/faqs.md: -------------------------------------------------------------------------------- 1 | # FAQs 2 | 3 | ## Code Style Guide? 4 | 5 | We're using [Airbnb's](https://github.com/airbnb/javascript) JS/React Style Guide with ESLint linting. We just like it :) 6 | 7 | ## React, hah? How do I? 8 | 9 | [React Native Express](http://www.reactnativeexpress.com/) is a great site to get you started, specifically: 10 | 11 | - [Get your head around ES6](http://www.reactnativeexpress.com/es6) 12 | - [What is JSX?](http://www.reactnativeexpress.com/jsx) 13 | - [What are Components?](http://www.reactnativeexpress.com/components) 14 | - [React State](http://www.reactnativeexpress.com/data_component_state) 15 | - [Redux](http://www.reactnativeexpress.com/redux) 16 | - [Rematch](https://rematch.gitbooks.io/rematch/) 17 | 18 | Once you've got your head around the basics, checkout the [React Native](https://facebook.github.io/react-native/) and [React](https://reactjs.org/) websites, specifically 19 | 20 | - Go through ['The Basics'](https://facebook.github.io/react-native/docs/props.html) 21 | - Gain an understanding of the [components](https://facebook.github.io/react-native/docs/activityindicator.html) React Native provides out of the box 22 | 23 | ## How do I change the Reach Native App Icon? 24 | 25 | You might want to change the app icons for iOS and Android. You can use the [app-icon](https://github.com/dwmkerr/app-icon) utility to generate all of the required icons for each required size. 26 | 27 | ```bash 28 | npx app-icon generate -i ./src/images/app-icon.png 29 | ``` 30 | 31 | This will generate the icon in all required sizes. You can also add labels to icons, which can be useful for testing. This example labels the icon with 'beta' and the current version number: 32 | 33 | ```bash 34 | npx app-icon label -i ./src/images/app-icon.png -o temp.png --top beta --bottom $(jq .version package.json) 35 | npx app-icon generate -i temp.png 36 | ``` 37 | 38 | ![Icon Labelled with Beta and Version Number](./icon-label.png) 39 | 40 | ## How do I change the React Native App Name/Bundle ID? 41 | 42 | - Use [react-native-rename](https://www.npmjs.com/package/react-native-rename) 43 | - eg. `npx react-native-rename "The Facebook" -b com.thefacebook.mobile-app` 44 | - Open the project in Xcode and double check that the Bundle ID has been updated (if not, correct it) 45 | -------------------------------------------------------------------------------- /OURS-NATIVE/documentation/file-structure.md: -------------------------------------------------------------------------------- 1 | ## File structure 2 | 3 | - `/android` - contains native code specific to the Android OS 4 | - `/documentation` - as the name suggests - any docs 5 | - `/fastlane` - configuration for auto-deploying the app to the app stores via Fastlane 6 | - `/ios` - native code specific to iOS 7 | - `/native-base-theme` - the app uses Native Base for base elements. You can edit the styles in here 8 | - `/src` - contains our JS and CSS code. `index.js` is the entry-point for our file, and is mandatory. 9 | - `/components` - 'Dumb-components' / presentational. [Read More →](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0) 10 | - `/constants` - App-wide variables 11 | - `/containers` - 'Smart-components' that connect business logic to presentation [Read More →](https://redux.js.org/docs/basics/UsageWithReact.html#presentational-and-container-components) 12 | - `/images` - hmm...what could this be? 13 | - `/lib` - Utils and custom libraries 14 | - `/models` - Rematch models combining actions, reducers and state. [Read More →](https://github.com/rematch/rematch#step-2-models) 15 | - `/routes`- wire up the router with any & all screens [Read More →](https://github.com/aksonov/react-native-router-flux) 16 | - `/store`- Redux Store - hooks up the stores and provides initial/template states [Read More →](https://redux.js.org/docs/basics/Store.html) 17 | - `/tests` - contains all of our tests, where the test file matches the resptive file from `/src` 18 | - `index.js` - The starting place for our app 19 | -------------------------------------------------------------------------------- /OURS-NATIVE/documentation/rnsk-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcnamee/react-native-boilerplate-builder/28076ec2c3426a6b65744ff7a843544153c40049/OURS-NATIVE/documentation/rnsk-logo.jpg -------------------------------------------------------------------------------- /OURS-NATIVE/fastlane/Appfile: -------------------------------------------------------------------------------- 1 | json_key_file("android/app/google-play-android-developer.json") # Path to the Android json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one 2 | package_name("com.AwesomeProject") # e.g. com.krausefx.app 3 | # itc_team_id "" # e.g. 1233445 - the iTunes Connect Team ID 4 | -------------------------------------------------------------------------------- /OURS-NATIVE/fastlane/Fastfile: -------------------------------------------------------------------------------- 1 | fastlane_version '2.125.0' 2 | 3 | before_all do 4 | # ensure_git_branch 5 | # ensure_git_status_clean 6 | # git_pull 7 | end 8 | 9 | platform :ios do 10 | desc 'Fetch certificates and provisioning profiles' 11 | lane :certificates do 12 | match(app_identifier: 'com.AwesomeProject.app', type: 'development', readonly: true) 13 | match(app_identifier: 'com.AwesomeProject.app', type: 'appstore', readonly: true) 14 | end 15 | 16 | desc 'Build the iOS application.' 17 | private_lane :build do 18 | # certificates 19 | # increment_build_number(xcodeproj: './ios/AwesomeProject.xcodeproj') 20 | gym(scheme: 'AwesomeProject', workspace: './ios/AwesomeProject.xcworkspace') 21 | end 22 | 23 | desc 'Ship to Testflight.' 24 | lane :beta do 25 | build 26 | pilot 27 | # commit_version_bump(message: 'Bump build', xcodeproj: './ios/AwesomeProject.xcodeproj') 28 | # push_to_git_remote 29 | end 30 | end 31 | 32 | platform :android do 33 | desc 'Build the Android application.' 34 | private_lane :build do 35 | gradle(task: 'clean', project_dir: 'android/') 36 | gradle(task: 'bundle', build_type: 'Release', project_dir: 'android/') 37 | end 38 | 39 | desc 'Ship to Playstore Beta.' 40 | lane :beta do 41 | build 42 | supply(track: 'beta', track_promote_to: 'beta') 43 | # git_commit(path: ['./android/gradle.properties'], message: 'Bump versionCode') 44 | # push_to_git_remote 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /OURS-NATIVE/fastlane/README.md: -------------------------------------------------------------------------------- 1 | fastlane documentation 2 | ================ 3 | # Installation 4 | 5 | Make sure you have the latest version of the Xcode command line tools installed: 6 | 7 | ``` 8 | xcode-select --install 9 | ``` 10 | 11 | Install _fastlane_ using 12 | ``` 13 | [sudo] gem install fastlane -NV 14 | ``` 15 | or alternatively using `brew cask install fastlane` 16 | 17 | # Available Actions 18 | ## iOS 19 | ### ios certificates 20 | ``` 21 | fastlane ios certificates 22 | ``` 23 | Fetch certificates and provisioning profiles 24 | ### ios beta 25 | ``` 26 | fastlane ios beta 27 | ``` 28 | Ship to Testflight. 29 | 30 | ---- 31 | 32 | ## Android 33 | ### android beta 34 | ``` 35 | fastlane android beta 36 | ``` 37 | Ship to Playstore Beta. 38 | 39 | ---- 40 | 41 | This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run. 42 | More information about fastlane can be found on [fastlane.tools](https://fastlane.tools). 43 | The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools). 44 | -------------------------------------------------------------------------------- /OURS-NATIVE/fastlane/metadata/android/en-GB/full_description.txt: -------------------------------------------------------------------------------- 1 | AwesomeProject 2 | -------------------------------------------------------------------------------- /OURS-NATIVE/fastlane/metadata/android/en-GB/short_description.txt: -------------------------------------------------------------------------------- 1 | AwesomeProject 2 | -------------------------------------------------------------------------------- /OURS-NATIVE/fastlane/metadata/android/en-GB/title.txt: -------------------------------------------------------------------------------- 1 | AwesomeProject 2 | -------------------------------------------------------------------------------- /OURS-NATIVE/fastlane/metadata/android/en-GB/video.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcnamee/react-native-boilerplate-builder/28076ec2c3426a6b65744ff7a843544153c40049/OURS-NATIVE/fastlane/metadata/android/en-GB/video.txt -------------------------------------------------------------------------------- /OURS-NATIVE/fastlane/update-app-version.sh: -------------------------------------------------------------------------------- 1 | ANDROID_FILE="android/app/build.gradle" 2 | TEMP_ANDROID_FILE="${ANDROID_FILE}.txt" 3 | 4 | IOS_FILE="ios/AwesomeProject/Info.plist" 5 | TEMP_IOS_FILE="${IOS_FILE}.txt" 6 | 7 | IOS_BUILD_NUMBER=1 8 | 9 | CURRENT_VERSION_NAME=$( /usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "${IOS_FILE}" ) 10 | 11 | # --- 12 | 13 | echo "••• What's the new App Version? (current version: $CURRENT_VERSION_NAME)" 14 | read APP_VERSION_NAME 15 | 16 | # --- 17 | 18 | # Android 19 | cat ${ANDROID_FILE} | sed "s/versionName \".*\"/versionName \"${APP_VERSION_NAME}\"/" > ${TEMP_ANDROID_FILE} 20 | echo "$(awk '{sub(/versionCode [[:digit:]]+$/,"versionCode "$2+1)}1' ${TEMP_ANDROID_FILE})" > ${TEMP_ANDROID_FILE} 21 | cat ${TEMP_ANDROID_FILE} > ${ANDROID_FILE} 22 | rm -f ${TEMP_ANDROID_FILE} 23 | 24 | # iOS 25 | /usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString ${APP_VERSION_NAME}" "${IOS_FILE}" 26 | /usr/libexec/PlistBuddy -c "Set :CFBundleVersion ${IOS_BUILD_NUMBER}" "${IOS_FILE}" 27 | -------------------------------------------------------------------------------- /OURS-NATIVE/index.js: -------------------------------------------------------------------------------- 1 | import { AppRegistry } from 'react-native'; 2 | import App from './App'; 3 | import { name as appName } from './app.json'; 4 | 5 | AppRegistry.registerComponent(appName, () => App); 6 | -------------------------------------------------------------------------------- /OURS-NATIVE/ios/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /OURS-NATIVE/ios/Images.xcassets/AppIcon.appiconset/120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcnamee/react-native-boilerplate-builder/28076ec2c3426a6b65744ff7a843544153c40049/OURS-NATIVE/ios/Images.xcassets/AppIcon.appiconset/120.png -------------------------------------------------------------------------------- /OURS-NATIVE/ios/Images.xcassets/AppIcon.appiconset/180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcnamee/react-native-boilerplate-builder/28076ec2c3426a6b65744ff7a843544153c40049/OURS-NATIVE/ios/Images.xcassets/AppIcon.appiconset/180.png -------------------------------------------------------------------------------- /OURS-NATIVE/ios/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "120.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "180.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "idiom" : "ios-marketing", 47 | "size" : "1024x1024", 48 | "scale" : "1x" 49 | } 50 | ], 51 | "info" : { 52 | "version" : 1, 53 | "author" : "xcode" 54 | } 55 | } -------------------------------------------------------------------------------- /OURS-NATIVE/ios/Images.xcassets/LaunchScreen.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "original" 25 | } 26 | } -------------------------------------------------------------------------------- /OURS-NATIVE/ios/Images.xcassets/LaunchScreen.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcnamee/react-native-boilerplate-builder/28076ec2c3426a6b65744ff7a843544153c40049/OURS-NATIVE/ios/Images.xcassets/LaunchScreen.imageset/LaunchImage.png -------------------------------------------------------------------------------- /OURS-NATIVE/ios/Images.xcassets/LaunchScreen.imageset/LaunchImage2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcnamee/react-native-boilerplate-builder/28076ec2c3426a6b65744ff7a843544153c40049/OURS-NATIVE/ios/Images.xcassets/LaunchScreen.imageset/LaunchImage2x.png -------------------------------------------------------------------------------- /OURS-NATIVE/ios/Images.xcassets/LaunchScreen.imageset/LaunchImage3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcnamee/react-native-boilerplate-builder/28076ec2c3426a6b65744ff7a843544153c40049/OURS-NATIVE/ios/Images.xcassets/LaunchScreen.imageset/LaunchImage3x.png -------------------------------------------------------------------------------- /OURS-NATIVE/src/components/About.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Container, Content, Text, H1, H2, H3, 4 | } from 'native-base'; 5 | import Spacer from './UI/Spacer'; 6 | 7 | const About = () => ( 8 | 9 | 10 | 11 |

Heading 1

12 | 13 | 14 | Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus 15 | commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. 16 | Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui. 17 | {' '} 18 | 19 | 20 | 21 |

Heading 2

22 | 23 | 24 | Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus 25 | commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. 26 | Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui. 27 | {' '} 28 | 29 | 30 | 31 |

Heading 3

32 | 33 | 34 | Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus 35 | commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. 36 | Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui. 37 | {' '} 38 | 39 |
40 |
41 | ); 42 | 43 | export default About; 44 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/components/Articles/Form.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { useForm } from 'react-hook-form'; 4 | import { 5 | Container, 6 | Content, 7 | Text, 8 | Form, 9 | Item, 10 | Label, 11 | Input, 12 | Button, 13 | } from 'native-base'; 14 | import { Messages, Header, Spacer } from '../UI'; 15 | import { errorMessages } from '../../constants/messages'; 16 | 17 | const ArticlesForm = ({ 18 | error, loading, success, onFormSubmit, defaultValues, 19 | }) => { 20 | const { 21 | register, handleSubmit, errors, setValue, 22 | } = useForm({ defaultValues }); 23 | 24 | useEffect(() => { 25 | register({ name: 'email' }, { required: errorMessages.missingEmail }); 26 | }, [register]); 27 | 28 | return ( 29 | 30 | 31 |
35 | 36 | {error && } 37 | {loading && } 38 | {success && } 39 | 40 |
41 | 42 | 43 | setValue('email', value)} 50 | /> 51 | 52 | {errors.email && {errors.email.message}} 53 | 54 | 55 | 56 | 59 | 60 | 61 | 62 | ); 63 | }; 64 | 65 | ArticlesForm.propTypes = { 66 | error: PropTypes.string, 67 | loading: PropTypes.bool, 68 | success: PropTypes.string, 69 | defaultValues: PropTypes.shape({ 70 | email: PropTypes.string, 71 | }), 72 | onFormSubmit: PropTypes.func.isRequired, 73 | }; 74 | 75 | ArticlesForm.defaultProps = { 76 | error: null, 77 | success: null, 78 | loading: false, 79 | defaultValues: {}, 80 | }; 81 | 82 | export default ArticlesForm; 83 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/components/Articles/List.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Actions } from 'react-native-router-flux'; 4 | import { FlatList, TouchableOpacity, Image } from 'react-native'; 5 | import { 6 | Container, Card, CardItem, Body, Text, Button, 7 | } from 'native-base'; 8 | import { Error, Spacer } from '../UI'; 9 | import { errorMessages } from '../../constants/messages'; 10 | 11 | const ArticlesList = ({ 12 | error, loading, listFlat, reFetch, meta, 13 | }) => { 14 | if (error) { 15 | return ; 16 | } 17 | 18 | if (listFlat.length < 1) { 19 | return ; 20 | } 21 | 22 | return ( 23 | 24 | reFetch({ forceSync: true })} 27 | refreshing={loading} 28 | renderItem={({ item }) => ( 29 | 30 | ( 33 | !item.placeholder 34 | ? Actions.articlesSingle({ id: item.id, title: item.name }) 35 | : null 36 | )} 37 | style={{ flex: 1 }} 38 | > 39 | 40 | {!!item.image && ( 41 | 53 | )} 54 | 55 | 56 | 57 | 58 | {item.name} 59 | 60 | {!!item.excerpt && {item.excerpt}} 61 | 62 | 63 | 64 | 65 | 66 | )} 67 | keyExtractor={(item) => `${item.id}-${item.name}`} 68 | ListFooterComponent={(meta && meta.page && meta.lastPage && meta.page < meta.lastPage) 69 | ? () => ( 70 | 71 | 72 | 79 | 80 | ) : null} 81 | /> 82 | 83 | 84 | 85 | ); 86 | }; 87 | 88 | ArticlesList.propTypes = { 89 | error: PropTypes.string, 90 | loading: PropTypes.bool, 91 | listFlat: PropTypes.arrayOf( 92 | PropTypes.shape({ 93 | placeholder: PropTypes.bool, 94 | id: PropTypes.number, 95 | name: PropTypes.string, 96 | date: PropTypes.string, 97 | content: PropTypes.string, 98 | excerpt: PropTypes.string, 99 | image: PropTypes.string, 100 | }), 101 | ), 102 | reFetch: PropTypes.func, 103 | meta: PropTypes.shape({ page: PropTypes.number, lastPage: PropTypes.number }), 104 | }; 105 | 106 | ArticlesList.defaultProps = { 107 | listFlat: [], 108 | error: null, 109 | reFetch: null, 110 | meta: { page: null, lastPage: null }, 111 | loading: false, 112 | }; 113 | 114 | export default ArticlesList; 115 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/components/Articles/Single.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Image } from 'react-native'; 4 | import { 5 | Container, Content, Card, CardItem, Body, H3, Text, 6 | } from 'native-base'; 7 | import { Loading, Error, Spacer } from '../UI'; 8 | import { errorMessages } from '../../constants/messages'; 9 | 10 | const ArticlesSingle = ({ 11 | error, loading, article, reFetch, 12 | }) => { 13 | if (error) { 14 | return ; 15 | } 16 | 17 | if (loading) { 18 | return ; 19 | } 20 | 21 | if (Object.keys(article).length < 1) { 22 | return ; 23 | } 24 | 25 | return ( 26 | 27 | 28 | {!!article.image && ( 29 | 35 | )} 36 | 37 | 38 |

{article.name}

39 | 40 | 41 | {!!article.content && ( 42 | 43 | 44 | Content 45 | 46 | 47 | 48 | {article.content} 49 | 50 | 51 | 52 | )} 53 | 54 |
55 |
56 | ); 57 | }; 58 | 59 | ArticlesSingle.propTypes = { 60 | error: PropTypes.string, 61 | loading: PropTypes.bool, 62 | article: PropTypes.shape(), 63 | reFetch: PropTypes.func, 64 | }; 65 | 66 | ArticlesSingle.defaultProps = { 67 | error: null, 68 | loading: false, 69 | article: {}, 70 | reFetch: null, 71 | }; 72 | 73 | export default ArticlesSingle; 74 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/components/UI/Error.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { 4 | Container, Text, H3, Button, View, 5 | } from 'native-base'; 6 | import Spacer from './Spacer'; 7 | 8 | const Error = ({ title, content, tryAgain }) => ( 9 | 10 | 11 | 12 |

{title}

13 | {content} 14 | {tryAgain && ( 15 | 18 | )} 19 | 20 |
21 |
22 | ); 23 | 24 | Error.propTypes = { 25 | title: PropTypes.string, 26 | content: PropTypes.string, 27 | tryAgain: PropTypes.func, 28 | }; 29 | 30 | Error.defaultProps = { 31 | title: 'Uh oh', 32 | content: 'An unexpected error came up', 33 | tryAgain: null, 34 | }; 35 | 36 | export default Error; 37 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/components/UI/Header.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { View } from 'react-native'; 4 | import { Text, H1 } from 'native-base'; 5 | import Spacer from './Spacer'; 6 | 7 | const Header = ({ title, content }) => ( 8 | 9 | 10 |

{title}

11 | {!!content && ( 12 | 13 | 14 | {content} 15 | 16 | )} 17 | 18 |
19 | ); 20 | 21 | Header.propTypes = { 22 | title: PropTypes.string, 23 | content: PropTypes.string, 24 | }; 25 | 26 | Header.defaultProps = { 27 | title: 'Missing title', 28 | content: '', 29 | }; 30 | 31 | export default Header; 32 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/components/UI/Loading.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { View, ActivityIndicator } from 'react-native'; 3 | import Colors from '../../../native-base-theme/variables/commonColor'; 4 | 5 | const Loading = () => ( 6 | 7 | 8 | 9 | ); 10 | 11 | export default Loading; 12 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/components/UI/Messages.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { View } from 'react-native'; 4 | import { Text } from 'native-base'; 5 | 6 | import Colors from '../../../native-base-theme/variables/commonColor'; 7 | 8 | const Messages = ({ message, type }) => ( 9 | 17 | {message} 18 | 19 | ); 20 | 21 | Messages.propTypes = { 22 | message: PropTypes.string, 23 | type: PropTypes.oneOf(['error', 'success', 'info']), 24 | }; 25 | 26 | Messages.defaultProps = { 27 | message: 'An unexpected error came up', 28 | type: 'error', 29 | }; 30 | 31 | export default Messages; 32 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/components/UI/Spacer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { View } from 'native-base'; 4 | 5 | const Spacer = ({ size }) => ; 6 | 7 | Spacer.propTypes = { 8 | size: PropTypes.number, 9 | }; 10 | 11 | Spacer.defaultProps = { 12 | size: 20, 13 | }; 14 | 15 | export default Spacer; 16 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/components/UI/index.js: -------------------------------------------------------------------------------- 1 | export { default as Error } from './Error'; 2 | export { default as Header } from './Header'; 3 | export { default as Loading } from './Loading'; 4 | export { default as Messages } from './Messages'; 5 | export { default as Spacer } from './Spacer'; 6 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/constants/config.js: -------------------------------------------------------------------------------- 1 | const isDevEnv = process.env.NODE_ENV === 'development'; 2 | 3 | export default { 4 | // App Details 5 | appName: 'AwesomeProject', 6 | 7 | // Build Configuration - eg. Debug or Release? 8 | isDevEnv, 9 | 10 | // Date Format 11 | dateFormat: 'Do MMM YYYY', 12 | 13 | // API 14 | apiBaseUrl: isDevEnv 15 | ? 'https://digitalsupply.co/wp-json/wp' 16 | : 'https://digitalsupply.co/wp-json/wp', 17 | 18 | // Google Analytics - uses a 'dev' account while we're testing 19 | gaTrackingId: isDevEnv ? 'UA-84284256-2' : 'UA-84284256-1', 20 | }; 21 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/constants/navigation.js: -------------------------------------------------------------------------------- 1 | import Colors from '../../native-base-theme/variables/commonColor'; 2 | 3 | export default { 4 | navbarProps: { 5 | navigationBarStyle: { backgroundColor: 'white' }, 6 | titleStyle: { 7 | color: Colors.textColor, 8 | alignSelf: 'center', 9 | fontSize: Colors.fontSizeBase, 10 | }, 11 | backButtonTintColor: Colors.textColor, 12 | }, 13 | 14 | tabProps: { 15 | swipeEnabled: false, 16 | activeBackgroundColor: 'rgba(255,255,255,0.1)', 17 | inactiveBackgroundColor: Colors.brandPrimary, 18 | tabBarStyle: { backgroundColor: Colors.brandPrimary }, 19 | }, 20 | 21 | icons: { 22 | style: { color: 'white', height: 30, width: 30 }, 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Provider } from 'react-redux'; 4 | import { Router, Stack } from 'react-native-router-flux'; 5 | import { PersistGate } from 'redux-persist/es/integration/react'; 6 | import SplashScreen from 'react-native-splash-screen'; 7 | 8 | import { Root, StyleProvider } from 'native-base'; 9 | import getTheme from '../native-base-theme/components'; 10 | import theme from '../native-base-theme/variables/commonColor'; 11 | 12 | import Routes from './routes/index'; 13 | import Loading from './components/UI/Loading'; 14 | 15 | class App extends React.Component { 16 | constructor() { 17 | super(); 18 | this.state = { loading: true }; 19 | } 20 | 21 | async componentDidMount() { 22 | SplashScreen.hide(); 23 | this.setState({ loading: false }); 24 | } 25 | 26 | render() { 27 | const { loading } = this.state; 28 | const { store, persistor } = this.props; 29 | 30 | if (loading) { 31 | return ; 32 | } 33 | 34 | return ( 35 | 36 | 37 | } persistor={persistor}> 38 | 39 | 40 | {Routes} 41 | 42 | 43 | 44 | 45 | 46 | ); 47 | } 48 | } 49 | 50 | App.propTypes = { 51 | store: PropTypes.shape({}).isRequired, 52 | persistor: PropTypes.shape({}).isRequired, 53 | }; 54 | 55 | export default App; 56 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/lib/api.js: -------------------------------------------------------------------------------- 1 | import AsyncStorage from '@react-native-community/async-storage'; 2 | import axios from 'axios'; 3 | import Config from '../constants/config'; 4 | 5 | /** 6 | * Axios defaults 7 | */ 8 | axios.defaults.baseURL = Config.apiBaseUrl; 9 | 10 | // Headers 11 | axios.defaults.headers.common['Content-Type'] = 'application/json'; 12 | axios.defaults.headers.common.Accept = 'application/json'; 13 | 14 | /** 15 | * Request Interceptor 16 | */ 17 | axios.interceptors.request.use( 18 | async (inputConfig) => { 19 | const config = inputConfig; 20 | 21 | // Check for and add the stored Auth Token to the header request 22 | let token = ''; 23 | try { 24 | token = await AsyncStorage.getItem('@Auth:token'); 25 | } catch (error) { 26 | /* Nothing */ 27 | } 28 | if (token) { 29 | config.headers.common.Authorization = `Bearer ${token}`; 30 | } 31 | 32 | return config; 33 | }, 34 | (error) => { 35 | throw error; 36 | }, 37 | ); 38 | 39 | /** 40 | * Response Interceptor 41 | */ 42 | axios.interceptors.response.use( 43 | (res) => { 44 | // Status code isn't a success code - throw error 45 | if (!`${res.status}`.startsWith('2')) { 46 | throw res.data; 47 | } 48 | 49 | // Otherwise just return the data 50 | return res; 51 | }, 52 | (error) => { 53 | // Pass the response from the API, rather than a status code 54 | if (error && error.response && error.response.data) { 55 | throw error.response.data; 56 | } 57 | throw error; 58 | }, 59 | ); 60 | 61 | export default axios; 62 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/routes/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Scene, Tabs, Stack } from 'react-native-router-flux'; 3 | import { Icon } from 'native-base'; 4 | import DefaultProps from '../constants/navigation'; 5 | import AppConfig from '../constants/config'; 6 | 7 | import { ArticlesForm, ArticlesList, ArticlesSingle } from '../containers'; 8 | 9 | import AboutComponent from '../components/About'; 10 | 11 | const Index = ( 12 | 13 | 14 | 21 | } 25 | {...DefaultProps.navbarProps} 26 | > 27 | 28 | 29 | 30 | } 34 | {...DefaultProps.navbarProps} 35 | > 36 | 37 | 38 | 39 | 40 | } 44 | {...DefaultProps.navbarProps} 45 | > 46 | 47 | 48 | 49 | 50 | 51 | ); 52 | 53 | export default Index; 54 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/store/index.js: -------------------------------------------------------------------------------- 1 | /* global */ 2 | import { init } from '@rematch/core'; 3 | import createPersistPlugin, { getPersistor } from '@rematch/persist'; 4 | import createLoadingPlugin from '@rematch/loading'; 5 | import AsyncStorage from '@react-native-community/async-storage'; 6 | import * as models from '../models'; 7 | 8 | // Create plugins 9 | const persistPlugin = createPersistPlugin({ 10 | key: 'root', 11 | storage: AsyncStorage, 12 | blacklist: [], 13 | }); 14 | const loadingPlugin = createLoadingPlugin({}); 15 | 16 | const configureStore = () => { 17 | const store = init({ 18 | models, 19 | redux: { 20 | middlewares: [], 21 | }, 22 | plugins: [persistPlugin, loadingPlugin], 23 | }); 24 | 25 | const persistor = getPersistor(); 26 | const { dispatch } = store; 27 | 28 | return { persistor, store, dispatch }; 29 | }; 30 | 31 | export default configureStore; 32 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/tests/__mocks__/@react-native-community/async-storage.js: -------------------------------------------------------------------------------- 1 | export default from '@react-native-community/async-storage/jest/async-storage-mock'; 2 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/tests/components/Articles/List.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import renderer from 'react-test-renderer'; 3 | import { render } from '@testing-library/react-native'; 4 | import ArticlesList from '../../../components/Articles/List'; 5 | import { errorMessages } from '../../../constants/messages'; 6 | 7 | it(' shows a nice error message', () => { 8 | const Component = ; 9 | 10 | // Matches snapshot 11 | expect(renderer.create(Component).toJSON()).toMatchSnapshot(); 12 | 13 | // Has the correct text on the page 14 | const { getByText } = render(Component); 15 | expect(getByText(errorMessages.articlesEmpty)); 16 | }); 17 | 18 | it(' shows a list of articles correctly', () => { 19 | const listItem = { 20 | id: 0, 21 | name: 'ABC', 22 | excerpt: 'DEF', 23 | contentRaw: 'DEF', 24 | date: '22/33/44', 25 | }; 26 | 27 | const Component = ; 28 | 29 | // Matches snapshot 30 | expect(renderer.create(Component).toJSON()).toMatchSnapshot(); 31 | 32 | // Has the correct text on the page 33 | const { getByText } = render(Component); 34 | expect(getByText(listItem.name)); 35 | }); 36 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/tests/components/Articles/Single.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import renderer from 'react-test-renderer'; 3 | import { render } from '@testing-library/react-native'; 4 | import ArticlesSingle from '../../../components/Articles/Single'; 5 | import { errorMessages } from '../../../constants/messages'; 6 | 7 | it(' shows a nice error message', () => { 8 | const Component = ; 9 | 10 | // Matches snapshot 11 | expect(renderer.create(Component).toJSON()).toMatchSnapshot(); 12 | 13 | // Has the correct text on the page 14 | const { getByText } = render(Component); 15 | expect(getByText(errorMessages.articles404)); 16 | }); 17 | 18 | it(' shows an article correctly', () => { 19 | const article = { 20 | id: 0, 21 | name: 'ABC', 22 | excerpt: 'DEF', 23 | content: 'DEF', 24 | date: '22/33/44', 25 | }; 26 | 27 | const Component = ; 28 | 29 | // Matches snapshot 30 | expect(renderer.create(Component).toJSON()).toMatchSnapshot(); 31 | 32 | // Has the correct text on the page 33 | const { getByText } = render(Component); 34 | expect(getByText(article.name)); 35 | }); 36 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/tests/components/Articles/__snapshots__/Single.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[` shows a nice error message 1`] = ` 4 | 18 | 28 | 39 | 53 | Uh oh 54 | 55 | 71 | This article could not be found 72 | 73 | 84 | 85 | 86 | `; 87 | 88 | exports[` shows an article correctly 1`] = ` 89 | 98 | 107 | 158 | 159 | 170 | 179 | ABC 180 | 181 | 192 | 218 | 236 | 247 | Content 248 | 249 | 250 | 264 | 273 | 283 | DEF 284 | 285 | 286 | 287 | 288 | 299 | 300 | 301 | 302 | 303 | `; 304 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/tests/components/UI/Error.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import renderer from 'react-test-renderer'; 3 | import { render } from '@testing-library/react-native'; 4 | import Error from '../../../components/UI/Error'; 5 | 6 | it(' renders with message', () => { 7 | const Component = ; 8 | 9 | // Matches snapshot 10 | expect(renderer.create(Component).toJSON()).toMatchSnapshot(); 11 | 12 | // Has the correct text on the page 13 | const { getByText } = render(Component); 14 | expect(getByText('hello boy')); 15 | }); 16 | 17 | it(' renders with a button', () => { 18 | const Component = {}} />; 19 | 20 | // Matches snapshot 21 | expect(renderer.create(Component).toJSON()).toMatchSnapshot(); 22 | 23 | // Has the correct text on the page 24 | const { getByText } = render(Component); 25 | expect(getByText('hello boy')); 26 | expect(getByText('Try Again')); 27 | }); 28 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/tests/components/UI/Header.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import renderer from 'react-test-renderer'; 3 | import { render } from '@testing-library/react-native'; 4 | import Header from '../../../components/UI/Header'; 5 | 6 | it('
renders with message', () => { 7 | const Component =
; 8 | 9 | // Matches snapshot 10 | expect(renderer.create(Component).toJSON()).toMatchSnapshot(); 11 | 12 | // Has the correct text on the page 13 | const { getByText } = render(Component); 14 | expect(getByText('hello boy')); 15 | expect(getByText("I'm here")); 16 | }); 17 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/tests/components/UI/Loading.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import renderer from 'react-test-renderer'; 3 | import Loading from '../../../components/UI/Loading'; 4 | 5 | it(' renders correctly', () => { 6 | const Component = ; 7 | 8 | // Matches snapshot 9 | expect(renderer.create(Component).toJSON()).toMatchSnapshot(); 10 | }); 11 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/tests/components/UI/Messages.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import renderer from 'react-test-renderer'; 3 | import { render } from '@testing-library/react-native'; 4 | import Messages from '../../../components/UI/Messages'; 5 | 6 | it(' renders with error and message', () => { 7 | const Component = ; 8 | 9 | // Matches snapshot 10 | expect(renderer.create(Component).toJSON()).toMatchSnapshot(); 11 | 12 | // Has the correct text on the page 13 | const { getByText } = render(Component); 14 | expect(getByText('Success')); 15 | }); 16 | 17 | it(' renders with error and message', () => { 18 | const Component = ; 19 | 20 | // Matches snapshot 21 | expect(renderer.create(Component).toJSON()).toMatchSnapshot(); 22 | 23 | // Has the correct text on the page 24 | const { getByText } = render(Component); 25 | expect(getByText('Error')); 26 | }); 27 | 28 | it(' renders with info and message', () => { 29 | const Component = ; 30 | 31 | // Matches snapshot 32 | expect(renderer.create(Component).toJSON()).toMatchSnapshot(); 33 | 34 | // Has the correct text on the page 35 | const { getByText } = render(Component); 36 | expect(getByText('Warning')); 37 | }); 38 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/tests/components/UI/Spacer.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import renderer from 'react-test-renderer'; 3 | import Spacer from '../../../components/UI/Spacer'; 4 | 5 | it(' renders with correctly with size: 10', () => { 6 | const Component = ; 7 | 8 | // Matches snapshot 9 | expect(renderer.create(Component).toJSON()).toMatchSnapshot(); 10 | }); 11 | 12 | it(' renders with correctly with size: 15', () => { 13 | const Component = ; 14 | 15 | // Matches snapshot 16 | expect(renderer.create(Component).toJSON()).toMatchSnapshot(); 17 | }); 18 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/tests/components/UI/__snapshots__/Error.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[` renders with a button 1`] = ` 4 | 18 | 28 | 39 | 53 | hello boy 54 | 55 | 71 | An unexpected error came up 72 | 73 | 110 | 125 | Try Again 126 | 127 | 128 | 139 | 140 | 141 | `; 142 | 143 | exports[` renders with message 1`] = ` 144 | 158 | 168 | 179 | 193 | hello boy 194 | 195 | 211 | An unexpected error came up 212 | 213 | 224 | 225 | 226 | `; 227 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/tests/components/UI/__snapshots__/Header.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`
renders with message 1`] = ` 4 | 5 | 16 | 25 | hello boy 26 | 27 | 28 | 39 | 49 | I'm here 50 | 51 | 52 | 63 | 64 | `; 65 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/tests/components/UI/__snapshots__/Loading.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[` renders correctly 1`] = ` 4 | 13 | 19 | 20 | `; 21 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/tests/components/UI/__snapshots__/Messages.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[` renders with error and message 1`] = ` 4 | 13 | 29 | Success 30 | 31 | 32 | `; 33 | 34 | exports[` renders with error and message 2`] = ` 35 | 44 | 60 | Error 61 | 62 | 63 | `; 64 | 65 | exports[` renders with info and message 1`] = ` 66 | 75 | 91 | Warning 92 | 93 | 94 | `; 95 | -------------------------------------------------------------------------------- /OURS-NATIVE/src/tests/components/UI/__snapshots__/Spacer.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[` renders with correctly with size: 10 1`] = ` 4 | 15 | `; 16 | 17 | exports[` renders with correctly with size: 15 1`] = ` 18 | 29 | `; 30 | -------------------------------------------------------------------------------- /OURS-WEB/.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Github Pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-18.04 11 | steps: 12 | - uses: actions/checkout@v2 13 | 14 | - name: Setup Node 15 | uses: actions/setup-node@v1 16 | with: 17 | node-version: '12.x' 18 | 19 | - name: Get yarn cache 20 | id: yarn-cache 21 | run: echo "::set-output name=dir::$(yarn cache dir)" 22 | 23 | - name: Cache dependencies 24 | uses: actions/cache@v1 25 | with: 26 | path: ${{ steps.yarn-cache.outputs.dir }} 27 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 28 | restore-keys: | 29 | ${{ runner.os }}-yarn- 30 | 31 | - run: yarn install 32 | - run: yarn build 33 | 34 | - name: Deploy 35 | uses: peaceiris/actions-gh-pages@v3 36 | with: 37 | github_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} 38 | publish_dir: ./build 39 | -------------------------------------------------------------------------------- /OURS-WEB/README.md: -------------------------------------------------------------------------------- 1 |
2 | React Web Starter Kit 3 |

4 |

React Web App

5 |

6 | Web Demo 7 |

8 | 9 | 10 | builds 11 | 12 | 13 | license 14 | 15 | 16 |
17 |

18 | What is this? 19 |   —   20 | Usage 21 |   —   22 | Docs 23 |   —   24 | Need help? 25 |

26 |
27 |
28 | 29 | --- 30 | 31 | ### Looking for something else? 32 | 33 | - [React Native Starter Kit / Boilerplate](https://github.com/mcnamee/react-native-starter-kit) 34 | - [React Native Starter Kit (Expo) / Boilerplate](https://github.com/mcnamee/react-native-expo-starter-kit) 35 | - [Previous Version (React Starter Kit (Web + Native) w/ Firebase)](https://github.com/mcnamee/react-native-starter-kit/tree/archive/v3) 36 | 37 | --- 38 | 39 | ## 👋 Intro 40 | 41 | This project was bootstrapped with the [React Boilerplate Builder](https://github.com/mcnamee/react-native-boilerplate-builder) by [Matt McNamee](https://mcnam.ee). 42 | 43 | The project is _super_ helpful to kick-start your next project, as it provides a lot of the common tools you may reach for, all ready to go. Specifically: 44 | 45 | - __Flux architecture__ 46 | - [Redux](https://redux.js.org/docs/introduction/) 47 | - Redux Wrapper: [Rematch](https://github.com/rematch/rematch) 48 | - __Routing and navigation__ 49 | - [React Router](https://github.com/ReactTraining/react-router) for web 50 | - __Data Caching / Offline__ 51 | - [Redux Persist](https://github.com/rt2zz/redux-persist) 52 | - __UI Toolkit__ 53 | - [Bootstrap](https://getbootstrap.com/) for web 54 | - __Code Linting__ with 55 | - [Airbnb's JS Linting](https://github.com/airbnb/javascript) guidelines 56 | 57 | --- 58 | 59 | ## 🚀 Getting Started 60 | 61 | - Install `eslint`, `prettier` and `editor config` plugins into your IDE 62 | 63 | ```bash 64 | # Install dependencies 65 | yarn install 66 | 67 | # Run the app in the development mode 68 | # Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 69 | yarn start 70 | 71 | # Launches the test runner in the interactive watch mode 72 | yarn test 73 | 74 | # Builds the app for production to the `build` folder 75 | # It correctly bundles React in production mode and optimizes the build for the best performance 76 | yarn build 77 | 78 | # Lint 79 | ./node_modules/.bin/eslint "src/**/*.js" 80 | ``` 81 | 82 | --- 83 | 84 | ## 📖 Docs 85 | 86 | - [Contributing to this project](documentation/contributing.md) 87 | - [Tests & testing](documentation/testing.md) 88 | - [Understanding the file structure](documentation/file-structure.md) 89 | - [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started) 90 | - [React documentation](https://reactjs.org/) 91 | - [Code Splitting](https://facebook.github.io/create-react-app/docs/code-splitting) 92 | - [Analyzing the Bundle Size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) 93 | - [Making a Progressive Web App](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) 94 | - [Advanced Configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) 95 | - [Deployment](https://facebook.github.io/create-react-app/docs/deployment) 96 | - [`yarn run build` fails to minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) 97 | 98 | --- 99 | 100 | ## 👊 Further Help? 101 | 102 | This repo is a great place to start. But...if you'd prefer to sit back and have your new project built for you or just need some consultation, [get in touch with me directly](https://mcnam.ee) and I can organise a quote. 103 | -------------------------------------------------------------------------------- /OURS-WEB/documentation/rsk-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcnamee/react-native-boilerplate-builder/28076ec2c3426a6b65744ff7a843544153c40049/OURS-WEB/documentation/rsk-logo.jpg -------------------------------------------------------------------------------- /OURS-WEB/documentation/web-demo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcnamee/react-native-boilerplate-builder/28076ec2c3426a6b65744ff7a843544153c40049/OURS-WEB/documentation/web-demo.jpg -------------------------------------------------------------------------------- /OURS-WEB/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Single Page Apps for GitHub Pages 6 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /OURS-WEB/public/CNAME: -------------------------------------------------------------------------------- 1 | react-starter-kit.mcnam.ee 2 | -------------------------------------------------------------------------------- /OURS-WEB/src/assets/images/app-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcnamee/react-native-boilerplate-builder/28076ec2c3426a6b65744ff7a843544153c40049/OURS-WEB/src/assets/images/app-icon.png -------------------------------------------------------------------------------- /OURS-WEB/src/assets/styles/_bootstrap.scss: -------------------------------------------------------------------------------- 1 | // Override Bootstrap's variables before importing 2 | // node_modules/bootstrap/scss/_variables.scss 3 | 4 | // Breakpoints 5 | $grid-breakpoints: ( 6 | xs: 0, 7 | sm: 576px, 8 | md: 768px, 9 | lg: 992px, 10 | xl: 1200px, 11 | xxl: 1400px 12 | ); 13 | 14 | // Jumbotron 15 | $jumbotron-bg: white; 16 | 17 | // Misc 18 | $border-radius: 3px; 19 | 20 | // Buttons 21 | $btn-border-radius: 3px; 22 | $btn-padding-x: 25px; 23 | $btn-padding-x-lg: 50px; 24 | $btn-font-size-lg: 1.15rem; 25 | 26 | // Type 27 | $headings-margin-bottom: 0.5em; 28 | $h1-font-size: 32px; 29 | $h2-font-size: 24px; 30 | $h3-font-size: 20px; 31 | $h4-font-size: 16px; 32 | 33 | $display1-size: 50px; 34 | $display2-size: 34px; 35 | $display3-size: 24px; 36 | $display4-size: 16px; 37 | 38 | // Then import Bootstrap 39 | @import "node_modules/bootstrap/scss/bootstrap"; 40 | -------------------------------------------------------------------------------- /OURS-WEB/src/assets/styles/components/_footer.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Styles for the Footer.js component 3 | */ 4 | -------------------------------------------------------------------------------- /OURS-WEB/src/assets/styles/components/_forms.scss: -------------------------------------------------------------------------------- 1 | label.required { 2 | &:after { 3 | position: relative; 4 | top: -2px; 5 | right: -2px; 6 | content: "*"; 7 | display: inline; 8 | color: red; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /OURS-WEB/src/assets/styles/components/_header.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Styles for the Header.js component 3 | */ 4 | -------------------------------------------------------------------------------- /OURS-WEB/src/assets/styles/components/_mobile-tab-bar.scss: -------------------------------------------------------------------------------- 1 | .mobile-tab-bar { 2 | position: fixed; 3 | bottom: 0; 4 | left: 0; 5 | right: 0; 6 | background: $light; 7 | z-index: 99; 8 | box-shadow: $box-shadow; 9 | text-align: center; 10 | border-top: 1px solid $border-color; 11 | 12 | .nav-pills { 13 | .nav-link { 14 | color: $gray-500; 15 | border-radius: 0; 16 | padding-left: 0.4rem; 17 | padding-right: 0.4rem; 18 | padding-bottom: 25px; 19 | border-top: 3px solid transparent; 20 | 21 | svg { 22 | color: $gray-800; 23 | display: block; 24 | margin: 0 auto 5px; 25 | font-size: 1.4rem; 26 | } 27 | 28 | span { 29 | display: block; 30 | font-size: 0.6rem; 31 | } 32 | 33 | &.active { 34 | background: transparent; 35 | color: #2469F6; 36 | border-top: 3px solid #2469F6; 37 | 38 | svg { 39 | color: #2469F6; 40 | } 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /OURS-WEB/src/assets/styles/components/_tables.scss: -------------------------------------------------------------------------------- 1 | table { 2 | tbody { 3 | tr:first-of-type { 4 | td { 5 | border-top: none; 6 | } 7 | } 8 | } 9 | } 10 | 11 | /* Adds a right hand shadow on the table */ 12 | .table-responsive { 13 | @include media-breakpoint-down(sm) { 14 | position: relative; 15 | display: flex; 16 | 17 | &:after { 18 | content: ''; 19 | display: block; 20 | position: sticky; 21 | width: 20px; 22 | background: linear-gradient(to right, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.25) 100%); 23 | margin-left: -20px; 24 | z-index: 2; 25 | pointer-events: none; 26 | flex-shrink: 0; 27 | right: 0; 28 | } 29 | } 30 | } 31 | 32 | table { 33 | thead { 34 | th { 35 | font-size: 0.8rem; 36 | text-transform: uppercase; 37 | letter-spacing: 1px; 38 | color: $gray-600; 39 | } 40 | } 41 | } 42 | 43 | /* Hides all columns except the first */ 44 | table.mobile-list-table { 45 | @include media-breakpoint-down(sm) { 46 | th, td { 47 | display: none; 48 | } 49 | 50 | td.mobile-list-table-keep { 51 | display: table-cell; 52 | position: relative; 53 | cursor: pointer; 54 | 55 | &:before { 56 | content:"\203A"; 57 | color: $gray-400; 58 | font-size: 2rem; 59 | position: absolute; 60 | right: 10px; 61 | top: 50%; 62 | transform: translateY(-56%); 63 | } 64 | } 65 | } 66 | } 67 | 68 | -------------------------------------------------------------------------------- /OURS-WEB/src/assets/styles/style.scss: -------------------------------------------------------------------------------- 1 | @import "bootstrap"; 2 | 3 | /** 4 | * Import Components 5 | */ 6 | @import "components/header"; 7 | @import "components/forms"; 8 | @import "components/footer"; 9 | @import "components/mobile-tab-bar"; 10 | @import "components/tables"; 11 | 12 | /** 13 | * Backgrounds 14 | */ 15 | .bg-gray-100 { background-color: $gray-100; } 16 | .bg-gray-200 { background-color: $gray-200; } 17 | .bg-gray-300 { background-color: $gray-300; } 18 | .bg-gray-400 { background-color: $gray-400; } 19 | .bg-gray-500 { background-color: $gray-500; } 20 | .bg-gray-600 { background-color: $gray-600; } 21 | .bg-gray-700 { background-color: $gray-700; } 22 | .bg-gray-800 { background-color: $gray-800; } 23 | .bg-gray-900 { background-color: $gray-900; } 24 | 25 | /** 26 | * Generic Styles 27 | */ 28 | body, html { 29 | height: 100%; 30 | width: 100%; 31 | display: block; 32 | 33 | * { 34 | outline: none !important; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /OURS-WEB/src/components/About.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Row, Col, Jumbotron, Container, 4 | } from 'reactstrap'; 5 | import { Link, withRouter } from 'react-router-dom'; 6 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 7 | import { 8 | faTachometerAlt, faPalette, faMoneyBillWave, faCertificate, faPlus, faUserCircle, 9 | } from '@fortawesome/free-solid-svg-icons'; 10 | import Template from './Templates/Dashboard'; 11 | 12 | const About = () => ( 13 | 115 | ); 116 | 117 | export default withRouter(About); 118 | -------------------------------------------------------------------------------- /OURS-WEB/src/components/Articles/Form.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { useForm } from 'react-hook-form'; 4 | import { withRouter } from 'react-router-dom'; 5 | import { 6 | Container, 7 | Row, 8 | Col, 9 | Card, 10 | CardBody, 11 | Alert, 12 | Form, 13 | FormGroup, 14 | Label, 15 | Input, 16 | Button, 17 | } from 'reactstrap'; 18 | import Template from '../Templates/Dashboard'; 19 | import { errorMessages } from '../../constants/messages'; 20 | 21 | const ArticlesForm = ({ 22 | error, loading, success, onFormSubmit, defaultValues, 23 | }) => { 24 | const { 25 | register, handleSubmit, errors, setValue, 26 | } = useForm({ defaultValues }); 27 | 28 | return ( 29 | 66 | ); 67 | }; 68 | 69 | ArticlesForm.propTypes = { 70 | error: PropTypes.string, 71 | loading: PropTypes.bool, 72 | success: PropTypes.string, 73 | defaultValues: PropTypes.shape({ 74 | email: PropTypes.string, 75 | }), 76 | onFormSubmit: PropTypes.func.isRequired, 77 | }; 78 | 79 | ArticlesForm.defaultProps = { 80 | error: null, 81 | success: null, 82 | loading: false, 83 | defaultValues: {}, 84 | }; 85 | 86 | export default withRouter(ArticlesForm); 87 | -------------------------------------------------------------------------------- /OURS-WEB/src/components/Articles/List.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { withRouter, Link } from 'react-router-dom'; 4 | import { 5 | Container, 6 | Row, 7 | Col, 8 | Table, 9 | Card, 10 | CardBody, 11 | Alert, 12 | } from 'reactstrap'; 13 | import Template from '../Templates/Dashboard'; 14 | import TablePagination from '../UI/TablePagination'; 15 | 16 | const List = ({ 17 | error, loading, listPaginated, page, pagination, meta, history, 18 | }) => ( 19 | 93 | ); 94 | 95 | List.propTypes = { 96 | error: PropTypes.string, 97 | loading: PropTypes.bool, 98 | listPaginated: PropTypes.shape({}), 99 | pagination: PropTypes.arrayOf(PropTypes.shape({ 100 | title: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, 101 | link: PropTypes.string.isRequired, 102 | })), 103 | page: PropTypes.number.isRequired, 104 | meta: PropTypes.shape({ total: PropTypes.number }), 105 | history: PropTypes.shape({ 106 | push: PropTypes.func.isRequired, 107 | }).isRequired, 108 | }; 109 | 110 | List.defaultProps = { 111 | error: null, 112 | listPaginated: {}, 113 | loading: false, 114 | pagination: [], 115 | meta: { total: 0 }, 116 | }; 117 | 118 | export default withRouter(List); 119 | -------------------------------------------------------------------------------- /OURS-WEB/src/components/Articles/Single.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { withRouter, Link, Redirect } from 'react-router-dom'; 4 | import { 5 | Container, 6 | Row, 7 | Col, 8 | Card, 9 | CardBody, 10 | Alert, 11 | CardImg, 12 | } from 'reactstrap'; 13 | import Template from '../Templates/Dashboard'; 14 | 15 | const Single = ({ 16 | error, loading, article, 17 | }) => { 18 | if (!loading && !article) return ; 19 | 20 | return ( 21 | 57 | ); 58 | }; 59 | 60 | Single.propTypes = { 61 | error: PropTypes.string, 62 | loading: PropTypes.bool, 63 | article: PropTypes.shape({ 64 | placeholder: PropTypes.bool, 65 | id: PropTypes.number, 66 | name: PropTypes.string, 67 | date: PropTypes.string, 68 | content: PropTypes.string, 69 | contentRaw: PropTypes.string, 70 | excerpt: PropTypes.string, 71 | image: PropTypes.string, 72 | }), 73 | }; 74 | 75 | Single.defaultProps = { 76 | error: null, 77 | loading: false, 78 | article: {}, 79 | }; 80 | 81 | export default withRouter(Single); 82 | -------------------------------------------------------------------------------- /OURS-WEB/src/components/Templates/Dashboard.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Helmet } from 'react-helmet'; 4 | import Header from '../UI/Header'; 5 | import MobileTabBar from '../UI/MobileTabBar'; 6 | import Footer from '../UI/Footer'; 7 | import PageTitle from '../UI/PageTitle'; 8 | 9 | const Template = ({ pageTitle, children, noPadding }) => ( 10 | 11 | 12 | {pageTitle} 13 | 14 | 15 |
16 | 17 |
18 | {children} 19 |
20 | 21 |