├── .github
└── FUNDING.yml
├── .gitignore
├── LICENSE
├── README.md
├── media
├── authflow.png
├── bottomtabs.gif
├── hero.png
├── midtrans.gif
├── thumbnail.gif
└── withnav.gif
├── template-typescript-bottom-tabs-supabase-auth-flow
├── .gitignore
├── App.tsx
├── README.md
├── app.json
├── assets
│ ├── adaptive-icon.png
│ ├── favicon.png
│ ├── fonts
│ │ └── SpaceMono-Regular.ttf
│ ├── icon.png
│ ├── images
│ │ ├── adaptive-icon.png
│ │ ├── favicon.png
│ │ ├── forget.png
│ │ ├── icon.png
│ │ ├── login.png
│ │ ├── register.png
│ │ └── splash.png
│ └── splash.png
├── babel.config.js
├── package-lock.json
├── package.json
├── src
│ ├── components
│ │ └── utils
│ │ │ ├── TabBarIcon.tsx
│ │ │ └── TabBarText.tsx
│ ├── initSupabase.ts
│ ├── navigation
│ │ ├── AuthStack.tsx
│ │ ├── MainStack.tsx
│ │ ├── MainTabs.tsx
│ │ └── index.tsx
│ ├── provider
│ │ └── AuthProvider.tsx
│ ├── screens
│ │ ├── About.tsx
│ │ ├── Home.tsx
│ │ ├── Profile.tsx
│ │ ├── SecondScreen.tsx
│ │ ├── auth
│ │ │ ├── ForgetPassword.tsx
│ │ │ ├── Login.tsx
│ │ │ └── Register.tsx
│ │ └── utils
│ │ │ └── Loading.tsx
│ └── types
│ │ └── navigation.tsx
└── tsconfig.json
├── template-typescript-bottom-tabs-with-auth-flow
├── .expo-shared
│ └── assets.json
├── .gitignore
├── App.tsx
├── README.md
├── app.json
├── assets
│ └── images
│ │ ├── adaptive-icon.png
│ │ ├── favicon.png
│ │ ├── forget.png
│ │ ├── icon.png
│ │ ├── login.png
│ │ ├── register.png
│ │ └── splash.png
├── babel.config.js
├── package-lock.json
├── package.json
├── src
│ ├── components
│ │ └── utils
│ │ │ ├── TabBarIcon.tsx
│ │ │ └── TabBarText.tsx
│ ├── navigation
│ │ ├── AuthStack.tsx
│ │ ├── MainStack.tsx
│ │ ├── MainTabs.tsx
│ │ └── index.tsx
│ ├── provider
│ │ └── AuthProvider.tsx
│ ├── screens
│ │ ├── About.tsx
│ │ ├── Home.tsx
│ │ ├── Profile.tsx
│ │ ├── SecondScreen.tsx
│ │ ├── auth
│ │ │ ├── ForgetPassword.tsx
│ │ │ ├── Login.tsx
│ │ │ └── Register.tsx
│ │ └── utils
│ │ │ └── Loading.tsx
│ └── types
│ │ └── navigation.tsx
└── tsconfig.json
├── template-with-bottom-tabs-auth-flow
├── .expo-shared
│ └── assets.json
├── .gitignore
├── App.js
├── README.md
├── app.json
├── assets
│ ├── favicon.png
│ ├── forget.png
│ ├── icon.png
│ ├── login.png
│ ├── register.png
│ └── splash.png
├── babel.config.js
├── package-lock.json
├── package.json
└── src
│ ├── components
│ └── utils
│ │ ├── TabBarIcon.js
│ │ └── TabBarText.js
│ ├── navigation
│ └── AppNavigator.js
│ ├── provider
│ └── AuthProvider.js
│ └── screens
│ ├── About.js
│ ├── Home.js
│ ├── Profile.js
│ ├── SecondScreen.js
│ ├── auth
│ ├── ForgetPassword.js
│ ├── Login.js
│ └── Register.js
│ └── utils
│ └── Loading.js
├── template-with-bottom-tabs
├── .expo-shared
│ └── assets.json
├── .gitignore
├── App.js
├── README.md
├── app.json
├── assets
│ ├── favicon.png
│ ├── icon.png
│ └── splash.png
├── babel.config.js
├── package-lock.json
├── package.json
└── src
│ ├── components
│ └── utils
│ │ ├── TabBarIcon.js
│ │ └── TabBarText.js
│ ├── navigation
│ └── AppNavigator.js
│ └── screens
│ ├── About.js
│ ├── Home.js
│ ├── Profile.js
│ └── SecondScreen.js
├── template-with-firebase-auth-flow
├── .expo-shared
│ └── assets.json
├── .gitignore
├── App.js
├── README.md
├── app.json
├── assets
│ ├── favicon.png
│ ├── forget.png
│ ├── icon.png
│ ├── login.png
│ ├── register.png
│ └── splash.png
├── babel.config.js
├── package-lock.json
├── package.json
└── src
│ ├── navigation
│ └── AppNavigator.js
│ ├── provider
│ └── AuthProvider.js
│ └── screens
│ ├── Home.js
│ ├── SecondScreen.js
│ ├── auth
│ ├── ForgetPassword.js
│ ├── Login.js
│ └── Register.js
│ └── utils
│ └── Loading.js
└── template-with-navigation
├── .expo-shared
└── assets.json
├── .gitignore
├── App.js
├── README.md
├── app.json
├── assets
├── favicon.png
├── icon.png
└── splash.png
├── babel.config.js
├── package-lock.json
├── package.json
└── src
├── navigation
└── AppNavigator.js
└── screens
├── Home.js
└── SecondScreen.js
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [codingki]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: kikiding
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom:
13 | [
14 | "https://karyakarsa.com/kikiding",
15 | ]
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | npm-debug.*
2 | *.jks
3 | *.p8
4 | *.p12
5 | *.key
6 | *.mobileprovision
7 | *.orig.*
8 |
9 | # macOS
10 | .DS_Store
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Nur Fikri
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React Native + Expo Starter Templates
2 |
3 | These are my starter templates or my way for building mobile app with react native and expo. I'm tired everytime I create a new project from blank, so I decided to make a starter templates, feel free to use it 🥳
4 |
5 | ## Preview
6 |
7 | 
8 |
9 | If you are looking for react native midtrans example, I moved it [here](https://github.com/codingki/react-native-midtrans-example)
10 |
11 | **Firebase auth flow**
12 | 
13 |
14 | ## Rapi UI
15 |
16 | 
17 |
18 | These UI components are provided by [Rapi UI](https://rapi-ui.kikiding.space/).
19 | Check the [documentation](https://rapi-ui.kikiding.space/docs/) for usage and more components.
20 |
21 | ## Documentation
22 |
23 | ### Typescript
24 |
25 | - [Template bottom tabs with auth flow (Typescript)](https://github.com/codingki/react-native-expo-template/tree/master/template-typescript-bottom-tabs-with-auth-flow)
26 | - [Template bottom tabs with Supabase.io auth flow (Typescript)](https://github.com/codingki/react-native-expo-template/tree/master/template-typescript-bottom-tabs-supabase-auth-flow)
27 |
28 | ### Javascript
29 |
30 | - [Template Blank with navigation](https://github.com/codingki/react-native-expo-template/tree/master/template-with-navigation)
31 | - [Template Bottom tabs](https://github.com/codingki/react-native-expo-template/tree/master/template-with-bottom-tabs)
32 | - [Template Firebase auth flow](https://github.com/codingki/react-native-expo-template/tree/master/template-with-firebase-auth-flow)
33 | - [Template Bottom tabs with auth flow](https://github.com/codingki/react-native-expo-template/tree/master/template-with-bottom-tabs-auth-flow)
34 |
35 | ## Changelog
36 |
37 | **03/01/2022**
38 |
39 | - Upgrade Expo SDK to v44.0 (latest)
40 | - Upgrade Firebase from v8.x -> v9.x (latest)
41 | - Updgrade React navigation from v5.x -> v6.x (latest)
42 |
43 | **15/07/2021**
44 |
45 | - Fix firebase import error
46 | - Upgrade Expo SDK to v42.0
47 |
48 | **13/06/2021**
49 |
50 | - Template now has darkmode
51 | - Rapi UI updated to 0.2.1
52 |
53 | **25/04/2021**
54 |
55 | - Expo updated to SDK 41
56 |
57 | **24/03/2021**
58 |
59 | - Now all the UI components uses [Rapi UI](https://rapi-ui.kikiding.space/)
60 | - Remove some unused packages
61 | - Fixed some bugs and file managements moved to `src/` directory
62 |
63 | if you find these useful don't forget to give it a star ⭐ and share it to your friends ❤️
64 |
65 | Reach me on [twitter](https://twitter.com/kikiding/)
66 |
--------------------------------------------------------------------------------
/media/authflow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/media/authflow.png
--------------------------------------------------------------------------------
/media/bottomtabs.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/media/bottomtabs.gif
--------------------------------------------------------------------------------
/media/hero.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/media/hero.png
--------------------------------------------------------------------------------
/media/midtrans.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/media/midtrans.gif
--------------------------------------------------------------------------------
/media/thumbnail.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/media/thumbnail.gif
--------------------------------------------------------------------------------
/media/withnav.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/media/withnav.gif
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/**/*
2 | .expo/*
3 | npm-debug.*
4 | *.jks
5 | *.p8
6 | *.p12
7 | *.key
8 | *.mobileprovision
9 | *.orig.*
10 | web-build/
11 |
12 | # macOS
13 | .DS_Store
14 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/App.tsx:
--------------------------------------------------------------------------------
1 | import { StatusBar } from "expo-status-bar";
2 | import React from "react";
3 | import { ThemeProvider } from "react-native-rapi-ui";
4 | import Navigation from "./src/navigation";
5 | import { AuthProvider } from "./src/provider/AuthProvider";
6 |
7 | export default function App() {
8 | const images = [
9 | require("./assets/images/login.png"),
10 | require("./assets/images/register.png"),
11 | require("./assets/images/forget.png"),
12 | ];
13 | return (
14 |
15 |
16 |
17 |
18 |
19 |
20 | );
21 | }
22 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/README.md:
--------------------------------------------------------------------------------
1 | # Template bottom tabs with auth flow (Typescript)
2 |
3 | Typescript Template starter with React Navigation Bottom Tabs and Supabase auth using React Context
4 |
5 | # Preview
6 |
7 | 
8 |
9 | # Installation
10 |
11 | 1. Install [node.js](https://nodejs.org/en/)
12 | 2. Install Expo
13 |
14 | ```jsx
15 | npm install --global expo-cli
16 | ```
17 |
18 | 3. Download this repo
19 | 4. Install deps on your template folder
20 |
21 | ```jsx
22 | npm install
23 | ```
24 |
25 | 5. Start the environtment
26 |
27 | ```jsx
28 | expo start
29 | ```
30 |
31 | # Auth Flow
32 |
33 | ### Supabase Setup
34 |
35 | - Set up a new Supabase.io project
36 | - Fill your supabase credentials to your config inside `./src/initSupabase.ts`
37 | - You can find your supabase credentials in your project -> settings -> API
38 |
39 | ```jsx
40 | // Better put your these secret keys in .env file
41 | export const supabase = createClient(
42 | "supabaseUrl", "supabaseKey",
43 | {
44 | localStorage: AsyncStorage as any,
45 | }
46 | );
47 | ```
48 |
49 | and you good to go!
50 |
51 | ### Prebuilt UI Screens
52 |
53 | There are 3 screens included inside `./src/screens/auth` and one more thing its included with the supabase auth function, so you don't need to create the function. The ilustrations I use [undraw](https://undraw.co/)
54 |
55 | - Login screen `./src/screens/auth/login.tsx`
56 | - Register screen `./src/screens/auth/register.tsx`
57 | - Forget password screen `./src/screens/auth/forget.tsx`
58 |
59 | ### React Navigation Auth Flow
60 |
61 | The checking logged users process is inside `./src/provider/AuthProvider` I use React Context, you can add more functions like get the data of the user and store it to the context (better static data, ex: uid)
62 |
63 | Inside the navigator `./src/navigation/AppNavigator.js`
64 | There's 2 stack navigator :
65 |
66 | - `` → for not logged in users stack
67 | - `` → for logged in users stack
68 | - `` → when checking if the user is logged in or not loading screen
69 |
70 | ```jsx
71 | export default () => {
72 | const auth = useContext(AuthContext);
73 | const user = auth.user;
74 | return (
75 |
76 | {user == null && }
77 | {user == false && }
78 | {user == true && }
79 |
80 | );
81 | };
82 | ```
83 |
84 | # Rapi UI
85 |
86 | 
87 |
88 | These UI components are provided by [Rapi UI](https://rapi-ui.kikiding.space/).
89 | Check the [documentation](https://rapi-ui.kikiding.space/docs/) for usage and more components.
90 |
91 | # File Managements
92 |
93 | These are the folders and the functionality all in `src/`
94 |
95 | ```jsx
96 | /src/assets -> for media such as images, etc
97 | /src/components -> for components
98 | /src/navigation -> for React Navigation
99 | /src/provider -> for React Context
100 | /src/screens -> for Screens
101 | /src/types -> for Types
102 | ```
103 |
104 | if you find these useful don't forget to give it a star ⭐ and share it to your friends ❤️
105 |
106 | Reach me on [twitter](https://twitter.com/kikiding/)
107 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "template-typescript-bottom-tabs-supabase-auth-flow",
4 | "slug": "template-typescript-bottom-tabs-supabase-auth-flow",
5 | "version": "1.0.0",
6 | "orientation": "portrait",
7 | "icon": "./assets/icon.png",
8 | "splash": {
9 | "image": "./assets/splash.png",
10 | "resizeMode": "contain",
11 | "backgroundColor": "#ffffff"
12 | },
13 | "updates": {
14 | "fallbackToCacheTimeout": 0
15 | },
16 | "assetBundlePatterns": [
17 | "**/*"
18 | ],
19 | "ios": {
20 | "supportsTablet": true
21 | },
22 | "android": {
23 | "adaptiveIcon": {
24 | "foregroundImage": "./assets/adaptive-icon.png",
25 | "backgroundColor": "#FFFFFF"
26 | }
27 | },
28 | "web": {
29 | "favicon": "./assets/favicon.png"
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/assets/adaptive-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-typescript-bottom-tabs-supabase-auth-flow/assets/adaptive-icon.png
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-typescript-bottom-tabs-supabase-auth-flow/assets/favicon.png
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/assets/fonts/SpaceMono-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-typescript-bottom-tabs-supabase-auth-flow/assets/fonts/SpaceMono-Regular.ttf
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-typescript-bottom-tabs-supabase-auth-flow/assets/icon.png
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/assets/images/adaptive-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-typescript-bottom-tabs-supabase-auth-flow/assets/images/adaptive-icon.png
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/assets/images/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-typescript-bottom-tabs-supabase-auth-flow/assets/images/favicon.png
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/assets/images/forget.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-typescript-bottom-tabs-supabase-auth-flow/assets/images/forget.png
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/assets/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-typescript-bottom-tabs-supabase-auth-flow/assets/images/icon.png
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/assets/images/login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-typescript-bottom-tabs-supabase-auth-flow/assets/images/login.png
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/assets/images/register.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-typescript-bottom-tabs-supabase-auth-flow/assets/images/register.png
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/assets/images/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-typescript-bottom-tabs-supabase-auth-flow/assets/images/splash.png
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-typescript-bottom-tabs-supabase-auth-flow/assets/splash.png
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.cache(true);
3 | return {
4 | presets: ['babel-preset-expo'],
5 | };
6 | };
7 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "node_modules/expo/AppEntry.js",
3 | "scripts": {
4 | "start": "expo start",
5 | "android": "expo start --android",
6 | "ios": "expo start --ios",
7 | "web": "expo start --web",
8 | "eject": "expo eject"
9 | },
10 | "dependencies": {
11 | "@expo/vector-icons": "^12.0.0",
12 | "@react-native-async-storage/async-storage": "~1.15.0",
13 | "@react-navigation/bottom-tabs": "^6.0.9",
14 | "@react-navigation/native": "^6.0.6",
15 | "@react-navigation/native-stack": "^6.2.5",
16 | "@supabase/supabase-js": "^1.29.1",
17 | "expo": "~44.0.0",
18 | "expo-asset": "~8.4.5",
19 | "expo-font": "~10.0.4",
20 | "expo-status-bar": "~1.2.0",
21 | "firebase": "^9.6.1",
22 | "react": "17.0.1",
23 | "react-dom": "17.0.1",
24 | "react-native": "0.64.3",
25 | "react-native-rapi-ui": "^0.2.1",
26 | "react-native-safe-area-context": "3.3.2",
27 | "react-native-screens": "~3.10.1",
28 | "react-native-web": "0.17.1"
29 | },
30 | "devDependencies": {
31 | "@babel/core": "^7.12.9",
32 | "@types/react": "~17.0.21",
33 | "@types/react-native": "~0.64.12",
34 | "typescript": "~4.3.5"
35 | },
36 | "private": true
37 | }
38 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/src/components/utils/TabBarIcon.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { themeColor, useTheme } from "react-native-rapi-ui";
3 | import { Ionicons } from "@expo/vector-icons";
4 |
5 | export default ({ icon, focused }: { icon: any; focused: boolean }) => {
6 | const { isDarkmode } = useTheme();
7 | return (
8 |
20 | );
21 | };
22 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/src/components/utils/TabBarText.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Text, themeColor, useTheme } from "react-native-rapi-ui";
3 | export default ({ title, focused }: { title: string; focused: boolean }) => {
4 | const { isDarkmode } = useTheme();
5 | return (
6 |
18 | {title}
19 |
20 | );
21 | };
22 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/src/initSupabase.ts:
--------------------------------------------------------------------------------
1 | import AsyncStorage from "@react-native-async-storage/async-storage";
2 | import { createClient } from "@supabase/supabase-js";
3 |
4 | // Better put your these secret keys in .env file
5 | export const supabase = createClient("supabaseUrl", "supabaseKey", {
6 | localStorage: AsyncStorage as any,
7 | detectSessionInUrl: false // Prevents Supabase from evaluating window.location.href, breaking mobile
8 | });
9 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/src/navigation/AuthStack.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { createNativeStackNavigator } from "@react-navigation/native-stack";
3 |
4 | import Login from "../screens/auth/Login";
5 | import Register from "../screens/auth/Register";
6 | import ForgetPassword from "../screens/auth/ForgetPassword";
7 |
8 | const AuthStack = createNativeStackNavigator();
9 | const Auth = () => {
10 | return (
11 |
16 |
17 |
18 |
19 |
20 | );
21 | };
22 |
23 | export default Auth;
24 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/src/navigation/MainStack.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { createNativeStackNavigator } from "@react-navigation/native-stack";
3 |
4 | import SecondScreen from "../screens/SecondScreen";
5 | import MainTabs from "./MainTabs";
6 |
7 | const MainStack = createNativeStackNavigator();
8 | const Main = () => {
9 | return (
10 |
15 |
16 |
17 |
18 | );
19 | };
20 |
21 | export default Main;
22 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/src/navigation/MainTabs.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
3 |
4 | import { themeColor, useTheme } from "react-native-rapi-ui";
5 | import TabBarIcon from "../components/utils/TabBarIcon";
6 | import TabBarText from "../components/utils/TabBarText";
7 |
8 | import Home from "../screens/Home";
9 | import About from "../screens/About";
10 | import Profile from "../screens/Profile";
11 |
12 | const Tabs = createBottomTabNavigator();
13 | const MainTabs = () => {
14 | const { isDarkmode } = useTheme();
15 | return (
16 |
25 | {/* these icons using Ionicons */}
26 | (
31 |
32 | ),
33 | tabBarIcon: ({ focused }) => (
34 |
35 | ),
36 | }}
37 | />
38 | (
43 |
44 | ),
45 | tabBarIcon: ({ focused }) => (
46 |
47 | ),
48 | }}
49 | />
50 | (
55 |
56 | ),
57 | tabBarIcon: ({ focused }) => (
58 |
59 | ),
60 | }}
61 | />
62 |
63 | );
64 | };
65 |
66 | export default MainTabs;
67 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/src/navigation/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import { AuthContext } from '../provider/AuthProvider';
3 |
4 | import { NavigationContainer } from '@react-navigation/native';
5 |
6 | import Main from './MainStack';
7 | import Auth from './AuthStack';
8 | import Loading from '../screens/utils/Loading';
9 |
10 | export default () => {
11 | const auth = useContext(AuthContext);
12 | const user = auth.user;
13 | return (
14 |
15 | {user == null && }
16 | {user == false && }
17 | {user == true && }
18 |
19 | );
20 | };
21 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/src/provider/AuthProvider.tsx:
--------------------------------------------------------------------------------
1 | import React, { createContext, useState, useEffect } from 'react';
2 | import { supabase } from '../initSupabase';
3 | import { Session } from '@supabase/supabase-js';
4 | type ContextProps = {
5 | user: null | boolean;
6 | session: Session | null;
7 | };
8 |
9 | const AuthContext = createContext>({});
10 |
11 | interface Props {
12 | children: React.ReactNode;
13 | }
14 |
15 | const AuthProvider = (props: Props) => {
16 | // user null = loading
17 | const [user, setUser] = useState(null);
18 | const [session, setSession] = useState(null);
19 |
20 | useEffect(() => {
21 | const session = supabase.auth.session();
22 | setSession(session);
23 | setUser(session ? true : false);
24 | const { data: authListener } = supabase.auth.onAuthStateChange(
25 | async (event, session) => {
26 | console.log(`Supabase auth event: ${event}`);
27 | setSession(session);
28 | setUser(session ? true : false);
29 | }
30 | );
31 | return () => {
32 | authListener!.unsubscribe();
33 | };
34 | }, [user]);
35 |
36 | return (
37 |
43 | {props.children}
44 |
45 | );
46 | };
47 |
48 | export { AuthContext, AuthProvider };
49 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/src/screens/About.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View } from "react-native";
3 | import { MainStackParamList } from "../types/navigation";
4 | import { NativeStackScreenProps } from "@react-navigation/native-stack";
5 | import { Layout, Text } from "react-native-rapi-ui";
6 |
7 | export default function ({
8 | navigation,
9 | }: NativeStackScreenProps) {
10 | return (
11 |
12 |
19 | This is the About tab
20 |
21 |
22 | );
23 | }
24 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/src/screens/Home.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View, Linking } from "react-native";
3 | import { MainStackParamList } from "../types/navigation";
4 | import { NativeStackScreenProps } from "@react-navigation/native-stack";
5 | import { supabase } from "../initSupabase";
6 | import {
7 | Layout,
8 | Button,
9 | Text,
10 | TopNav,
11 | Section,
12 | SectionContent,
13 | useTheme,
14 | themeColor,
15 | } from "react-native-rapi-ui";
16 | import { Ionicons } from "@expo/vector-icons";
17 |
18 | export default function ({
19 | navigation,
20 | }: NativeStackScreenProps) {
21 | const { isDarkmode, setTheme } = useTheme();
22 | return (
23 |
24 |
32 | }
33 | rightAction={() => {
34 | if (isDarkmode) {
35 | setTheme("light");
36 | } else {
37 | setTheme("dark");
38 | }
39 | }}
40 | />
41 |
48 |
49 |
50 |
51 | These UI components provided by Rapi UI
52 |
53 |
85 |
86 |
87 |
88 | );
89 | }
90 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/src/screens/Profile.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View } from "react-native";
3 | import { MainStackParamList } from "../types/navigation";
4 | import { NativeStackScreenProps } from "@react-navigation/native-stack";
5 | import { Layout, Text } from "react-native-rapi-ui";
6 |
7 | export default function ({
8 | navigation,
9 | }: NativeStackScreenProps) {
10 | return (
11 |
12 |
19 | This is the Profile tab
20 |
21 |
22 | );
23 | }
24 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/src/screens/SecondScreen.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View } from "react-native";
3 | import { MainStackParamList } from "../types/navigation";
4 | import { NativeStackScreenProps } from "@react-navigation/native-stack";
5 | import {
6 | Layout,
7 | TopNav,
8 | Text,
9 | themeColor,
10 | useTheme,
11 | } from "react-native-rapi-ui";
12 | import { Ionicons } from "@expo/vector-icons";
13 |
14 | export default function ({
15 | navigation,
16 | }: NativeStackScreenProps) {
17 | const { isDarkmode, setTheme } = useTheme();
18 | return (
19 |
20 |
28 | }
29 | leftAction={() => navigation.goBack()}
30 | rightContent={
31 |
36 | }
37 | rightAction={() => {
38 | if (isDarkmode) {
39 | setTheme("light");
40 | } else {
41 | setTheme("dark");
42 | }
43 | }}
44 | />
45 |
52 | {/* This text using ubuntu font */}
53 | This is the second screen
54 |
55 |
56 | );
57 | }
58 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/src/screens/auth/ForgetPassword.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { StatusBar } from "expo-status-bar";
3 | import {
4 | ScrollView,
5 | TouchableOpacity,
6 | View,
7 | KeyboardAvoidingView,
8 | Image,
9 | } from "react-native";
10 | import { supabase } from "../../initSupabase";
11 | import { AuthStackParamList } from "../../types/navigation";
12 | import { NativeStackScreenProps } from "@react-navigation/native-stack";
13 | import {
14 | Layout,
15 | Text,
16 | TextInput,
17 | Button,
18 | useTheme,
19 | themeColor,
20 | } from "react-native-rapi-ui";
21 |
22 | export default function ({
23 | navigation,
24 | }: NativeStackScreenProps) {
25 | const { isDarkmode, setTheme } = useTheme();
26 | const [email, setEmail] = useState("");
27 | const [loading, setLoading] = useState(false);
28 |
29 | async function forget() {
30 | setLoading(true);
31 | const { data, error } = await supabase.auth.api.resetPasswordForEmail(
32 | email
33 | );
34 | if (!error) {
35 | setLoading(false);
36 | alert("Check your email to reset your password!");
37 | }
38 | if (error) {
39 | setLoading(false);
40 | alert(error.message);
41 | }
42 | }
43 | return (
44 |
45 |
46 |
51 |
59 |
67 |
68 |
76 |
84 | Forget Password
85 |
86 | Email
87 | setEmail(text)}
96 | />
97 | {
100 | forget();
101 | }}
102 | style={{
103 | marginTop: 20,
104 | }}
105 | disabled={loading}
106 | />
107 |
108 |
116 | Already have an account?
117 | {
119 | navigation.navigate("Login");
120 | }}
121 | >
122 |
129 | Login here
130 |
131 |
132 |
133 |
141 | {
143 | isDarkmode ? setTheme("light") : setTheme("dark");
144 | }}
145 | >
146 |
153 | {isDarkmode ? "☀️ light theme" : "🌑 dark theme"}
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 | );
162 | }
163 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/src/screens/auth/Login.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { StatusBar } from "expo-status-bar";
3 | import {
4 | ScrollView,
5 | TouchableOpacity,
6 | View,
7 | KeyboardAvoidingView,
8 | Image,
9 | } from "react-native";
10 | import { supabase } from "../../initSupabase";
11 | import { AuthStackParamList } from "../../types/navigation";
12 | import { NativeStackScreenProps } from "@react-navigation/native-stack";
13 |
14 | import {
15 | Layout,
16 | Text,
17 | TextInput,
18 | Button,
19 | useTheme,
20 | themeColor,
21 | } from "react-native-rapi-ui";
22 |
23 | export default function ({
24 | navigation,
25 | }: NativeStackScreenProps) {
26 | const { isDarkmode, setTheme } = useTheme();
27 | const [email, setEmail] = useState("");
28 | const [password, setPassword] = useState("");
29 | const [loading, setLoading] = useState(false);
30 |
31 | async function login() {
32 | setLoading(true);
33 | const { user, error } = await supabase.auth.signIn({
34 | email: email,
35 | password: password,
36 | });
37 | if (!error && !user) {
38 | setLoading(false);
39 | alert("Check your email for the login link!");
40 | }
41 | if (error) {
42 | setLoading(false);
43 | alert(error.message);
44 | }
45 | }
46 | return (
47 |
48 |
49 |
54 |
62 |
70 |
71 |
79 |
87 | Login
88 |
89 | Email
90 | setEmail(text)}
99 | />
100 |
101 | Password
102 | setPassword(text)}
111 | />
112 | {
115 | login();
116 | }}
117 | style={{
118 | marginTop: 20,
119 | }}
120 | disabled={loading}
121 | />
122 |
123 |
131 | Don't have an account?
132 | {
134 | navigation.navigate("Register");
135 | }}
136 | >
137 |
144 | Register here
145 |
146 |
147 |
148 |
156 | {
158 | navigation.navigate("ForgetPassword");
159 | }}
160 | >
161 |
162 | Forget password
163 |
164 |
165 |
166 |
174 | {
176 | isDarkmode ? setTheme("light") : setTheme("dark");
177 | }}
178 | >
179 |
186 | {isDarkmode ? "☀️ light theme" : "🌑 dark theme"}
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 | );
195 | }
196 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/src/screens/auth/Register.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { StatusBar } from "expo-status-bar";
3 | import {
4 | ScrollView,
5 | TouchableOpacity,
6 | View,
7 | KeyboardAvoidingView,
8 | Image,
9 | } from "react-native";
10 | import { supabase } from "../../initSupabase";
11 | import { AuthStackParamList } from "../../types/navigation";
12 | import { NativeStackScreenProps } from "@react-navigation/native-stack";
13 | import {
14 | Layout,
15 | Text,
16 | TextInput,
17 | Button,
18 | useTheme,
19 | themeColor,
20 | } from "react-native-rapi-ui";
21 |
22 | export default function ({
23 | navigation,
24 | }: NativeStackScreenProps) {
25 | const { isDarkmode, setTheme } = useTheme();
26 | const [email, setEmail] = useState("");
27 | const [password, setPassword] = useState("");
28 | const [loading, setLoading] = useState(false);
29 |
30 | async function register() {
31 | setLoading(true);
32 | const { user, error } = await supabase.auth.signUp({
33 | email: email,
34 | password: password,
35 | });
36 | if (!error && !user) {
37 | setLoading(false);
38 | alert("Check your email for the login link!");
39 | }
40 | if (error) {
41 | setLoading(false);
42 | alert(error.message);
43 | }
44 | }
45 | return (
46 |
47 |
48 |
53 |
61 |
69 |
70 |
78 |
86 | Register
87 |
88 | Email
89 | setEmail(text)}
98 | />
99 |
100 | Password
101 | setPassword(text)}
110 | />
111 | {
114 | register();
115 | }}
116 | style={{
117 | marginTop: 20,
118 | }}
119 | disabled={loading}
120 | />
121 |
122 |
130 | Already have an account?
131 | {
133 | navigation.navigate("Login");
134 | }}
135 | >
136 |
143 | Login here
144 |
145 |
146 |
147 |
155 | {
157 | isDarkmode ? setTheme("light") : setTheme("dark");
158 | }}
159 | >
160 |
167 | {isDarkmode ? "☀️ light theme" : "🌑 dark theme"}
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 | );
176 | }
177 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/src/screens/utils/Loading.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View, ActivityIndicator } from "react-native";
3 | import { Layout, themeColor } from "react-native-rapi-ui";
4 |
5 | export default function () {
6 | return (
7 |
8 |
15 |
16 |
17 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/src/types/navigation.tsx:
--------------------------------------------------------------------------------
1 | export type MainStackParamList = {
2 | MainTabs: undefined;
3 | SecondScreen: undefined;
4 | };
5 |
6 | export type AuthStackParamList = {
7 | Login: undefined;
8 | Register: undefined;
9 | ForgetPassword: undefined;
10 | };
11 |
12 | export type MainTabsParamList = {
13 | Home: undefined;
14 | Profile: undefined;
15 | About: undefined;
16 | };
17 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-supabase-auth-flow/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "expo/tsconfig.base",
3 | "compilerOptions": {
4 | "strict": true
5 | }
6 | }
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/.expo-shared/assets.json:
--------------------------------------------------------------------------------
1 | {
2 | "e997a5256149a4b76e6bfd6cbf519c5e5a0f1d278a3d8fa1253022b03c90473b": true,
3 | "af683c96e0ffd2cf81287651c9433fa44debc1220ca7cb431fe482747f34a505": true,
4 | "12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true,
5 | "40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true
6 | }
7 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/**/*
2 | .expo/*
3 | npm-debug.*
4 | *.jks
5 | *.p8
6 | *.p12
7 | *.key
8 | *.mobileprovision
9 | *.orig.*
10 | web-build/
11 |
12 | # macOS
13 | .DS_Store
14 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/App.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Navigation from "./src/navigation";
3 | import { AuthProvider } from "./src/provider/AuthProvider";
4 | import { ThemeProvider } from "react-native-rapi-ui";
5 | import { LogBox } from "react-native";
6 |
7 | export default function App() {
8 | const images = [
9 | require("./assets/images/login.png"),
10 | require("./assets/images/register.png"),
11 | require("./assets/images/forget.png"),
12 | ];
13 |
14 | // Ignore firebase v9 AsyncStorage warning
15 | React.useEffect(() => {
16 | LogBox.ignoreLogs([
17 | "AsyncStorage has been extracted from react-native core and will be removed in a future release. It can now be installed and imported from '@react-native-async-storage/async-storage' instead of 'react-native'. See https://github.com/react-native-async-storage/async-storage",
18 | ]);
19 | }, []);
20 |
21 | return (
22 |
23 |
24 |
25 |
26 |
27 | );
28 | }
29 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/README.md:
--------------------------------------------------------------------------------
1 | # Template bottom tabs with auth flow (Typescript)
2 |
3 | Typescript Template starter with React Navigation Bottom Tabs and Firebase auth using React Context
4 |
5 | # Preview
6 |
7 | 
8 |
9 | # Installation
10 |
11 | 1. Install [node.js](https://nodejs.org/en/)
12 | 2. Install Expo
13 |
14 | ```jsx
15 | npm install --global expo-cli
16 | ```
17 |
18 | 3. Download this repo
19 | 4. Install deps on your template folder
20 |
21 | ```jsx
22 | npm install
23 | ```
24 |
25 | 5. Start the environtment
26 |
27 | ```jsx
28 | expo start
29 | ```
30 |
31 | # Auth Flow
32 |
33 | ### Firebase Setup
34 |
35 | - Set up a new firebase project
36 | - Go to Authentication and under Sign-in Method enable Email/Password
37 | - Fill this firebase config to your config inside `./src/navigation/index.tsx`
38 |
39 | ```jsx
40 | // Better put your these secret keys in .env file
41 | const firebaseConfig = {
42 | apiKey: '',
43 | authDomain: '',
44 | databaseURL: '',
45 | projectId: '',
46 | storageBucket: '',
47 | messagingSenderId: '',
48 | appId: '',
49 | };
50 | ```
51 |
52 | and you good to go!
53 |
54 | ### Prebuilt UI Screens
55 |
56 | There are 3 screens included inside `./src/screens/auth` and one more thing its included with the firebase auth function, so you don't need to create the function. The ilustrations I use [undraw](https://undraw.co/)
57 |
58 | - Login screen `./src/screens/auth/login.tsx`
59 | - Register screen `./src/screens/auth/register.tsx`
60 | - Forget password screen `./src/screens/auth/forget.tsx`
61 |
62 | ### React Navigation Auth Flow
63 |
64 | The checking logged users process is inside `./src/provider/AuthProvider` I use React Context, you can add more functions like get the data of the user and store it to the context (better static data, ex: uid)
65 |
66 | Inside the navigator `./src/navigation/AppNavigator.js`
67 | There's 2 stack navigator :
68 |
69 | - `` → for not logged in users stack
70 | - `` → for logged in users stack
71 | - `` → when checking if the user is logged in or not loading screen
72 |
73 | ```jsx
74 | export default () => {
75 | const auth = useContext(AuthContext);
76 | const user = auth.user;
77 | return (
78 |
79 | {user == null && }
80 | {user == false && }
81 | {user == true && }
82 |
83 | );
84 | };
85 | ```
86 |
87 | # Rapi UI
88 |
89 | 
90 |
91 | These UI components are provided by [Rapi UI](https://rapi-ui.kikiding.space/).
92 | Check the [documentation](https://rapi-ui.kikiding.space/docs/) for usage and more components.
93 |
94 | # File Managements
95 |
96 | These are the folders and the functionality all in `src/`
97 |
98 | ```jsx
99 | /src/assets -> for media such as images, etc
100 | /src/components -> for components
101 | /src/navigation -> for React Navigation
102 | /src/provider -> for React Context
103 | /src/screens -> for Screens
104 | /src/types -> for Types
105 | ```
106 |
107 | if you find these useful don't forget to give it a star ⭐ and share it to your friends ❤️
108 |
109 | Reach me on [twitter](https://twitter.com/kikiding/)
110 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "TypescriptBottomTabsAuthFlow",
4 | "slug": "TypescriptBottomTabsAuthFlow",
5 | "version": "1.0.0",
6 | "orientation": "portrait",
7 | "icon": "./assets/images/icon.png",
8 | "scheme": "myapp",
9 | "userInterfaceStyle": "automatic",
10 | "splash": {
11 | "image": "./assets/images/splash.png",
12 | "resizeMode": "contain",
13 | "backgroundColor": "#ffffff"
14 | },
15 | "updates": {
16 | "fallbackToCacheTimeout": 0
17 | },
18 | "assetBundlePatterns": ["**/*"],
19 | "ios": {
20 | "supportsTablet": true
21 | },
22 | "android": {
23 | "adaptiveIcon": {
24 | "foregroundImage": "./assets/images/adaptive-icon.png",
25 | "backgroundColor": "#FFFFFF"
26 | }
27 | },
28 | "web": {
29 | "favicon": "./assets/images/favicon.png"
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/assets/images/adaptive-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-typescript-bottom-tabs-with-auth-flow/assets/images/adaptive-icon.png
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/assets/images/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-typescript-bottom-tabs-with-auth-flow/assets/images/favicon.png
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/assets/images/forget.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-typescript-bottom-tabs-with-auth-flow/assets/images/forget.png
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/assets/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-typescript-bottom-tabs-with-auth-flow/assets/images/icon.png
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/assets/images/login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-typescript-bottom-tabs-with-auth-flow/assets/images/login.png
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/assets/images/register.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-typescript-bottom-tabs-with-auth-flow/assets/images/register.png
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/assets/images/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-typescript-bottom-tabs-with-auth-flow/assets/images/splash.png
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.cache(true);
3 | return {
4 | presets: ['babel-preset-expo'],
5 | };
6 | };
7 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "node_modules/expo/AppEntry.js",
3 | "scripts": {
4 | "start": "expo start",
5 | "android": "expo start --android",
6 | "ios": "expo start --ios",
7 | "web": "expo start --web",
8 | "eject": "expo eject"
9 | },
10 | "dependencies": {
11 | "@expo/vector-icons": "^12.0.0",
12 | "@react-navigation/bottom-tabs": "^6.0.9",
13 | "@react-navigation/native": "^6.0.6",
14 | "@react-navigation/native-stack": "^6.2.5",
15 | "expo": "~44.0.0",
16 | "expo-asset": "~8.4.5",
17 | "expo-font": "~10.0.4",
18 | "expo-status-bar": "~1.2.0",
19 | "firebase": "^9.6.1",
20 | "react": "17.0.1",
21 | "react-dom": "17.0.1",
22 | "react-native": "0.64.3",
23 | "react-native-rapi-ui": "^0.2.1",
24 | "react-native-safe-area-context": "3.3.2",
25 | "react-native-screens": "~3.10.1",
26 | "react-native-web": "0.17.1"
27 | },
28 | "devDependencies": {
29 | "@babel/core": "^7.12.9",
30 | "@types/react": "~17.0.21",
31 | "@types/react-native": "~0.64.12",
32 | "typescript": "~4.3.5"
33 | },
34 | "private": true
35 | }
36 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/src/components/utils/TabBarIcon.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { themeColor, useTheme } from "react-native-rapi-ui";
3 | import { Ionicons } from "@expo/vector-icons";
4 |
5 | export default ({ icon, focused }: { icon: any; focused: boolean }) => {
6 | const { isDarkmode } = useTheme();
7 | return (
8 |
20 | );
21 | };
22 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/src/components/utils/TabBarText.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Text, themeColor, useTheme } from "react-native-rapi-ui";
3 | export default ({ title, focused }: { title: string; focused: boolean }) => {
4 | const { isDarkmode } = useTheme();
5 | return (
6 |
18 | {title}
19 |
20 | );
21 | };
22 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/src/navigation/AuthStack.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { createNativeStackNavigator } from "@react-navigation/native-stack";
3 |
4 | import Login from "../screens/auth/Login";
5 | import Register from "../screens/auth/Register";
6 | import ForgetPassword from "../screens/auth/ForgetPassword";
7 |
8 | const AuthStack = createNativeStackNavigator();
9 | const Auth = () => {
10 | return (
11 |
16 |
17 |
18 |
19 |
20 | );
21 | };
22 |
23 | export default Auth;
24 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/src/navigation/MainStack.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { createNativeStackNavigator } from "@react-navigation/native-stack";
3 |
4 | import SecondScreen from "../screens/SecondScreen";
5 | import MainTabs from "./MainTabs";
6 |
7 | const MainStack = createNativeStackNavigator();
8 | const Main = () => {
9 | return (
10 |
15 |
16 |
17 |
18 | );
19 | };
20 |
21 | export default Main;
22 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/src/navigation/MainTabs.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
3 |
4 | import { themeColor, useTheme } from "react-native-rapi-ui";
5 | import TabBarIcon from "../components/utils/TabBarIcon";
6 | import TabBarText from "../components/utils/TabBarText";
7 |
8 | import Home from "../screens/Home";
9 | import About from "../screens/About";
10 | import Profile from "../screens/Profile";
11 |
12 | const Tabs = createBottomTabNavigator();
13 | const MainTabs = () => {
14 | const { isDarkmode } = useTheme();
15 | return (
16 |
25 | {/* these icons using Ionicons */}
26 | (
31 |
32 | ),
33 | tabBarIcon: ({ focused }) => (
34 |
35 | ),
36 | }}
37 | />
38 | (
43 |
44 | ),
45 | tabBarIcon: ({ focused }) => (
46 |
47 | ),
48 | }}
49 | />
50 | (
55 |
56 | ),
57 | tabBarIcon: ({ focused }) => (
58 |
59 | ),
60 | }}
61 | />
62 |
63 | );
64 | };
65 |
66 | export default MainTabs;
67 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/src/navigation/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from "react";
2 | import { getApps, initializeApp } from "firebase/app";
3 | import { AuthContext } from "../provider/AuthProvider";
4 |
5 | import { NavigationContainer } from "@react-navigation/native";
6 |
7 | import Main from "./MainStack";
8 | import Auth from "./AuthStack";
9 | import Loading from "../screens/utils/Loading";
10 |
11 | // Better put your these secret keys in .env file
12 | const firebaseConfig = {
13 | apiKey: "",
14 | authDomain: "",
15 | databaseURL: "",
16 | projectId: "",
17 | storageBucket: "",
18 | messagingSenderId: "",
19 | appId: "",
20 | };
21 | if (getApps().length === 0) {
22 | initializeApp(firebaseConfig);
23 | }
24 |
25 | export default () => {
26 | const auth = useContext(AuthContext);
27 | const user = auth.user;
28 | return (
29 |
30 | {user == null && }
31 | {user == false && }
32 | {user == true && }
33 |
34 | );
35 | };
36 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/src/provider/AuthProvider.tsx:
--------------------------------------------------------------------------------
1 | import React, { createContext, useState, useEffect } from "react";
2 | import { getAuth, onAuthStateChanged } from "firebase/auth";
3 |
4 | type ContextProps = {
5 | user: null | boolean;
6 | };
7 |
8 | const AuthContext = createContext>({});
9 |
10 | interface Props {
11 | children: React.ReactNode;
12 | }
13 |
14 | const AuthProvider = (props: Props) => {
15 | const auth = getAuth();
16 | // user null = loading
17 | const [user, setUser] = useState(null);
18 |
19 | useEffect(() => {
20 | checkLogin();
21 | }, []);
22 |
23 | function checkLogin() {
24 | onAuthStateChanged(auth, function (u) {
25 | if (u) {
26 | setUser(true);
27 | // getUserData();
28 | } else {
29 | setUser(false);
30 | // setUserData(null);
31 | }
32 | });
33 | }
34 |
35 | return (
36 |
41 | {props.children}
42 |
43 | );
44 | };
45 |
46 | export { AuthContext, AuthProvider };
47 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/src/screens/About.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View } from "react-native";
3 | import { MainStackParamList } from "../types/navigation";
4 | import { NativeStackScreenProps } from "@react-navigation/native-stack";
5 | import { Layout, Text } from "react-native-rapi-ui";
6 |
7 | export default function ({
8 | navigation,
9 | }: NativeStackScreenProps) {
10 | return (
11 |
12 |
19 | This is the About tab
20 |
21 |
22 | );
23 | }
24 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/src/screens/Home.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View, Linking } from "react-native";
3 | import { MainStackParamList } from "../types/navigation";
4 | import { getAuth, signOut } from "firebase/auth";
5 | import { NativeStackScreenProps } from "@react-navigation/native-stack";
6 | import {
7 | Layout,
8 | Button,
9 | Text,
10 | TopNav,
11 | Section,
12 | SectionContent,
13 | useTheme,
14 | themeColor,
15 | } from "react-native-rapi-ui";
16 | import { Ionicons } from "@expo/vector-icons";
17 |
18 | export default function ({
19 | navigation,
20 | }: NativeStackScreenProps) {
21 | const { isDarkmode, setTheme } = useTheme();
22 | const auth = getAuth();
23 | return (
24 |
25 |
33 | }
34 | rightAction={() => {
35 | if (isDarkmode) {
36 | setTheme("light");
37 | } else {
38 | setTheme("dark");
39 | }
40 | }}
41 | />
42 |
49 |
50 |
51 |
52 | These UI components provided by Rapi UI
53 |
54 | Linking.openURL("https://rapi-ui.kikiding.space/")}
59 | />
60 | {
63 | navigation.navigate("SecondScreen");
64 | }}
65 | style={{
66 | marginTop: 10,
67 | }}
68 | />
69 | {
73 | signOut(auth);
74 | }}
75 | style={{
76 | marginTop: 10,
77 | }}
78 | />
79 |
80 |
81 |
82 |
83 | );
84 | }
85 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/src/screens/Profile.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View } from "react-native";
3 | import { MainStackParamList } from "../types/navigation";
4 | import { NativeStackScreenProps } from "@react-navigation/native-stack";
5 | import { Layout, Text } from "react-native-rapi-ui";
6 |
7 | export default function ({
8 | navigation,
9 | }: NativeStackScreenProps) {
10 | return (
11 |
12 |
19 | This is the Profile tab
20 |
21 |
22 | );
23 | }
24 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/src/screens/SecondScreen.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View } from "react-native";
3 | import { MainStackParamList } from "../types/navigation";
4 | import { NativeStackScreenProps } from "@react-navigation/native-stack";
5 | import {
6 | Layout,
7 | TopNav,
8 | Text,
9 | useTheme,
10 | themeColor,
11 | } from "react-native-rapi-ui";
12 | import { Ionicons } from "@expo/vector-icons";
13 |
14 | export default function ({
15 | navigation,
16 | }: NativeStackScreenProps) {
17 | const { isDarkmode, setTheme } = useTheme();
18 | return (
19 |
20 |
28 | }
29 | leftAction={() => navigation.goBack()}
30 | rightContent={
31 |
36 | }
37 | rightAction={() => {
38 | if (isDarkmode) {
39 | setTheme("light");
40 | } else {
41 | setTheme("dark");
42 | }
43 | }}
44 | />
45 |
52 | {/* This text using ubuntu font */}
53 | This is the second screen
54 |
55 |
56 | );
57 | }
58 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/src/screens/auth/ForgetPassword.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import {
3 | ScrollView,
4 | TouchableOpacity,
5 | View,
6 | KeyboardAvoidingView,
7 | Image,
8 | } from "react-native";
9 | import { AuthStackParamList } from "../../types/navigation";
10 | import { getAuth, sendPasswordResetEmail } from "firebase/auth";
11 | import { NativeStackScreenProps } from "@react-navigation/native-stack";
12 | import {
13 | Layout,
14 | Text,
15 | TextInput,
16 | Button,
17 | useTheme,
18 | themeColor,
19 | } from "react-native-rapi-ui";
20 |
21 | export default function ({
22 | navigation,
23 | }: NativeStackScreenProps) {
24 | const { isDarkmode, setTheme } = useTheme();
25 | const auth = getAuth();
26 | const [email, setEmail] = useState("");
27 | const [loading, setLoading] = useState(false);
28 |
29 | async function forget() {
30 | setLoading(true);
31 | await sendPasswordResetEmail(auth, email)
32 | .then(function () {
33 | setLoading(false);
34 | navigation.navigate("Login");
35 | alert("Your password reset has been sent to your email");
36 | })
37 | .catch(function (error) {
38 | setLoading(false);
39 | alert(error);
40 | });
41 | }
42 | return (
43 |
44 |
45 |
50 |
58 |
66 |
67 |
75 |
83 | Forget Password
84 |
85 | Email
86 | setEmail(text)}
95 | />
96 | {
99 | forget();
100 | }}
101 | style={{
102 | marginTop: 20,
103 | }}
104 | disabled={loading}
105 | />
106 |
107 |
115 | Already have an account?
116 | {
118 | navigation.navigate("Login");
119 | }}
120 | >
121 |
128 | Login here
129 |
130 |
131 |
132 |
140 | {
142 | isDarkmode ? setTheme("light") : setTheme("dark");
143 | }}
144 | >
145 |
152 | {isDarkmode ? "☀️ light theme" : "🌑 dark theme"}
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 | );
161 | }
162 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/src/screens/auth/Login.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import {
3 | ScrollView,
4 | TouchableOpacity,
5 | View,
6 | KeyboardAvoidingView,
7 | Image,
8 | } from "react-native";
9 | import { AuthStackParamList } from "../../types/navigation";
10 | import { getAuth, signInWithEmailAndPassword } from "firebase/auth";
11 | import { NativeStackScreenProps } from "@react-navigation/native-stack";
12 | import {
13 | Layout,
14 | Text,
15 | TextInput,
16 | Button,
17 | useTheme,
18 | themeColor,
19 | } from "react-native-rapi-ui";
20 |
21 | export default function ({
22 | navigation,
23 | }: NativeStackScreenProps) {
24 | const { isDarkmode, setTheme } = useTheme();
25 | const auth = getAuth();
26 | const [email, setEmail] = useState("");
27 | const [password, setPassword] = useState("");
28 | const [loading, setLoading] = useState(false);
29 |
30 | async function login() {
31 | setLoading(true);
32 | await signInWithEmailAndPassword(auth, email, password).catch(function (
33 | error
34 | ) {
35 | // Handle Errors here.
36 | var errorCode = error.code;
37 | var errorMessage = error.message;
38 | // ...
39 | setLoading(false);
40 | alert(errorMessage);
41 | });
42 | }
43 | return (
44 |
45 |
46 |
51 |
59 |
67 |
68 |
76 |
84 | Login
85 |
86 | Email
87 | setEmail(text)}
96 | />
97 |
98 | Password
99 | setPassword(text)}
108 | />
109 | {
112 | login();
113 | }}
114 | style={{
115 | marginTop: 20,
116 | }}
117 | disabled={loading}
118 | />
119 |
120 |
128 | Don't have an account?
129 | {
131 | navigation.navigate("Register");
132 | }}
133 | >
134 |
141 | Register here
142 |
143 |
144 |
145 |
153 | {
155 | navigation.navigate("ForgetPassword");
156 | }}
157 | >
158 |
159 | Forget password
160 |
161 |
162 |
163 |
171 | {
173 | isDarkmode ? setTheme("light") : setTheme("dark");
174 | }}
175 | >
176 |
183 | {isDarkmode ? "☀️ light theme" : "🌑 dark theme"}
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 | );
192 | }
193 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/src/screens/auth/Register.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { StatusBar } from "expo-status-bar";
3 | import {
4 | ScrollView,
5 | TouchableOpacity,
6 | View,
7 | KeyboardAvoidingView,
8 | Image,
9 | } from "react-native";
10 | import { AuthStackParamList } from "../../types/navigation";
11 | import { getAuth, createUserWithEmailAndPassword } from "firebase/auth";
12 | import { NativeStackScreenProps } from "@react-navigation/native-stack";
13 | import {
14 | Layout,
15 | Text,
16 | TextInput,
17 | Button,
18 | useTheme,
19 | themeColor,
20 | } from "react-native-rapi-ui";
21 |
22 | export default function ({
23 | navigation,
24 | }: NativeStackScreenProps) {
25 | const { isDarkmode, setTheme } = useTheme();
26 | const auth = getAuth();
27 | const [email, setEmail] = useState("");
28 | const [password, setPassword] = useState("");
29 | const [loading, setLoading] = useState(false);
30 |
31 | async function register() {
32 | setLoading(true);
33 | await createUserWithEmailAndPassword(auth, email, password).catch(function (
34 | error: any
35 | ) {
36 | // Handle Errors here.
37 | var errorCode = error.code;
38 | var errorMessage = error.message;
39 | // ...
40 | setLoading(false);
41 | alert(errorMessage);
42 | });
43 | }
44 | return (
45 |
46 |
47 |
52 |
60 |
68 |
69 |
77 |
85 | Register
86 |
87 | Email
88 | setEmail(text)}
97 | />
98 |
99 | Password
100 | setPassword(text)}
109 | />
110 | {
113 | register();
114 | }}
115 | style={{
116 | marginTop: 20,
117 | }}
118 | disabled={loading}
119 | />
120 |
121 |
129 | Already have an account?
130 | {
132 | navigation.navigate("Login");
133 | }}
134 | >
135 |
142 | Login here
143 |
144 |
145 |
146 |
154 | {
156 | isDarkmode ? setTheme("light") : setTheme("dark");
157 | }}
158 | >
159 |
166 | {isDarkmode ? "☀️ light theme" : "🌑 dark theme"}
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 | );
175 | }
176 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/src/screens/utils/Loading.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View, ActivityIndicator } from "react-native";
3 | import { Layout, themeColor } from "react-native-rapi-ui";
4 |
5 | export default function () {
6 | return (
7 |
8 |
15 |
16 |
17 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/src/types/navigation.tsx:
--------------------------------------------------------------------------------
1 | export type MainStackParamList = {
2 | MainTabs: undefined;
3 | SecondScreen: undefined;
4 | };
5 |
6 | export type AuthStackParamList = {
7 | Login: undefined;
8 | Register: undefined;
9 | ForgetPassword: undefined;
10 | };
11 |
12 | export type MainTabsParamList = {
13 | Home: undefined;
14 | Profile: undefined;
15 | About: undefined;
16 | };
17 |
--------------------------------------------------------------------------------
/template-typescript-bottom-tabs-with-auth-flow/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowSyntheticDefaultImports": true,
4 | "jsx": "react-native",
5 | "lib": [
6 | "dom",
7 | "esnext"
8 | ],
9 | "moduleResolution": "node",
10 | "noEmit": true,
11 | "skipLibCheck": true,
12 | "resolveJsonModule": true,
13 | "strict": true
14 | },
15 | "extends": "expo/tsconfig.base"
16 | }
17 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs-auth-flow/.expo-shared/assets.json:
--------------------------------------------------------------------------------
1 | {
2 | "12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true,
3 | "40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true
4 | }
5 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs-auth-flow/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/**/*
2 | .expo/*
3 | npm-debug.*
4 | *.jks
5 | *.p8
6 | *.p12
7 | *.key
8 | *.mobileprovision
9 | *.orig.*
10 | web-build/
11 |
12 | # macOS
13 | .DS_Store
14 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs-auth-flow/App.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import AppNavigator from "./src/navigation/AppNavigator";
3 | import { AuthProvider } from "./src/provider/AuthProvider";
4 | import { ThemeProvider } from "react-native-rapi-ui";
5 | import { LogBox } from "react-native";
6 |
7 | export default function App() {
8 | const images = [
9 | require("./assets/icon.png"),
10 | require("./assets/splash.png"),
11 | require("./assets/login.png"),
12 | require("./assets/register.png"),
13 | require("./assets/forget.png"),
14 | ];
15 |
16 | // Ignore firebase v9 AsyncStorage warning
17 | React.useEffect(() => {
18 | LogBox.ignoreLogs([
19 | "AsyncStorage has been extracted from react-native core and will be removed in a future release. It can now be installed and imported from '@react-native-async-storage/async-storage' instead of 'react-native'. See https://github.com/react-native-async-storage/async-storage",
20 | ]);
21 | }, []);
22 |
23 | return (
24 |
25 |
26 |
27 |
28 |
29 | );
30 | }
31 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs-auth-flow/README.md:
--------------------------------------------------------------------------------
1 | # Template Bottom tabs with auth flow
2 |
3 | Template starter with React Navigation Bottom Tabs and Firebase auth using React Context
4 |
5 | # Preview
6 |
7 | 
8 |
9 | # Installation
10 |
11 | 1. Install [node.js](https://nodejs.org/en/)
12 | 2. Install Expo
13 |
14 | ```jsx
15 | npm install --global expo-cli
16 | ```
17 |
18 | 3. Download this repo
19 | 4. Install deps on your template folder
20 |
21 | ```jsx
22 | npm install
23 | ```
24 |
25 | 5. Start the environtment
26 |
27 | ```jsx
28 | expo start
29 | ```
30 |
31 | # Auth Flow
32 |
33 | ### Firebase Setup
34 |
35 | - Set up a new firebase project
36 | - Go to Authentication and under Sign-in Method enable Email/Password
37 | - Fill this firebase config to your config inside `./src/navigation/AppNavigator.js`
38 |
39 | ```jsx
40 | // Better put your these secret keys in .env file
41 | const firebaseConfig = {
42 | apiKey: '',
43 | authDomain: '',
44 | databaseURL: '',
45 | projectId: '',
46 | storageBucket: '',
47 | messagingSenderId: '',
48 | appId: '',
49 | };
50 | ```
51 |
52 | and you good to go!
53 |
54 | ### Prebuilt UI Screens
55 |
56 | There are 3 screens included inside `./src/screens/auth` and one more thing its included with the firebase auth function, so you don't need to create the function. The ilustrations I use [undraw](https://undraw.co/)
57 |
58 | - Login screen `./src/screens/auth/login.tsx`
59 | - Register screen `./src/screens/auth/register.tsx`
60 | - Forget password screen `./src/screens/auth/forget.tsx`
61 |
62 | I personally use these screens on my project [TiktTeng](https://github.com/codingki/TikTeng) in early stages before the redesign, feel free to use these screens ❤️
63 |
64 | ### React Navigation Auth Flow
65 |
66 | The checking logged users process is inside `./src/provider/AuthProvider` I use React Context, you can add more functions like get the data of the user and store it to the context (better static data, ex: uid)
67 |
68 | Inside the navigator `./src/navigation/AppNavigator.js`
69 | There's 2 stack navigator :
70 |
71 | - `` → for not logged in users stack
72 | - `` → for logged in users stack
73 | - `` → when checking if the user is logged in or not loading screen
74 |
75 | ```jsx
76 | export default () => {
77 | const auth = useContext(AuthContext);
78 | const user = auth.user;
79 | return (
80 |
81 | {user == null && }
82 | {user == false && }
83 | {user == true && }
84 |
85 | );
86 | };
87 | ```
88 |
89 | # Rapi UI
90 |
91 | 
92 |
93 | These UI components are provided by [Rapi UI](https://rapi-ui.kikiding.space/).
94 | Check the [documentation](https://rapi-ui.kikiding.space/docs/) for usage and more components.
95 |
96 | # File Managements
97 |
98 | These are the folders and the functionality
99 |
100 | ```jsx
101 | /src/assets -> for media such as images, etc
102 | /src/components -> for components
103 | /src/navigation -> for React Navigation
104 | /src/provider -> for React Context
105 | /src/screens -> for Screens
106 | ```
107 |
108 | if you find these useful don't forget to give it a star ⭐ and share it to your friends ❤️
109 |
110 | Reach me on [twitter](https://twitter.com/kikiding/)
111 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs-auth-flow/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "BottomTabsFirebaseAuthFlow",
4 | "slug": "BottomTabsFirebaseAuthFlow",
5 | "version": "1.0.0",
6 | "orientation": "portrait",
7 | "icon": "./assets/icon.png",
8 | "splash": {
9 | "image": "./assets/splash.png",
10 | "resizeMode": "contain",
11 | "backgroundColor": "#ffffff"
12 | },
13 | "updates": {
14 | "fallbackToCacheTimeout": 0
15 | },
16 | "assetBundlePatterns": ["**/*"],
17 | "ios": {
18 | "supportsTablet": true
19 | },
20 | "web": {
21 | "favicon": "./assets/favicon.png"
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs-auth-flow/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-with-bottom-tabs-auth-flow/assets/favicon.png
--------------------------------------------------------------------------------
/template-with-bottom-tabs-auth-flow/assets/forget.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-with-bottom-tabs-auth-flow/assets/forget.png
--------------------------------------------------------------------------------
/template-with-bottom-tabs-auth-flow/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-with-bottom-tabs-auth-flow/assets/icon.png
--------------------------------------------------------------------------------
/template-with-bottom-tabs-auth-flow/assets/login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-with-bottom-tabs-auth-flow/assets/login.png
--------------------------------------------------------------------------------
/template-with-bottom-tabs-auth-flow/assets/register.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-with-bottom-tabs-auth-flow/assets/register.png
--------------------------------------------------------------------------------
/template-with-bottom-tabs-auth-flow/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-with-bottom-tabs-auth-flow/assets/splash.png
--------------------------------------------------------------------------------
/template-with-bottom-tabs-auth-flow/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.cache(true);
3 | return {
4 | presets: ['babel-preset-expo'],
5 | };
6 | };
7 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs-auth-flow/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "node_modules/expo/AppEntry.js",
3 | "scripts": {
4 | "start": "expo start",
5 | "android": "expo start --android",
6 | "ios": "expo start --ios",
7 | "web": "expo start --web",
8 | "eject": "expo eject"
9 | },
10 | "dependencies": {
11 | "@expo/vector-icons": "^12.0.0",
12 | "@react-navigation/bottom-tabs": "^6.0.9",
13 | "@react-navigation/native": "^6.0.6",
14 | "@react-navigation/native-stack": "^6.2.5",
15 | "expo": "~44.0.0",
16 | "expo-asset": "~8.4.5",
17 | "expo-font": "~10.0.4",
18 | "expo-status-bar": "~1.2.0",
19 | "firebase": "^9.6.1",
20 | "react": "17.0.1",
21 | "react-dom": "17.0.1",
22 | "react-native": "0.64.3",
23 | "react-native-rapi-ui": "^0.2.1",
24 | "react-native-safe-area-context": "3.3.2",
25 | "react-native-screens": "~3.10.1",
26 | "react-native-web": "0.17.1"
27 | },
28 | "devDependencies": {
29 | "@babel/core": "^7.12.9"
30 | },
31 | "private": true
32 | }
33 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs-auth-flow/src/components/utils/TabBarIcon.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { themeColor, useTheme } from "react-native-rapi-ui";
3 | import { Ionicons } from "@expo/vector-icons";
4 |
5 | export default (props) => {
6 | const { isDarkmode } = useTheme();
7 | return (
8 |
20 | );
21 | };
22 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs-auth-flow/src/components/utils/TabBarText.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Text, themeColor, useTheme } from "react-native-rapi-ui";
3 | export default (props) => {
4 | const { isDarkmode } = useTheme();
5 | return (
6 |
18 | {props.title}
19 |
20 | );
21 | };
22 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs-auth-flow/src/navigation/AppNavigator.js:
--------------------------------------------------------------------------------
1 | import React, { useContext } from "react";
2 | import { initializeApp, getApps } from "firebase/app";
3 | import { NavigationContainer } from "@react-navigation/native";
4 | import { createNativeStackNavigator } from "@react-navigation/native-stack";
5 | import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
6 |
7 | import { useTheme, themeColor } from "react-native-rapi-ui";
8 | import TabBarIcon from "../components/utils/TabBarIcon";
9 | import TabBarText from "../components/utils/TabBarText";
10 | //Screens
11 | import Home from "../screens/Home";
12 | import SecondScreen from "../screens/SecondScreen";
13 | import About from "../screens/About";
14 | import Profile from "../screens/Profile";
15 | import Loading from "../screens/utils/Loading";
16 | // Auth screens
17 | import Login from "../screens/auth/Login";
18 | import Register from "../screens/auth/Register";
19 | import ForgetPassword from "../screens/auth/ForgetPassword";
20 | import { AuthContext } from "../provider/AuthProvider";
21 |
22 | // Better put your these secret keys in .env file
23 | const firebaseConfig = {
24 | apiKey: "",
25 | authDomain: "",
26 | databaseURL: "",
27 | projectId: "",
28 | storageBucket: "",
29 | messagingSenderId: "",
30 | appId: "",
31 | };
32 |
33 | if (getApps().length === 0) {
34 | initializeApp(firebaseConfig);
35 | }
36 |
37 | const AuthStack = createNativeStackNavigator();
38 | const Auth = () => {
39 | return (
40 |
45 |
46 |
47 |
48 |
49 | );
50 | };
51 |
52 | const MainStack = createNativeStackNavigator();
53 | const Main = () => {
54 | return (
55 |
60 |
61 |
62 |
63 | );
64 | };
65 |
66 | const Tabs = createBottomTabNavigator();
67 | const MainTabs = () => {
68 | const { isDarkmode } = useTheme();
69 | return (
70 |
79 | {/* these icons using Ionicons */}
80 | (
85 |
86 | ),
87 | tabBarIcon: ({ focused }) => (
88 |
89 | ),
90 | }}
91 | />
92 | (
97 |
98 | ),
99 | tabBarIcon: ({ focused }) => (
100 |
101 | ),
102 | }}
103 | />
104 | (
109 |
110 | ),
111 | tabBarIcon: ({ focused }) => (
112 |
113 | ),
114 | }}
115 | />
116 |
117 | );
118 | };
119 |
120 | export default () => {
121 | const auth = useContext(AuthContext);
122 | const user = auth.user;
123 | return (
124 |
125 | {user == null && }
126 | {user == false && }
127 | {user == true && }
128 |
129 | );
130 | };
131 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs-auth-flow/src/provider/AuthProvider.js:
--------------------------------------------------------------------------------
1 | import React, { createContext, useState, useEffect } from "react";
2 | import { getAuth, onAuthStateChanged } from "firebase/auth";
3 |
4 | const AuthContext = createContext();
5 | const AuthProvider = (props) => {
6 | const auth = getAuth();
7 | // user null = loading
8 | const [user, setUser] = useState(null);
9 |
10 | useEffect(() => {
11 | checkLogin();
12 | }, []);
13 |
14 | function checkLogin() {
15 | onAuthStateChanged(auth, (u) => {
16 | if (u) {
17 | setUser(true);
18 | // getUserData();
19 | } else {
20 | setUser(false);
21 | // setUserData(null);
22 | }
23 | });
24 | }
25 |
26 | return (
27 |
32 | {props.children}
33 |
34 | );
35 | };
36 |
37 | export { AuthContext, AuthProvider };
38 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs-auth-flow/src/screens/About.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 | import { Layout, Text } from 'react-native-rapi-ui';
4 |
5 | export default function ({ navigation }) {
6 | return (
7 |
8 |
15 | This is the About tab
16 |
17 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs-auth-flow/src/screens/Home.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View, Linking } from "react-native";
3 | import { getAuth, signOut } from "firebase/auth";
4 | import {
5 | Layout,
6 | Button,
7 | Text,
8 | TopNav,
9 | Section,
10 | SectionContent,
11 | useTheme,
12 | } from "react-native-rapi-ui";
13 |
14 | export default function ({ navigation }) {
15 | const { isDarkmode, setTheme } = useTheme();
16 | const auth = getAuth();
17 | return (
18 |
19 |
27 |
28 |
29 |
30 | These UI components provided by Rapi UI
31 |
32 | Linking.openURL("https://rapi-ui.kikiding.space/")}
37 | />
38 | {
41 | navigation.navigate("SecondScreen");
42 | }}
43 | style={{
44 | marginTop: 10,
45 | }}
46 | />
47 | {
51 | signOut(auth);
52 | }}
53 | style={{
54 | marginTop: 10,
55 | }}
56 | />
57 | {
61 | if (isDarkmode) {
62 | setTheme("light");
63 | } else {
64 | setTheme("dark");
65 | }
66 | }}
67 | style={{
68 | marginTop: 10,
69 | }}
70 | />
71 |
72 |
73 |
74 |
75 | );
76 | }
77 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs-auth-flow/src/screens/Profile.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 | import { Layout, Text } from 'react-native-rapi-ui';
4 |
5 | export default function ({ navigation }) {
6 | return (
7 |
8 |
15 | This is the Profile tab
16 |
17 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs-auth-flow/src/screens/SecondScreen.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View } from "react-native";
3 | import {
4 | Layout,
5 | TopNav,
6 | Text,
7 | themeColor,
8 | useTheme,
9 | } from "react-native-rapi-ui";
10 | import { Ionicons } from "@expo/vector-icons";
11 |
12 | export default function ({ navigation }) {
13 | const { isDarkmode } = useTheme();
14 | return (
15 |
16 |
24 | }
25 | leftAction={() => navigation.goBack()}
26 | />
27 |
34 | {/* This text using ubuntu font */}
35 | This is the second screen
36 |
37 |
38 | );
39 | }
40 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs-auth-flow/src/screens/auth/ForgetPassword.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import {
3 | ScrollView,
4 | TouchableOpacity,
5 | View,
6 | KeyboardAvoidingView,
7 | Image,
8 | } from "react-native";
9 | import { getAuth, sendPasswordResetEmail } from "firebase/auth";
10 | import {
11 | Layout,
12 | Text,
13 | TextInput,
14 | Button,
15 | useTheme,
16 | themeColor,
17 | } from "react-native-rapi-ui";
18 |
19 | export default function ({ navigation }) {
20 | const { isDarkmode, setTheme } = useTheme();
21 | const auth = getAuth();
22 | const [email, setEmail] = useState("");
23 | const [loading, setLoading] = useState(false);
24 |
25 | async function forget() {
26 | setLoading(true);
27 | await sendPasswordResetEmail(auth, email)
28 | .then(function () {
29 | setLoading(false);
30 | navigation.navigate("Login");
31 | alert("Your password reset has been sent to your email");
32 | })
33 | .catch(function (error) {
34 | setLoading(false);
35 | alert(error);
36 | });
37 | }
38 | return (
39 |
40 |
41 |
46 |
54 |
62 |
63 |
71 |
79 | Forget Password
80 |
81 | Email
82 | setEmail(text)}
91 | />
92 | {
95 | forget();
96 | }}
97 | style={{
98 | marginTop: 20,
99 | }}
100 | disabled={loading}
101 | />
102 |
103 |
111 | Already have an account?
112 | {
114 | navigation.navigate("Login");
115 | }}
116 | >
117 |
124 | Login here
125 |
126 |
127 |
128 |
136 | {
138 | isDarkmode ? setTheme("light") : setTheme("dark");
139 | }}
140 | >
141 |
148 | {isDarkmode ? "☀️ light theme" : "🌑 dark theme"}
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 | );
157 | }
158 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs-auth-flow/src/screens/auth/Login.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import {
3 | ScrollView,
4 | TouchableOpacity,
5 | View,
6 | KeyboardAvoidingView,
7 | Image,
8 | } from "react-native";
9 | import { getAuth, signInWithEmailAndPassword } from "firebase/auth";
10 | import {
11 | Layout,
12 | Text,
13 | TextInput,
14 | Button,
15 | useTheme,
16 | themeColor,
17 | } from "react-native-rapi-ui";
18 |
19 | export default function ({ navigation }) {
20 | const { isDarkmode, setTheme } = useTheme();
21 | const auth = getAuth();
22 | const [email, setEmail] = useState("");
23 | const [password, setPassword] = useState("");
24 | const [loading, setLoading] = useState(false);
25 |
26 | async function login() {
27 | setLoading(true);
28 | await signInWithEmailAndPassword(auth, email, password).catch(function (
29 | error
30 | ) {
31 | // Handle Errors here.
32 | var errorCode = error.code;
33 | var errorMessage = error.message;
34 | // ...
35 | setLoading(false);
36 | alert(errorMessage);
37 | });
38 | }
39 |
40 | return (
41 |
42 |
43 |
48 |
56 |
64 |
65 |
73 |
81 | Login
82 |
83 | Email
84 | setEmail(text)}
93 | />
94 |
95 | Password
96 | setPassword(text)}
105 | />
106 | {
109 | login();
110 | }}
111 | style={{
112 | marginTop: 20,
113 | }}
114 | disabled={loading}
115 | />
116 |
117 |
125 | Don't have an account?
126 | {
128 | navigation.navigate("Register");
129 | }}
130 | >
131 |
138 | Register here
139 |
140 |
141 |
142 |
150 | {
152 | navigation.navigate("ForgetPassword");
153 | }}
154 | >
155 |
156 | Forget password
157 |
158 |
159 |
160 |
168 | {
170 | isDarkmode ? setTheme("light") : setTheme("dark");
171 | }}
172 | >
173 |
180 | {isDarkmode ? "☀️ light theme" : "🌑 dark theme"}
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 | );
189 | }
190 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs-auth-flow/src/screens/auth/Register.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import {
3 | ScrollView,
4 | TouchableOpacity,
5 | View,
6 | KeyboardAvoidingView,
7 | Image,
8 | } from "react-native";
9 | import { getAuth, createUserWithEmailAndPassword } from "firebase/auth";
10 | import {
11 | Layout,
12 | Text,
13 | TextInput,
14 | Button,
15 | useTheme,
16 | themeColor,
17 | } from "react-native-rapi-ui";
18 |
19 | export default function ({ navigation }) {
20 | const { isDarkmode, setTheme } = useTheme();
21 | const auth = getAuth();
22 | const [email, setEmail] = useState("");
23 | const [password, setPassword] = useState("");
24 | const [loading, setLoading] = useState(false);
25 |
26 | async function register() {
27 | setLoading(true);
28 | await createUserWithEmailAndPassword(auth, email, password).catch(function (
29 | error
30 | ) {
31 | // Handle Errors here.
32 | var errorCode = error.code;
33 | var errorMessage = error.message;
34 | // ...
35 | setLoading(false);
36 | alert(errorMessage);
37 | });
38 | }
39 |
40 | return (
41 |
42 |
43 |
48 |
56 |
64 |
65 |
73 |
81 | Register
82 |
83 | Email
84 | setEmail(text)}
93 | />
94 |
95 | Password
96 | setPassword(text)}
105 | />
106 | {
109 | register();
110 | }}
111 | style={{
112 | marginTop: 20,
113 | }}
114 | disabled={loading}
115 | />
116 |
117 |
125 | Already have an account?
126 | {
128 | navigation.navigate("Login");
129 | }}
130 | >
131 |
138 | Login here
139 |
140 |
141 |
142 |
150 | {
152 | isDarkmode ? setTheme("light") : setTheme("dark");
153 | }}
154 | >
155 |
162 | {isDarkmode ? "☀️ light theme" : "🌑 dark theme"}
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 | );
171 | }
172 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs-auth-flow/src/screens/utils/Loading.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View, ActivityIndicator } from "react-native";
3 | import { Layout, themeColor } from "react-native-rapi-ui";
4 |
5 | export default function ({ navigation }) {
6 | return (
7 |
8 |
15 | {/* This text using ubuntu font */}
16 |
17 |
18 |
19 | );
20 | }
21 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs/.expo-shared/assets.json:
--------------------------------------------------------------------------------
1 | {
2 | "12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true,
3 | "40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true
4 | }
5 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/**/*
2 | .expo/*
3 | npm-debug.*
4 | *.jks
5 | *.p8
6 | *.p12
7 | *.key
8 | *.mobileprovision
9 | *.orig.*
10 | web-build/
11 |
12 | # macOS
13 | .DS_Store
14 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs/App.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import AppNavigator from "./src/navigation/AppNavigator";
3 | import { ThemeProvider } from "react-native-rapi-ui";
4 | export default function App() {
5 | return (
6 |
7 |
8 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs/README.md:
--------------------------------------------------------------------------------
1 | # Template Bottom tabs
2 |
3 | Template starter with React Navigation Bottom Tabs
4 |
5 | # Preview
6 |
7 | 
8 |
9 | # Installation
10 |
11 | 1. Install [node.js](https://nodejs.org/en/)
12 | 2. Install Expo
13 |
14 | ```jsx
15 | npm install --global expo-cli
16 | ```
17 |
18 | 3. Download this repo
19 | 4. Install deps on your template folder
20 |
21 | ```jsx
22 | npm install
23 | ```
24 |
25 | 5. Start the environtment
26 |
27 | ```jsx
28 | expo start
29 | ```
30 |
31 | ### Rapi UI
32 |
33 | 
34 |
35 | These UI components are provided by [Rapi UI](https://rapi-ui.kikiding.space/).
36 | Check the [documentation](https://rapi-ui.kikiding.space/docs/) for usage and more components.
37 |
38 | # File Managements
39 |
40 | These are the folders and the functionality
41 |
42 | ```jsx
43 | /src/assets -> for media such as images, etc
44 | /src/components -> for components
45 | /src/navigation -> for React Navigation
46 | /src/screens -> for Screens
47 | ```
48 |
49 | if you find these useful don't forget to give it a star ⭐ and share it to your friends ❤️
50 |
51 | Reach me on [twitter](https://twitter.com/kikiding/)
52 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "withBottomTabs",
4 | "slug": "withBottomTabs",
5 | "version": "1.0.0",
6 | "orientation": "portrait",
7 | "icon": "./assets/icon.png",
8 | "splash": {
9 | "image": "./assets/splash.png",
10 | "resizeMode": "contain",
11 | "backgroundColor": "#ffffff"
12 | },
13 | "updates": {
14 | "fallbackToCacheTimeout": 0
15 | },
16 | "assetBundlePatterns": [
17 | "**/*"
18 | ],
19 | "ios": {
20 | "supportsTablet": true
21 | },
22 | "web": {
23 | "favicon": "./assets/favicon.png"
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-with-bottom-tabs/assets/favicon.png
--------------------------------------------------------------------------------
/template-with-bottom-tabs/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-with-bottom-tabs/assets/icon.png
--------------------------------------------------------------------------------
/template-with-bottom-tabs/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-with-bottom-tabs/assets/splash.png
--------------------------------------------------------------------------------
/template-with-bottom-tabs/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.cache(true);
3 | return {
4 | presets: ['babel-preset-expo'],
5 | };
6 | };
7 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "node_modules/expo/AppEntry.js",
3 | "scripts": {
4 | "start": "expo start",
5 | "android": "expo start --android",
6 | "ios": "expo start --ios",
7 | "web": "expo start --web",
8 | "eject": "expo eject"
9 | },
10 | "dependencies": {
11 | "@expo/vector-icons": "^12.0.0",
12 | "@react-navigation/bottom-tabs": "^6.0.9",
13 | "@react-navigation/native": "^6.0.6",
14 | "@react-navigation/native-stack": "^6.2.5",
15 | "expo": "~44.0.0",
16 | "expo-asset": "~8.4.5",
17 | "expo-font": "~10.0.4",
18 | "expo-status-bar": "~1.2.0",
19 | "react": "17.0.1",
20 | "react-dom": "17.0.1",
21 | "react-native": "0.64.3",
22 | "react-native-rapi-ui": "^0.2.1",
23 | "react-native-safe-area-context": "3.3.2",
24 | "react-native-screens": "~3.10.1",
25 | "react-native-web": "0.17.1"
26 | },
27 | "devDependencies": {
28 | "@babel/core": "^7.12.9"
29 | },
30 | "private": true
31 | }
32 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs/src/components/utils/TabBarIcon.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { themeColor, useTheme } from "react-native-rapi-ui";
3 | import { Ionicons } from "@expo/vector-icons";
4 |
5 | export default (props) => {
6 | const { isDarkmode } = useTheme();
7 | return (
8 |
20 | );
21 | };
22 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs/src/components/utils/TabBarText.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Text, themeColor, useTheme } from "react-native-rapi-ui";
3 | export default (props) => {
4 | const { isDarkmode } = useTheme();
5 | return (
6 |
18 | {props.title}
19 |
20 | );
21 | };
22 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs/src/navigation/AppNavigator.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { NavigationContainer } from "@react-navigation/native";
3 | import { createNativeStackNavigator } from "@react-navigation/native-stack";
4 | import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
5 |
6 | import { themeColor, useTheme } from "react-native-rapi-ui";
7 | import TabBarIcon from "../components/utils/TabBarIcon";
8 | import TabBarText from "../components/utils/TabBarText";
9 |
10 | import Home from "../screens/Home";
11 | import SecondScreen from "../screens/SecondScreen";
12 | import About from "../screens/About";
13 | import Profile from "../screens/Profile";
14 |
15 | const MainStack = createNativeStackNavigator();
16 | const Main = () => {
17 | return (
18 |
23 |
24 |
25 |
26 | );
27 | };
28 |
29 | const Tabs = createBottomTabNavigator();
30 | const MainTabs = () => {
31 | const { isDarkmode } = useTheme();
32 | return (
33 |
42 | {/* these icons using Ionicons */}
43 | (
48 |
49 | ),
50 | tabBarIcon: ({ focused }) => (
51 |
52 | ),
53 | }}
54 | />
55 | (
60 |
61 | ),
62 | tabBarIcon: ({ focused }) => (
63 |
64 | ),
65 | }}
66 | />
67 | (
72 |
73 | ),
74 | tabBarIcon: ({ focused }) => (
75 |
76 | ),
77 | }}
78 | />
79 |
80 | );
81 | };
82 |
83 | export default () => {
84 | return (
85 |
86 |
87 |
88 | );
89 | };
90 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs/src/screens/About.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 | import { Layout, Text } from 'react-native-rapi-ui';
4 |
5 | export default function ({ navigation }) {
6 | return (
7 |
8 |
15 | This is the About tab
16 |
17 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs/src/screens/Home.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View, Linking } from "react-native";
3 | import {
4 | Layout,
5 | Button,
6 | Text,
7 | Section,
8 | SectionContent,
9 | useTheme,
10 | } from "react-native-rapi-ui";
11 |
12 | export default function ({ navigation }) {
13 | const { isDarkmode, setTheme } = useTheme();
14 | return (
15 |
16 |
24 |
25 |
26 |
27 | These UI components provided by Rapi UI
28 |
29 | Linking.openURL("https://rapi-ui.kikiding.space/")}
34 | />
35 | {
38 | navigation.navigate("SecondScreen");
39 | }}
40 | style={{
41 | marginTop: 10,
42 | }}
43 | />
44 |
45 | {
49 | if (isDarkmode) {
50 | setTheme("light");
51 | } else {
52 | setTheme("dark");
53 | }
54 | }}
55 | style={{
56 | marginTop: 10,
57 | }}
58 | />
59 |
60 |
61 |
62 |
63 | );
64 | }
65 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs/src/screens/Profile.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 | import { Layout, Text } from 'react-native-rapi-ui';
4 |
5 | export default function ({ navigation }) {
6 | return (
7 |
8 |
15 | This is the Profile tab
16 |
17 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/template-with-bottom-tabs/src/screens/SecondScreen.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View } from "react-native";
3 | import {
4 | Layout,
5 | TopNav,
6 | Text,
7 | themeColor,
8 | useTheme,
9 | } from "react-native-rapi-ui";
10 | import { Ionicons } from "@expo/vector-icons";
11 |
12 | export default function ({ navigation }) {
13 | const { isDarkmode } = useTheme();
14 | return (
15 |
16 |
24 | }
25 | leftAction={() => navigation.goBack()}
26 | />
27 |
34 | {/* This text using ubuntu font */}
35 | This is the second screen
36 |
37 |
38 | );
39 | }
40 |
--------------------------------------------------------------------------------
/template-with-firebase-auth-flow/.expo-shared/assets.json:
--------------------------------------------------------------------------------
1 | {
2 | "12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true,
3 | "40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true
4 | }
5 |
--------------------------------------------------------------------------------
/template-with-firebase-auth-flow/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/**/*
2 | .expo/*
3 | npm-debug.*
4 | *.jks
5 | *.p8
6 | *.p12
7 | *.key
8 | *.mobileprovision
9 | *.orig.*
10 | web-build/
11 |
12 | # macOS
13 | .DS_Store
14 |
--------------------------------------------------------------------------------
/template-with-firebase-auth-flow/App.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import AppNavigator from "./src/navigation/AppNavigator";
3 | import { AuthProvider } from "./src/provider/AuthProvider";
4 | import { ThemeProvider } from "react-native-rapi-ui";
5 | import { LogBox } from "react-native";
6 |
7 | export default function App(props) {
8 | const images = [
9 | require("./assets/icon.png"),
10 | require("./assets/splash.png"),
11 | require("./assets/login.png"),
12 | require("./assets/register.png"),
13 | require("./assets/forget.png"),
14 | ];
15 |
16 | // Ignore firebase v9 AsyncStorage warning
17 | React.useEffect(() => {
18 | LogBox.ignoreLogs([
19 | "AsyncStorage has been extracted from react-native core and will be removed in a future release. It can now be installed and imported from '@react-native-async-storage/async-storage' instead of 'react-native'. See https://github.com/react-native-async-storage/async-storage",
20 | ]);
21 | }, []);
22 |
23 | return (
24 |
25 |
26 |
27 |
28 |
29 | );
30 | }
31 |
--------------------------------------------------------------------------------
/template-with-firebase-auth-flow/README.md:
--------------------------------------------------------------------------------
1 | # Template Firebase auth flow
2 |
3 | Template starter with React Navigation and Firebase auth using React Context
4 |
5 | # Preview
6 |
7 | 
8 |
9 | # Installation
10 |
11 | 1. Install [node.js](https://nodejs.org/en/)
12 | 2. Install Expo
13 |
14 | ```jsx
15 | npm install --global expo-cli
16 | ```
17 |
18 | 3. Download this repo
19 | 4. Install deps on your template folder
20 |
21 | ```jsx
22 | npm install
23 | ```
24 |
25 | 5. Start the environtment
26 |
27 | ```jsx
28 | expo start
29 | ```
30 |
31 | # Auth Flow
32 |
33 | ### Firebase Setup
34 |
35 | - Set up a new firebase project
36 | - Go to Authentication and under Sign-in Method enable Email/Password
37 | - Fill this firebase config to your config inside `./src/navigation/AppNavigator.js`
38 |
39 | ```jsx
40 | // Better put your these secret keys in .env file
41 | const firebaseConfig = {
42 | apiKey: '',
43 | authDomain: '',
44 | databaseURL: '',
45 | projectId: '',
46 | storageBucket: '',
47 | messagingSenderId: '',
48 | appId: '',
49 | };
50 | ```
51 |
52 | ### Prebuilt UI Screens
53 |
54 | There are 3 screens included inside `./src/screens/auth` and one more thing its included with the firebase auth function, so you don't need to create the function. The ilustrations I use [undraw](https://undraw.co/)
55 |
56 | - Login screen `./src/screens/auth/login.tsx`
57 | - Register screen `./src/screens/auth/register.tsx`
58 | - Forget password screen `./src/screens/auth/forget.tsx`
59 |
60 | I personally use these screens on my project [TiktTeng](https://github.com/codingki/TikTeng) in early stages before the redesign, feel free to use these screens ❤️
61 |
62 | ### React Navigation Auth Flow
63 |
64 | The checking logged users process is inside `./src/provider/AuthProvider` I use React Context, you can add more functions like get the data of the user and store it to the context (better static data, ex: uid)
65 |
66 | Inside the navigator `./src/navigation/AppNavigator.js`
67 | There's 2 stack navigator :
68 |
69 | - `` → for not logged in users stack
70 | - `` → for logged in users stack
71 | - `` → when checking if the user is logged in or not loading screen
72 |
73 | ```jsx
74 | export default () => {
75 | const auth = useContext(AuthContext);
76 | const user = auth.user;
77 | return (
78 |
79 | {user == null && }
80 | {user == false && }
81 | {user == true && }
82 |
83 | );
84 | };
85 | ```
86 |
87 | ## Rapi UI
88 |
89 | 
90 |
91 | These UI components are provided by [Rapi UI](https://rapi-ui.kikiding.space/).
92 | Check the [documentation](https://rapi-ui.kikiding.space/docs/) for usage and more components.
93 |
94 | # File Managements
95 |
96 | These are the folders and the functionality
97 |
98 | ```jsx
99 | /src/assets -> for media such as images, etc
100 | /src/components -> for components
101 | /src/navigation -> for React Navigation
102 | /src/provider -> for React Context
103 | /src/screens -> for Screens
104 | ```
105 |
106 | if you find these useful don't forget to give it a star ⭐ and share it to your friends ❤️
107 |
108 | Reach me on [twitter](https://twitter.com/kikiding/)
109 |
--------------------------------------------------------------------------------
/template-with-firebase-auth-flow/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "firebaseAuthFlow",
4 | "slug": "firebaseAuthFlow",
5 | "version": "1.0.0",
6 | "orientation": "portrait",
7 | "icon": "./assets/icon.png",
8 | "splash": {
9 | "image": "./assets/splash.png",
10 | "resizeMode": "contain",
11 | "backgroundColor": "#ffffff"
12 | },
13 | "updates": {
14 | "fallbackToCacheTimeout": 0
15 | },
16 | "assetBundlePatterns": ["**/*"],
17 | "ios": {
18 | "supportsTablet": true
19 | },
20 | "web": {
21 | "favicon": "./assets/favicon.png"
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/template-with-firebase-auth-flow/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-with-firebase-auth-flow/assets/favicon.png
--------------------------------------------------------------------------------
/template-with-firebase-auth-flow/assets/forget.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-with-firebase-auth-flow/assets/forget.png
--------------------------------------------------------------------------------
/template-with-firebase-auth-flow/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-with-firebase-auth-flow/assets/icon.png
--------------------------------------------------------------------------------
/template-with-firebase-auth-flow/assets/login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-with-firebase-auth-flow/assets/login.png
--------------------------------------------------------------------------------
/template-with-firebase-auth-flow/assets/register.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-with-firebase-auth-flow/assets/register.png
--------------------------------------------------------------------------------
/template-with-firebase-auth-flow/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-with-firebase-auth-flow/assets/splash.png
--------------------------------------------------------------------------------
/template-with-firebase-auth-flow/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function (api) {
2 | api.cache(true);
3 | return {
4 | presets: ['babel-preset-expo'],
5 | };
6 | };
7 |
--------------------------------------------------------------------------------
/template-with-firebase-auth-flow/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "node_modules/expo/AppEntry.js",
3 | "scripts": {
4 | "start": "expo start",
5 | "android": "expo start --android",
6 | "ios": "expo start --ios",
7 | "web": "expo start --web",
8 | "eject": "expo eject"
9 | },
10 | "dependencies": {
11 | "@expo/vector-icons": "^12.0.0",
12 | "@react-navigation/native": "^6.0.6",
13 | "@react-navigation/native-stack": "^6.2.5",
14 | "expo": "~44.0.0",
15 | "expo-asset": "~8.4.5",
16 | "expo-font": "~10.0.4",
17 | "expo-status-bar": "~1.2.0",
18 | "firebase": "^9.6.1",
19 | "react": "17.0.1",
20 | "react-dom": "17.0.1",
21 | "react-native": "0.64.3",
22 | "react-native-rapi-ui": "^0.2.1",
23 | "react-native-safe-area-context": "3.3.2",
24 | "react-native-screens": "~3.10.1",
25 | "react-native-web": "0.17.1"
26 | },
27 | "devDependencies": {
28 | "@babel/core": "^7.12.9"
29 | },
30 | "private": true
31 | }
32 |
--------------------------------------------------------------------------------
/template-with-firebase-auth-flow/src/navigation/AppNavigator.js:
--------------------------------------------------------------------------------
1 | import React, { useContext } from "react";
2 | import { initializeApp, getApps } from "firebase/app";
3 | import { NavigationContainer } from "@react-navigation/native";
4 | import { createNativeStackNavigator } from "@react-navigation/native-stack";
5 | import { AuthContext } from "../provider/AuthProvider";
6 |
7 | // Main
8 | import Home from "../screens/Home";
9 | import SecondScreen from "../screens/SecondScreen";
10 |
11 | // Auth screens
12 | import Login from "../screens/auth/Login";
13 | import Register from "../screens/auth/Register";
14 | import ForgetPassword from "../screens/auth/ForgetPassword";
15 |
16 | import Loading from "../screens/utils/Loading";
17 |
18 | // Better put your these secret keys in .env file
19 | const firebaseConfig = {
20 | apiKey: "",
21 | authDomain: "",
22 | databaseURL: "",
23 | projectId: "",
24 | storageBucket: "",
25 | messagingSenderId: "",
26 | appId: "",
27 | };
28 | if (getApps().length === 0) {
29 | initializeApp(firebaseConfig);
30 | }
31 |
32 | const AuthStack = createNativeStackNavigator();
33 |
34 | const Auth = () => {
35 | return (
36 |
41 |
42 |
43 |
44 |
45 | );
46 | };
47 |
48 | const MainStack = createNativeStackNavigator();
49 |
50 | const Main = () => {
51 | return (
52 |
57 |
58 |
59 |
60 | );
61 | };
62 |
63 | export default () => {
64 | const auth = useContext(AuthContext);
65 | const user = auth.user;
66 | return (
67 |
68 | {user == null && }
69 | {user == false && }
70 | {user == true && }
71 |
72 | );
73 | };
74 |
--------------------------------------------------------------------------------
/template-with-firebase-auth-flow/src/provider/AuthProvider.js:
--------------------------------------------------------------------------------
1 | import React, { createContext, useState, useEffect } from "react";
2 | import { getAuth, onAuthStateChanged } from "firebase/auth";
3 |
4 | const AuthContext = createContext();
5 | const AuthProvider = (props) => {
6 | const auth = getAuth();
7 | // user null = loading
8 | const [user, setUser] = useState(null);
9 |
10 | useEffect(() => {
11 | checkLogin();
12 | }, []);
13 |
14 | function checkLogin() {
15 | onAuthStateChanged(auth, (u) => {
16 | if (u) {
17 | setUser(true);
18 | // getUserData();
19 | } else {
20 | setUser(false);
21 | // setUserData(null);
22 | }
23 | });
24 | }
25 |
26 | return (
27 |
32 | {props.children}
33 |
34 | );
35 | };
36 |
37 | export { AuthContext, AuthProvider };
38 |
--------------------------------------------------------------------------------
/template-with-firebase-auth-flow/src/screens/Home.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View, Linking } from "react-native";
3 | import { getAuth, signOut } from "firebase/auth";
4 | import {
5 | Layout,
6 | Button,
7 | Text,
8 | TopNav,
9 | Section,
10 | SectionContent,
11 | useTheme,
12 | themeColor,
13 | } from "react-native-rapi-ui";
14 | import { Ionicons } from "@expo/vector-icons";
15 |
16 | export default function ({ navigation }) {
17 | const { isDarkmode, setTheme } = useTheme();
18 | const auth = getAuth();
19 | return (
20 |
21 |
29 | }
30 | rightAction={() => {
31 | if (isDarkmode) {
32 | setTheme("light");
33 | } else {
34 | setTheme("dark");
35 | }
36 | }}
37 | />
38 |
45 |
46 |
47 |
48 | These UI components provided by Rapi UI
49 |
50 | Linking.openURL("https://rapi-ui.kikiding.space/")}
55 | />
56 | {
59 | navigation.navigate("SecondScreen");
60 | }}
61 | style={{
62 | marginTop: 10,
63 | }}
64 | />
65 | {
69 | signOut(auth);
70 | }}
71 | style={{
72 | marginTop: 10,
73 | }}
74 | />
75 |
76 |
77 |
78 |
79 | );
80 | }
81 |
--------------------------------------------------------------------------------
/template-with-firebase-auth-flow/src/screens/SecondScreen.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View } from "react-native";
3 | import {
4 | Layout,
5 | TopNav,
6 | Text,
7 | themeColor,
8 | useTheme,
9 | } from "react-native-rapi-ui";
10 | import { Ionicons } from "@expo/vector-icons";
11 |
12 | export default function ({ navigation }) {
13 | const { isDarkmode, setTheme } = useTheme();
14 | return (
15 |
16 |
24 | }
25 | leftAction={() => navigation.goBack()}
26 | rightContent={
27 |
32 | }
33 | rightAction={() => {
34 | if (isDarkmode) {
35 | setTheme("light");
36 | } else {
37 | setTheme("dark");
38 | }
39 | }}
40 | />
41 |
48 | {/* This text using ubuntu font */}
49 | This is the second screen
50 |
51 |
52 | );
53 | }
54 |
--------------------------------------------------------------------------------
/template-with-firebase-auth-flow/src/screens/auth/ForgetPassword.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import {
3 | ScrollView,
4 | TouchableOpacity,
5 | View,
6 | KeyboardAvoidingView,
7 | Image,
8 | } from "react-native";
9 | import { getAuth, sendPasswordResetEmail } from "firebase/auth";
10 | import {
11 | Layout,
12 | Text,
13 | TextInput,
14 | Button,
15 | useTheme,
16 | themeColor,
17 | } from "react-native-rapi-ui";
18 |
19 | export default function ({ navigation }) {
20 | const { isDarkmode, setTheme } = useTheme();
21 | const auth = getAuth();
22 | const [email, setEmail] = useState("");
23 | const [loading, setLoading] = useState(false);
24 |
25 | async function forget() {
26 | setLoading(true);
27 | await sendPasswordResetEmail(auth, email)
28 | .then(function () {
29 | setLoading(false);
30 | navigation.navigate("Login");
31 | alert("Your password reset has been sent to your email");
32 | })
33 | .catch(function (error) {
34 | setLoading(false);
35 | alert(error);
36 | });
37 | }
38 | return (
39 |
40 |
41 |
46 |
54 |
62 |
63 |
71 |
79 | Forget Password
80 |
81 | Email
82 | setEmail(text)}
91 | />
92 | {
95 | forget();
96 | }}
97 | style={{
98 | marginTop: 20,
99 | }}
100 | disabled={loading}
101 | />
102 |
103 |
111 | Already have an account?
112 | {
114 | navigation.navigate("Login");
115 | }}
116 | >
117 |
124 | Login here
125 |
126 |
127 |
128 |
136 | {
138 | isDarkmode ? setTheme("light") : setTheme("dark");
139 | }}
140 | >
141 |
148 | {isDarkmode ? "☀️ light theme" : "🌑 dark theme"}
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 | );
157 | }
158 |
--------------------------------------------------------------------------------
/template-with-firebase-auth-flow/src/screens/auth/Login.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import {
3 | ScrollView,
4 | TouchableOpacity,
5 | View,
6 | KeyboardAvoidingView,
7 | Image,
8 | } from "react-native";
9 | import { getAuth, signInWithEmailAndPassword } from "firebase/auth";
10 | import {
11 | Layout,
12 | Text,
13 | TextInput,
14 | Button,
15 | useTheme,
16 | themeColor,
17 | } from "react-native-rapi-ui";
18 |
19 | export default function ({ navigation }) {
20 | const { isDarkmode, setTheme } = useTheme();
21 | const auth = getAuth();
22 | const [email, setEmail] = useState("");
23 | const [password, setPassword] = useState("");
24 | const [loading, setLoading] = useState(false);
25 |
26 | async function login() {
27 | setLoading(true);
28 | await signInWithEmailAndPassword(auth, email, password).catch(function (
29 | error
30 | ) {
31 | // Handle Errors here.
32 | var errorCode = error.code;
33 | var errorMessage = error.message;
34 | // ...
35 | setLoading(false);
36 | alert(errorMessage);
37 | });
38 | }
39 |
40 | return (
41 |
42 |
43 |
48 |
56 |
64 |
65 |
73 |
81 | Login
82 |
83 | Email
84 | setEmail(text)}
93 | />
94 |
95 | Password
96 | setPassword(text)}
105 | />
106 | {
109 | login();
110 | }}
111 | style={{
112 | marginTop: 20,
113 | }}
114 | disabled={loading}
115 | />
116 |
117 |
125 | Don't have an account?
126 | {
128 | navigation.navigate("Register");
129 | }}
130 | >
131 |
138 | Register here
139 |
140 |
141 |
142 |
150 | {
152 | navigation.navigate("ForgetPassword");
153 | }}
154 | >
155 |
156 | Forget password
157 |
158 |
159 |
160 |
168 | {
170 | isDarkmode ? setTheme("light") : setTheme("dark");
171 | }}
172 | >
173 |
180 | {isDarkmode ? "☀️ light theme" : "🌑 dark theme"}
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 | );
189 | }
190 |
--------------------------------------------------------------------------------
/template-with-firebase-auth-flow/src/screens/auth/Register.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import {
3 | ScrollView,
4 | TouchableOpacity,
5 | View,
6 | KeyboardAvoidingView,
7 | Image,
8 | } from "react-native";
9 | import { getAuth, createUserWithEmailAndPassword } from "firebase/auth";
10 | import {
11 | Layout,
12 | Text,
13 | TextInput,
14 | Button,
15 | useTheme,
16 | themeColor,
17 | } from "react-native-rapi-ui";
18 |
19 | export default function ({ navigation }) {
20 | const { isDarkmode, setTheme } = useTheme();
21 | const auth = getAuth();
22 | const [email, setEmail] = useState("");
23 | const [password, setPassword] = useState("");
24 | const [loading, setLoading] = useState(false);
25 |
26 | async function register() {
27 | setLoading(true);
28 | await createUserWithEmailAndPassword(auth, email, password).catch(function (
29 | error
30 | ) {
31 | // Handle Errors here.
32 | var errorCode = error.code;
33 | var errorMessage = error.message;
34 | // ...
35 | setLoading(false);
36 | alert(errorMessage);
37 | });
38 | }
39 |
40 | return (
41 |
42 |
43 |
48 |
56 |
64 |
65 |
73 |
81 | Register
82 |
83 | Email
84 | setEmail(text)}
93 | />
94 |
95 | Password
96 | setPassword(text)}
105 | />
106 | {
109 | register();
110 | }}
111 | style={{
112 | marginTop: 20,
113 | }}
114 | disabled={loading}
115 | />
116 |
117 |
125 | Already have an account?
126 | {
128 | navigation.navigate("Login");
129 | }}
130 | >
131 |
138 | Login here
139 |
140 |
141 |
142 |
150 | {
152 | isDarkmode ? setTheme("light") : setTheme("dark");
153 | }}
154 | >
155 |
162 | {isDarkmode ? "☀️ light theme" : "🌑 dark theme"}
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 | );
171 | }
172 |
--------------------------------------------------------------------------------
/template-with-firebase-auth-flow/src/screens/utils/Loading.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View, ActivityIndicator } from "react-native";
3 | import { Layout, themeColor } from "react-native-rapi-ui";
4 |
5 | export default function ({ navigation }) {
6 | return (
7 |
8 |
15 |
16 |
17 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/template-with-navigation/.expo-shared/assets.json:
--------------------------------------------------------------------------------
1 | {
2 | "12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true,
3 | "40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true
4 | }
5 |
--------------------------------------------------------------------------------
/template-with-navigation/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/**/*
2 | .expo/*
3 | npm-debug.*
4 | *.jks
5 | *.p8
6 | *.p12
7 | *.key
8 | *.mobileprovision
9 | *.orig.*
10 | web-build/
11 |
12 | # macOS
13 | .DS_Store
14 |
--------------------------------------------------------------------------------
/template-with-navigation/App.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import AppNavigator from "./src/navigation/AppNavigator";
3 | import { ThemeProvider } from "react-native-rapi-ui";
4 |
5 | export default function App() {
6 | return (
7 |
8 |
9 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/template-with-navigation/README.md:
--------------------------------------------------------------------------------
1 | # Template Blank with navigation
2 |
3 | Template starter with React Navigation
4 |
5 | # Preview
6 |
7 | 
8 |
9 | # Installation
10 |
11 | 1. Install [node.js](https://nodejs.org/en/)
12 | 2. Install Expo
13 |
14 | ```jsx
15 | npm install --global expo-cli
16 | ```
17 |
18 | 3. Download this repo
19 | 4. Install deps on your template folder
20 |
21 | ```jsx
22 | npm install
23 | ```
24 |
25 | 5. Start the environtment
26 |
27 | ```jsx
28 | expo start
29 | ```
30 |
31 | ## Rapi UI
32 |
33 | 
34 |
35 | These UI components are provided by [Rapi UI](https://rapi-ui.kikiding.space/).
36 | Check the [documentation](https://rapi-ui.kikiding.space/docs/) for usage and more components.
37 |
38 | # File Managements
39 |
40 | These are the folders and the functionality
41 |
42 | ```jsx
43 | /src/assets -> for media such as images, etc
44 | /src/components -> for components
45 | /src/navigation -> for React Navigation
46 | /src/provider -> for React Context
47 | /src/screens -> for Screens
48 | ```
49 |
50 | if you find these useful don't forget to give it a star ⭐ and share it to your friends ❤️
51 |
52 | Reach me on [twitter](https://twitter.com/kikiding/)
53 |
--------------------------------------------------------------------------------
/template-with-navigation/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "withNavigation",
4 | "slug": "withNavigation",
5 | "version": "1.0.0",
6 | "orientation": "portrait",
7 | "icon": "./assets/icon.png",
8 | "splash": {
9 | "image": "./assets/splash.png",
10 | "resizeMode": "contain",
11 | "backgroundColor": "#ffffff"
12 | },
13 | "updates": {
14 | "fallbackToCacheTimeout": 0
15 | },
16 | "assetBundlePatterns": [
17 | "**/*"
18 | ],
19 | "ios": {
20 | "supportsTablet": true
21 | },
22 | "web": {
23 | "favicon": "./assets/favicon.png"
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/template-with-navigation/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-with-navigation/assets/favicon.png
--------------------------------------------------------------------------------
/template-with-navigation/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-with-navigation/assets/icon.png
--------------------------------------------------------------------------------
/template-with-navigation/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingki/react-native-expo-template/8c2ec7b27005f6bfea818b29c0614159f638f96e/template-with-navigation/assets/splash.png
--------------------------------------------------------------------------------
/template-with-navigation/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.cache(true);
3 | return {
4 | presets: ['babel-preset-expo'],
5 | };
6 | };
7 |
--------------------------------------------------------------------------------
/template-with-navigation/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "node_modules/expo/AppEntry.js",
3 | "scripts": {
4 | "start": "expo start",
5 | "android": "expo start --android",
6 | "ios": "expo start --ios",
7 | "web": "expo start --web",
8 | "eject": "expo eject"
9 | },
10 | "dependencies": {
11 | "@expo/vector-icons": "^12.0.0",
12 | "@react-navigation/native": "^6.0.6",
13 | "@react-navigation/native-stack": "^6.2.5",
14 | "expo": "~44.0.0",
15 | "expo-asset": "~8.4.5",
16 | "expo-font": "~10.0.4",
17 | "expo-status-bar": "~1.2.0",
18 | "react": "17.0.1",
19 | "react-dom": "17.0.1",
20 | "react-native": "0.64.3",
21 | "react-native-rapi-ui": "^0.2.1",
22 | "react-native-web": "0.17.1",
23 | "react-native-safe-area-context": "3.3.2",
24 | "react-native-screens": "~3.10.1"
25 | },
26 | "devDependencies": {
27 | "@babel/core": "^7.12.9"
28 | },
29 | "private": true
30 | }
31 |
--------------------------------------------------------------------------------
/template-with-navigation/src/navigation/AppNavigator.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { NavigationContainer } from "@react-navigation/native";
3 | import { createNativeStackNavigator } from "@react-navigation/native-stack";
4 |
5 | import Home from "../screens/Home";
6 | import SecondScreen from "../screens/SecondScreen";
7 |
8 | const MainStack = createNativeStackNavigator();
9 |
10 | const Main = () => {
11 | return (
12 |
17 |
18 |
19 |
20 | );
21 | };
22 |
23 | export default () => {
24 | return (
25 |
26 |
27 |
28 | );
29 | };
30 |
--------------------------------------------------------------------------------
/template-with-navigation/src/screens/Home.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View, Linking } from "react-native";
3 | import {
4 | Layout,
5 | TopNav,
6 | Text,
7 | Button,
8 | Section,
9 | SectionContent,
10 | useTheme,
11 | themeColor,
12 | } from "react-native-rapi-ui";
13 | import { Ionicons } from "@expo/vector-icons";
14 |
15 | export default function ({ navigation }) {
16 | const { isDarkmode, setTheme } = useTheme();
17 | return (
18 |
19 |
27 | }
28 | rightAction={() => {
29 | if (isDarkmode) {
30 | setTheme("light");
31 | } else {
32 | setTheme("dark");
33 | }
34 | }}
35 | />
36 |
43 |
44 |
45 |
46 | These UI components provided by Rapi UI
47 |
48 | Linking.openURL("https://rapi-ui.kikiding.space/")}
53 | />
54 | {
57 | navigation.navigate("SecondScreen");
58 | }}
59 | style={{
60 | marginTop: 10,
61 | }}
62 | />
63 |
64 |
65 |
66 |
67 | );
68 | }
69 |
--------------------------------------------------------------------------------
/template-with-navigation/src/screens/SecondScreen.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View } from "react-native";
3 | import {
4 | Layout,
5 | TopNav,
6 | Text,
7 | themeColor,
8 | useTheme,
9 | } from "react-native-rapi-ui";
10 | import { Ionicons } from "@expo/vector-icons";
11 |
12 | export default function ({ navigation }) {
13 | const { isDarkmode, setTheme } = useTheme();
14 | return (
15 |
16 |
24 | }
25 | leftAction={() => navigation.goBack()}
26 | rightContent={
27 |
32 | }
33 | rightAction={() => {
34 | if (isDarkmode) {
35 | setTheme("light");
36 | } else {
37 | setTheme("dark");
38 | }
39 | }}
40 | />
41 |
42 |
49 | {/* This text using ubuntu font */}
50 | This is the second screen
51 |
52 |
53 | );
54 | }
55 |
--------------------------------------------------------------------------------