about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--package.json1
-rw-r--r--src/routes/index.tsx59
-rw-r--r--src/routes/types.ts2
-rw-r--r--src/screens/Home.tsx5
-rw-r--r--src/screens/Login.tsx17
-rw-r--r--src/screens/Signup.tsx23
-rw-r--r--src/state/index.ts8
-rw-r--r--src/state/models/root-store.ts11
-rw-r--r--src/state/models/session.ts21
-rw-r--r--yarn.lock5
11 files changed, 129 insertions, 25 deletions
diff --git a/README.md b/README.md
index 159d374ad..9627e39ed 100644
--- a/README.md
+++ b/README.md
@@ -24,8 +24,6 @@ Uses:
 
 ## TODOs
 
-- Navigation
-  - Auth / Unauthed
 - Web
   - Desktop vs mobile styling
 - API
diff --git a/package.json b/package.json
index 764c79b44..763f6d89e 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,7 @@
     "@react-navigation/native-stack": "^6.6.2",
     "@react-navigation/stack": "^6.2.1",
     "mobx": "^6.6.0",
+    "mobx-react-lite": "^3.4.0",
     "mobx-state-tree": "^5.1.5",
     "react": "17.0.2",
     "react-dom": "17.0.2",
diff --git a/src/routes/index.tsx b/src/routes/index.tsx
index 9ea1766f5..fa035e3c9 100644
--- a/src/routes/index.tsx
+++ b/src/routes/index.tsx
@@ -8,12 +8,16 @@ import {
 } from '@react-navigation/native'
 import {createNativeStackNavigator} from '@react-navigation/native-stack'
 import {createBottomTabNavigator} from '@react-navigation/bottom-tabs'
+import {observer} from 'mobx-react-lite'
 import type {RootStackParamList} from './types'
+import {useStores} from '../state'
 import {Home} from '../screens/Home'
 import {Search} from '../screens/Search'
 import {Notifications} from '../screens/Notifications'
 import {Menu} from '../screens/Menu'
 import {Profile} from '../screens/Profile'
+import {Login} from '../screens/Login'
+import {Signup} from '../screens/Signup'
 import {NotFound} from '../screens/NotFound'
 
 const linking: LinkingOptions<RootStackParamList> = {
@@ -30,6 +34,8 @@ const linking: LinkingOptions<RootStackParamList> = {
           Menu: 'menu',
         },
       },
+      Login: 'login',
+      Signup: 'signup',
       Profile: 'profile/:name',
       NotFound: '*',
     },
@@ -50,23 +56,38 @@ const tabBarScreenOptions = ({
   },
 })
 
-const Primary = () => (
-  <PrimaryTab.Navigator
-    screenOptions={tabBarScreenOptions}
-    initialRouteName="Home">
-    <PrimaryTab.Screen name="Home" component={Home} />
-    <PrimaryTab.Screen name="Search" component={Search} />
-    <PrimaryTab.Screen name="Notifications" component={Notifications} />
-    <PrimaryTab.Screen name="Menu" component={Menu} />
-  </PrimaryTab.Navigator>
-)
+function Primary() {
+  return (
+    <PrimaryTab.Navigator
+      screenOptions={tabBarScreenOptions}
+      initialRouteName="Home">
+      <PrimaryTab.Screen name="Home" component={Home} />
+      <PrimaryTab.Screen name="Search" component={Search} />
+      <PrimaryTab.Screen name="Notifications" component={Notifications} />
+      <PrimaryTab.Screen name="Menu" component={Menu} />
+    </PrimaryTab.Navigator>
+  )
+}
 
