Skip to content

Commit 5455712

Browse files
committed
feat(onboarding): adds onboarding screen and xstate machine
1 parent f79aeb0 commit 5455712

16 files changed

+265
-12
lines changed

App.tsx

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1+
import 'react-native-gesture-handler';
12
import { Router } from "./src/router";
3+
import { MachinesProvider } from './src/context'
4+
import { StatusBar } from 'react-native';
25

36
export default function App() {
47
return (
5-
<Router />
8+
<MachinesProvider>
9+
<StatusBar translucent barStyle={'default'} />
10+
<Router />
11+
</MachinesProvider>
612
)
713
}

package.json

+6-1
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,19 @@
1616
"@react-navigation/native": "^6.1.9",
1717
"@react-navigation/stack": "^6.3.20",
1818
"@xstate/react": "^3.2.2",
19+
"formik": "^2.4.5",
1920
"nativewind": "^2.0.11",
2021
"react": "18.2.0",
2122
"react-native": "0.72.6",
2223
"react-native-gesture-handler": "^2.13.4",
2324
"react-native-reanimated": "^3.5.4",
2425
"react-native-safe-area-context": "^4.7.4",
2526
"react-native-screens": "^3.27.0",
26-
"xstate": "^4.38.3"
27+
"xstate": "^4.38.3",
28+
"xstate-logger": "^0.0.3",
29+
"yup": "^1.3.2",
30+
"zod": "^3.22.4",
31+
"zod-formik-adapter": "^1.2.0"
2732
},
2833
"devDependencies": {
2934
"@babel/core": "^7.20.0",

pnpm-lock.yaml

+103
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/context/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './machines.context'

src/context/machines.context.tsx

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { createContext, useContext } from "react";
2+
import { InterpreterFrom } from 'xstate';
3+
import { userMachine } from '../machines'
4+
import { useInterpret } from "@xstate/react";
5+
import { xstateLogger} from 'xstate-logger'
6+
import { any } from "zod";
7+
8+
export const MachinesContext = createContext({} as {
9+
user: InterpreterFrom<typeof userMachine>
10+
})
11+
12+
export function MachinesProvider({ children }: { children: React.ReactNode }) {
13+
const user = useInterpret(userMachine).start().onTransition(state => xstateLogger(state as any));
14+
return (
15+
<MachinesContext.Provider value={{ user }}>
16+
{children}
17+
</MachinesContext.Provider>
18+
)
19+
}

src/hooks/globalMachines.hook.ts

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { useContext } from 'react'
2+
import { MachinesContext } from '../context'
3+
4+
export function useGlobalMachines() {
5+
const machines = useContext(MachinesContext);
6+
7+
return machines;
8+
}

src/hooks/index.ts

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from './user.hook';
2+
export * from './globalMachines.hook'
3+
export * from './router.hook'

src/hooks/router.hook.ts

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { NavigationProp, useNavigation } from "@react-navigation/native";
2+
import { RootStackParamList } from "../types";
3+
4+
export function useRouter() {
5+
return useNavigation<NavigationProp<RootStackParamList>>();
6+
}

src/hooks/user.hook.ts

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { useSelector } from "@xstate/react";
2+
import { useGlobalMachines } from "./globalMachines.hook";
3+
4+
export function useUser() {
5+
const { user } = useGlobalMachines();
6+
7+
const isLoading = useSelector(user, state => state.matches("loading"));
8+
const userData = useSelector(user, state => state.context.user);
9+
10+
function logout() {
11+
user.send("LOGOUT");
12+
}
13+
14+
function onboard(name: string) {
15+
user.send({
16+
type: "ONBOARD",
17+
data: {
18+
name
19+
}
20+
});
21+
}
22+
23+
return {
24+
userData,
25+
isLoading,
26+
handlers: {
27+
logout,
28+
onboard
29+
},
30+
};
31+
}

src/machines/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './user.machine'

src/machines/user.machine.ts

+11-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import AsyncStorage from "@react-native-async-storage/async-storage";
2-
import { assign, createMachine } from "xstate";
2+
import { assign, createMachine, InterpreterFrom } from "xstate";
33

44
type UserMachineEvents = {
55
type: "LOGOUT"
@@ -37,12 +37,14 @@ export const userMachine = createMachine({
3737
context: {
3838
user: null,
3939
},
40+
predictableActionArguments: true,
4041
schema: {
4142
context: {} as UserMachineContext,
4243
events: {} as UserMachineEvents,
4344
services: {} as UserMachienServices
4445
},
4546
id: "user",
47+
initial: "loading",
4648
states: {
4749
loading: {
4850
invoke: {
@@ -66,7 +68,8 @@ export const userMachine = createMachine({
6668
invoke: {
6769
src: "removeUser",
6870
onDone: {
69-
target: "noUser"
71+
target: "noUser",
72+
actions: ["removeUser"]
7073
}
7174
}
7275
},
@@ -89,7 +92,10 @@ export const userMachine = createMachine({
8992
actions: {
9093
assignUser: assign({
9194
user: (_, event) => event.data
92-
})
95+
}),
96+
removeUser: assign({
97+
user: null
98+
}),
9399
},
94100
services: {
95101
removeUser: async () => {
@@ -101,6 +107,8 @@ export const userMachine = createMachine({
101107
},
102108
getUser: async () => {
103109
const user = await AsyncStorage.getItem("user")
110+
console.log('user', user);
111+
104112
if (!user) {
105113
throw new Error("No user")
106114
}

src/router.tsx

+16-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,27 @@
11
import { NavigationContainer } from "@react-navigation/native";
22
import { createStackNavigator } from "@react-navigation/stack";
33
import { Welcome, Todos } from "./screens";
4+
import { useUser } from "./hooks";
5+
import { ActivityIndicator, View } from "react-native";
6+
import { RootStackParamList } from "./types";
47

5-
const Stack = createStackNavigator();
8+
const Stack = createStackNavigator<RootStackParamList>();
69

710
export function Router() {
11+
const { isLoading, userData } = useUser();
12+
13+
if (isLoading) {
14+
return (
15+
<View className="flex flex-1 items-center justify-center">
16+
<ActivityIndicator />
17+
</View>
18+
)
19+
}
20+
21+
822
return (
923
<NavigationContainer>
10-
<Stack.Navigator screenOptions={{
24+
<Stack.Navigator initialRouteName={!userData ? 'Welcome' : 'Todos'} screenOptions={{
1125
headerShown: false
1226
}}>
1327
<Stack.Screen name="Welcome" component={Welcome} />

0 commit comments

Comments
 (0)