-export const Root = () => (
-  <NavigationContainer linking={linking} fallback={<Text>Loading...</Text>}>
-    <RootStack.Navigator initialRouteName="Primary">
-      <RootStack.Screen name="Primary" component={Primary} />
-      <RootStack.Screen name="Profile" component={Profile} />
-      <RootStack.Screen name="NotFound" component={NotFound} />
-    </RootStack.Navigator>
-  </NavigationContainer>
-)
+export const Root = observer(() => {
+  const store = useStores()
+  return (
+    <NavigationContainer linking={linking} fallback={<Text>Loading...</Text>}>
+      <RootStack.Navigator
+        initialRouteName={store.session.isAuthed ? 'Primary' : 'Login'}>
+        {store.session.isAuthed ? (
+          <>
+            <RootStack.Screen name="Primary" component={Primary} />
+            <RootStack.Screen name="Profile" component={Profile} />
+            <RootStack.Screen name="NotFound" component={NotFound} />
+          </>
+        ) : (
+          <>
+            <RootStack.Screen name="Login" component={Login} />
+            <RootStack.Screen name="Signup" component={Signup} />
+          </>
+        )}
+      </RootStack.Navigator>
+    </NavigationContainer>
+  )
+})
diff --git a/src/routes/types.ts b/src/routes/types.ts
index 668dc2e2f..88148fd4d 100644
--- a/src/routes/types.ts
+++ b/src/routes/types.ts
@@ -6,6 +6,8 @@ import type {BottomTabScreenProps} from '@react-navigation/bottom-tabs'
 export type RootStackParamList = {
   Primary: undefined
   Profile: {name: string}
+  Login: undefined
+  Signup: undefined
   NotFound: undefined
 }
 export type RootStackScreenProps<T extends keyof RootStackParamList> =
diff --git a/src/screens/Home.tsx b/src/screens/Home.tsx
index f4b8ffb63..a2d013abe 100644
--- a/src/screens/Home.tsx
+++ b/src/screens/Home.tsx
@@ -1,8 +1,10 @@
 import React from 'react'
 import {Text, Button, View, SafeAreaView} from 'react-native'
 import type {PrimaryTabScreenProps} from '../routes/types'
+import {useStores} from '../state'
 
-export const Home = ({navigation}: PrimaryTabScreenProps<'Home'>) => {
+export function Home({navigation}: PrimaryTabScreenProps<'Home'>) {
+  const store = useStores()
   return (
     <SafeAreaView style={{flex: 1}}>
       <View style={{flex: 1}}>
@@ -11,6 +13,7 @@ export const Home = ({navigation}: PrimaryTabScreenProps<'Home'>) => {
           title="Go to Jane's profile"
           onPress={() => navigation.navigate('Profile', {name: 'Jane'})}
         />
+        <Button title="Logout" onPress={() => store.session.setAuthed(false)} />
       </View>
     </SafeAreaView>
   )
diff --git a/src/screens/Login.tsx b/src/screens/Login.tsx
new file mode 100644
index 000000000..77580748c
--- /dev/null
+++ b/src/screens/Login.tsx
@@ -0,0 +1,17 @@
+import React from 'react'
+import {Text, Button, View, SafeAreaView} from 'react-native'
+import type {RootStackScreenProps} from '../routes/types'
+import {useStores} from '../state'
+
+export function Login({navigation}: RootStackScreenProps<'Login'>) {
+  const store = useStores()
+  return (
+    <SafeAreaView style={{flex: 1}}>
+      <View style={{flex: 1}}>
+        <Text>Welcome! Time to sign in</Text>
+        <Button title="Login" onPress={() => store.session.setAuthed(true)} />
+        <Button title="Sign Up" onPress={() => navigation.navigate('Signup')} />
+      </View>
+    </SafeAreaView>
+  )
+}
diff --git a/src/screens/Signup.tsx b/src/screens/Signup.tsx
new file mode 100644
index 000000000..bf7f8f2f8
--- /dev/null
+++ b/src/screens/Signup.tsx
@@ -0,0 +1,23 @@
+import React from 'react'
+import {Text, Button, View, SafeAreaView} from 'react-native'
+import type {RootStackScreenProps} from '../routes/types'
+import {useStores} from '../state'
+
+export function Signup({navigation}: RootStackScreenProps<'Signup'>) {
+  const store = useStores()
+  return (
+    <SafeAreaView style={{flex: 1}}>
+      <View style={{flex: 1}}>
+        <Text>Let's create your account</Text>
+        <Button
+          title="Create new account"
+          onPress={() => store.session.setAuthed(true)}
+        />
+        <Button
+          title="Log in to an existing account"
+          onPress={() => navigation.navigate('Login')}
+        />
+      </View>
+    </SafeAreaView>
+  )
+}
diff --git a/src/state/index.ts b/src/state/index.ts
index 7c97ce294..496f3631d 100644
--- a/src/state/index.ts
+++ b/src/state/index.ts
@@ -1,5 +1,9 @@
 import {onSnapshot} from 'mobx-state-tree'
-import {RootStoreModel, RootStore} from './models/root-store'
+import {
+  RootStoreModel,
+  RootStore,
+  createDefaultRootStore,
+} from './models/root-store'
 import {Environment} from './env'
 import * as storage from './storage'
 
@@ -15,7 +19,7 @@ export async function setupState() {
     rootStore = RootStoreModel.create(data, env)
   } catch (e) {
     console.error('Failed to load state from storage', e)
-    rootStore = RootStoreModel.create({}, env)
+    rootStore = RootStoreModel.create(createDefaultRootStore(), env)
   }
 
   // track changes & save to storage
diff --git a/src/state/models/root-store.ts b/src/state/models/root-store.ts
index 164dfcced..143c59ea1 100644
--- a/src/state/models/root-store.ts
+++ b/src/state/models/root-store.ts
@@ -4,12 +4,21 @@
 
 import {Instance, SnapshotOut, types} from 'mobx-state-tree'
 import {createContext, useContext} from 'react'
+import {SessionModel, createDefaultSession} from './session'
 
-export const RootStoreModel = types.model('RootStore').props({})
+export const RootStoreModel = types.model('RootStore').props({
+  session: SessionModel,
+})
 
 export interface RootStore extends Instance<typeof RootStoreModel> {}
 export interface RootStoreSnapshot extends SnapshotOut<typeof RootStoreModel> {}
 
+export function createDefaultRootStore() {
+  return {
+    session: createDefaultSession(),
+  }
+}
+
 // react context & hook utilities
 const RootStoreContext = createContext<RootStore>({} as RootStore)
 export const RootStoreProvider = RootStoreContext.Provider
diff --git a/src/state/models/session.ts b/src/state/models/session.ts
new file mode 100644
index 000000000..675feb8bc
--- /dev/null
+++ b/src/state/models/session.ts
@@ -0,0 +1,21 @@
+import {Instance, SnapshotOut, types} from 'mobx-state-tree'
+
+export const SessionModel = types
+  .model('Session')
+  .props({
+    isAuthed: types.boolean,
+  })
+  .actions(self => ({
+    setAuthed: (v: boolean) => {
+      self.isAuthed = v
+    },
+  }))
+
+export interface Session extends Instance<typeof SessionModel> {}
+export interface SessionSnapshot extends SnapshotOut<typeof SessionModel> {}
+
+export function createDefaultSession() {
+  return {
+    isAuthed: false,
+  }
+}
diff --git a/yarn.lock b/yarn.lock
index 9202cfe7b..837633c54 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -8564,6 +8564,11 @@ mkdirp@^0.5.1, mkdirp@~0.5.1:
   dependencies:
     minimist "^1.2.6"
 
+mobx-react-lite@^3.4.0:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/mobx-react-lite/-/mobx-react-lite-3.4.0.tgz#d59156a96889cdadad751e5e4dab95f28926dfff"
+  integrity sha512-bRuZp3C0itgLKHu/VNxi66DN/XVkQG7xtoBVWxpvC5FhAqbOCP21+nPhULjnzEqd7xBMybp6KwytdUpZKEgpIQ==
+
 mobx-state-tree@^5.1.5:
   version "5.1.5"
   resolved "https://registry.yarnpkg.com/mobx-state-tree/-/mobx-state-tree-5.1.5.tgz#7344d61072705747abb98d23ad21302e38200105"