Refactor to store

This commit is contained in:
Maarten 2024-08-08 14:05:17 +02:00
parent e3a2251898
commit b619fe34f8
9 changed files with 177 additions and 70 deletions

View file

@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { StyleSheet, ScrollView, SafeAreaView, View, StatusBar, TouchableOpacity, Image } from 'react-native'; import { StyleSheet, ScrollView, SafeAreaView, View, StatusBar } from 'react-native';
// @ts-ignore // @ts-ignore
import CalendarPicker from 'react-native-calendar-picker'; import CalendarPicker from 'react-native-calendar-picker';
import Ionicons from '@expo/vector-icons/Ionicons'; import Ionicons from '@expo/vector-icons/Ionicons';
@ -12,22 +12,33 @@ import { useToken } from '@/context/AppProvider';
import { Request } from '@/services/request'; import { Request } from '@/services/request';
import List from '@/components/List'; import List from '@/components/List';
import { useIsFocused } from '@react-navigation/core'; import { useIsFocused } from '@react-navigation/core';
import { useSelector } from 'react-redux';
export default function HomeScreen() { export default function HomeScreen() {
const colorScheme = useColorScheme() ?? 'light'; const colorScheme = useColorScheme() ?? 'light';
const isFocused = useIsFocused(); const isFocused = useIsFocused();
const session = useSelector((state: any) => state.data.session);
const reloadCalendar = useSelector((state: any) => state.data.reloadCalendar);
const { token, isLoading } = useToken(); const { token, isLoading } = useToken();
const [ name, setName ] = useState( ' ' ); // Default empty space to prevent layout shifting const [ name, setName ] = useState( ' ' ); // Default empty space to prevent layout shifting
const [ dates, setDates ] = useState<any | null>( [] ); const [ dates, setDates ] = useState<any | null>( [] );
const [ types, setTypes ] = useState<any | null>( [] ); const [ types, setTypes ] = useState<any | null>( [] );
// Load session
useEffect( () => {
setName(session.name);
}, [session, isFocused]);
useEffect( () => { useEffect( () => {
if (token) { if (token) {
loadCalendar();
}
}, [ reloadCalendar, isFocused ] );
// Load calendar data
const loadCalendar = () => {
Request.post( 'calendar', { token: token } ).then( (response) => { Request.post( 'calendar', { token: token } ).then( (response) => {
if (response.success) { if (response.success) {
// Set name
setName( response.name );
// Set dates // Set dates
let calendarDates: any[] = []; let calendarDates: any[] = [];
response.dates.forEach( (date: any) => { response.dates.forEach( (date: any) => {
@ -45,7 +56,6 @@ export default function HomeScreen() {
} }
} ) } )
} }
}, [ isFocused ] );
return ( return (
<SafeAreaView style={{ flex: 1, backgroundColor: Colors[ colorScheme ].background, }}> <SafeAreaView style={{ flex: 1, backgroundColor: Colors[ colorScheme ].background, }}>

View file

@ -10,13 +10,13 @@ import { Colors } from '@/constants/Colors';
import { useColorScheme } from '@/hooks/useColorScheme'; import { useColorScheme } from '@/hooks/useColorScheme';
import List from '@/components/List'; import List from '@/components/List';
import { Request } from '@/services/request'; import { Request } from '@/services/request';
import { useToken } from '@/context/AppProvider';
import { useIsFocused } from '@react-navigation/core'; import { useIsFocused } from '@react-navigation/core';
import { useSelector } from 'react-redux';
export default function MapScreen() { export default function MapScreen() {
const colorScheme = useColorScheme() ?? 'light'; const colorScheme = useColorScheme() ?? 'light';
const { token, isLoading } = useToken();
const isFocused = useIsFocused(); const isFocused = useIsFocused();
const session = useSelector((state: any) => state.data.session);
const [ types, setTypes ] = useState<any>( [] ); const [ types, setTypes ] = useState<any>( [] );
const [ coordinates, setCoordinates ] = useState<any>( [] ); const [ coordinates, setCoordinates ] = useState<any>( [] );
@ -24,17 +24,8 @@ export default function MapScreen() {
// Load session // Load session
useEffect( () => { useEffect( () => {
if (token) {
Request.post( 'sessions/get', { token: token } ).then( (response) => {
console.log('session', response);
if (response.success) {
const { session } = response;
setCoordinates([session.coordinates.longitude, session.coordinates.latitude]); setCoordinates([session.coordinates.longitude, session.coordinates.latitude]);
} }, [session, isFocused]);
} )
}
}, [isFocused]);
// Load markers and types // Load markers and types
useEffect( () => { useEffect( () => {

View file

@ -10,6 +10,7 @@ import {
} from 'react-native'; } from 'react-native';
import { useRouter } from 'expo-router'; import { useRouter } from 'expo-router';
import Ionicons from '@expo/vector-icons/Ionicons'; import Ionicons from '@expo/vector-icons/Ionicons';
import { useSelector } from 'react-redux';
import { ThemedText } from '@/components/ThemedText'; import { ThemedText } from '@/components/ThemedText';
import { ThemedView } from '@/components/ThemedView'; import { ThemedView } from '@/components/ThemedView';
@ -19,10 +20,13 @@ import { useToken } from '@/context/AppProvider';
import { Message } from '@/services/message'; import { Message } from '@/services/message';
import { Request } from '@/services/request'; import { Request } from '@/services/request';
import CustomModal from '@/components/EditModal'; import CustomModal from '@/components/EditModal';
import { store } from '@/store/store';
import { setSession, setReloadCalendar } from '@/store/dataStore';
export default function SettingsScreen() { export default function SettingsScreen() {
const colorScheme = useColorScheme() ?? 'light'; const colorScheme = useColorScheme() ?? 'light';
const { token, isLoading } = useToken(); const { token, isLoading } = useToken();
const session = useSelector((state: any) => state.data.session);
const router = useRouter(); const router = useRouter();
// Name // Name
@ -37,22 +41,13 @@ export default function SettingsScreen() {
const [ addressModalVisible, setAddressModalVisible ] = useState( false ); const [ addressModalVisible, setAddressModalVisible ] = useState( false );
useEffect( () => { useEffect( () => {
// Load current session
if (token) {
Request.post( 'sessions/get', { token: token } ).then( (response) => {
if (response.success) {
const { session } = response;
setSessionData( session ); setSessionData( session );
} }, [session] );
} )
}
}, [] );
// Set session data in view // Set session data in view
const setSessionData = (session: any) => { const setSessionData = (session: any) => {
// Name // Name
setName( session.name ) setName( session.name );
// Address // Address
setZipcode( session.address.zipcode ); setZipcode( session.address.zipcode );
@ -61,7 +56,7 @@ export default function SettingsScreen() {
setCity( session.address.city ); setCity( session.address.city );
} }
// Handle // Handle save settings
const handleSave = (inputValues: Record<string, string>) => { const handleSave = (inputValues: Record<string, string>) => {
let postData: any = { token: token }; let postData: any = { token: token };
@ -69,21 +64,27 @@ export default function SettingsScreen() {
postData[ 'name' ] = inputValues.name; postData[ 'name' ] = inputValues.name;
} }
let addressChanged = false;
if (inputValues.zipcode) { if (inputValues.zipcode) {
postData[ 'zipcode' ] = inputValues.zipcode; postData[ 'zipcode' ] = inputValues.zipcode;
addressChanged = true;
} }
if (inputValues.houseNumber) { if (inputValues.houseNumber) {
postData[ 'houseNumber' ] = inputValues.houseNumber; postData[ 'houseNumber' ] = inputValues.houseNumber;
addressChanged = true;
} }
Request.post( 'sessions/update', postData ) Request.post( 'sessions/update', postData )
.then( (response) => { .then( (response) => {
console.log( 'save', response );
if (response.success) { if (response.success) {
setSessionData( response.session ); setSessionData( response.session );
// Save to store
store.dispatch(setSession(response.session))
store.dispatch(setReloadCalendar(addressChanged))
Message.success( 'Opgeslagen!' ) Message.success( 'Opgeslagen!' )
} else { } else {
Message.error( response.message ); Message.error( response.message );
@ -91,6 +92,7 @@ export default function SettingsScreen() {
} ); } );
}; };
// Remove session data and logout
const logout = () => { const logout = () => {
Alert.alert( 'Uitloggen', 'Weet je het zeker?', [ Alert.alert( 'Uitloggen', 'Weet je het zeker?', [
{ {

View file

@ -1,17 +1,18 @@
import { useFonts } from 'expo-font'; import { useFonts } from 'expo-font';
import { Slot, Stack } from 'expo-router'; import { Slot, SplashScreen, Stack } from 'expo-router';
import * as SplashScreen from 'expo-splash-screen'; import { Provider } from 'react-redux';
import { useEffect } from 'react'; import { useEffect } from 'react';
import 'react-native-reanimated'; import 'react-native-reanimated';
import { AppProvider } from '@/context/AppProvider';
import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native'; import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native';
import Toast from 'react-native-toast-message'; import Toast from 'react-native-toast-message';
import { AutocompleteDropdownContextProvider } from 'react-native-autocomplete-dropdown'; import { AutocompleteDropdownContextProvider } from 'react-native-autocomplete-dropdown';
import { AppProvider } from '@/context/AppProvider';
import { useColorScheme } from '@/hooks/useColorScheme'; import { useColorScheme } from '@/hooks/useColorScheme';
import { store } from '@/store/store';
// Prevent the splash screen from auto-hiding before asset loading is complete. // Prevent the splash screen from auto-hiding before asset loading is complete.
// SplashScreen.preventAutoHideAsync(); SplashScreen.preventAutoHideAsync();
export default function RootLayout() { export default function RootLayout() {
const colorScheme = useColorScheme(); const colorScheme = useColorScheme();
@ -22,7 +23,7 @@ export default function RootLayout() {
useEffect( () => { useEffect( () => {
if (loaded) { if (loaded) {
// SplashScreen.hideAsync(); SplashScreen.hideAsync();
} }
}, [ loaded ] ); }, [ loaded ] );
@ -31,6 +32,7 @@ export default function RootLayout() {
} }
return ( return (
<Provider store={store}>
<AppProvider> <AppProvider>
<AutocompleteDropdownContextProvider> <AutocompleteDropdownContextProvider>
<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}> <ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
@ -43,5 +45,6 @@ export default function RootLayout() {
</ThemeProvider> </ThemeProvider>
</AutocompleteDropdownContextProvider> </AutocompleteDropdownContextProvider>
</AppProvider> </AppProvider>
</Provider>
); );
} }

View file

@ -5,6 +5,8 @@ import { ThemedText } from '@/components/ThemedText';
import { ThemedView } from '@/components/ThemedView'; import { ThemedView } from '@/components/ThemedView';
import { useToken } from '@/context/AppProvider'; import { useToken } from '@/context/AppProvider';
import { Request } from '@/services/request'; import { Request } from '@/services/request';
import { store } from '@/store/store';
import { setSession } from '@/store/dataStore';
export default function OnboardStartScreen() { export default function OnboardStartScreen() {
@ -21,6 +23,9 @@ export default function OnboardStartScreen() {
const fetchData = async () => { const fetchData = async () => {
const response = await Request.post( 'sessions/get', { token: token } ); const response = await Request.post( 'sessions/get', { token: token } );
if (response.success) { if (response.success) {
// Save to store
store.dispatch(setSession(response.session))
// @ts-ignore // @ts-ignore
router.replace( '/(tabs)' ); router.replace( '/(tabs)' );
} else { } else {

View file

@ -18,6 +18,7 @@
"@react-native-async-storage/async-storage": "1.23.1", "@react-native-async-storage/async-storage": "1.23.1",
"@react-native-community/cli-platform-ios": "^14.0.0", "@react-native-community/cli-platform-ios": "^14.0.0",
"@react-navigation/native": "^6.0.2", "@react-navigation/native": "^6.0.2",
"@reduxjs/toolkit": "^2.2.7",
"@rnmapbox/maps": "^10.1.28", "@rnmapbox/maps": "^10.1.28",
"@uiw/react-color-circle": "^2.3.0", "@uiw/react-color-circle": "^2.3.0",
"axios": "^1.7.2", "axios": "^1.7.2",
@ -51,7 +52,8 @@
"react-native-svg": "15.2.0", "react-native-svg": "15.2.0",
"react-native-toast-message": "^2.2.0", "react-native-toast-message": "^2.2.0",
"react-native-web": "~0.19.10", "react-native-web": "~0.19.10",
"react-native-webview": "13.8.6" "react-native-webview": "13.8.6",
"react-redux": "^9.1.2"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.20.0", "@babel/core": "^7.20.0",

38
store/dataStore.tsx Normal file
View file

@ -0,0 +1,38 @@
// dataStore.js
import { createSlice } from '@reduxjs/toolkit';
const dataStore = createSlice( {
name: 'data',
initialState: {
session: {
token: '',
name: '',
device: '',
address: {
id: 0,
zipcode: '',
houseNumber: '',
street: '',
city: '',
},
coordinates: {
latitude: '',
longitude: '',
},
},
reloadCalendar: true,
},
reducers: {
setSession: (state, action) => {
state.session = action.payload;
},
setReloadCalendar: (state, action) => {
state.reloadCalendar = action.payload;
},
},
} );
export const { setSession } = dataStore.actions;
export const { setReloadCalendar } = dataStore.actions;
export default dataStore.reducer;

8
store/store.tsx Normal file
View file

@ -0,0 +1,8 @@
import { configureStore } from '@reduxjs/toolkit';
import dataReducer from './dataStore';
export const store = configureStore({
reducer: {
data: dataReducer,
},
});

View file

@ -1983,6 +1983,16 @@
dependencies: dependencies:
nanoid "^3.1.23" nanoid "^3.1.23"
"@reduxjs/toolkit@^2.2.7":
version "2.2.7"
resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-2.2.7.tgz#199e3d10ccb39267cb5aee92c0262fd9da7fdfb2"
integrity sha512-faI3cZbSdFb8yv9dhDTmGwclW0vk0z5o1cia+kf7gCbaCwHI5e+7tP57mJUv22pNcNbeA62GSrPpfrUfdXcQ6g==
dependencies:
immer "^10.0.3"
redux "^5.0.1"
redux-thunk "^3.1.0"
reselect "^5.1.0"
"@remix-run/node@^2.7.2": "@remix-run/node@^2.7.2":
version "2.10.3" version "2.10.3"
resolved "https://registry.npmjs.org/@remix-run/node/-/node-2.10.3.tgz" resolved "https://registry.npmjs.org/@remix-run/node/-/node-2.10.3.tgz"
@ -2408,6 +2418,11 @@
resolved "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.25.tgz" resolved "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.25.tgz"
integrity sha512-XOfUup9r3Y06nFAZh3WvO0rBU4OtlfPB/vgxpjg+NRdGU6CN6djdc6OEiH+PcqHCY6eFLo9Ista73uarf4gnBg== integrity sha512-XOfUup9r3Y06nFAZh3WvO0rBU4OtlfPB/vgxpjg+NRdGU6CN6djdc6OEiH+PcqHCY6eFLo9Ista73uarf4gnBg==
"@types/use-sync-external-store@^0.0.3":
version "0.0.3"
resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43"
integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==
"@types/yargs-parser@*": "@types/yargs-parser@*":
version "21.0.3" version "21.0.3"
resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz" resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz"
@ -4976,6 +4991,11 @@ image-size@^1.0.2:
dependencies: dependencies:
queue "6.0.2" queue "6.0.2"
immer@^10.0.3:
version "10.1.1"
resolved "https://registry.yarnpkg.com/immer/-/immer-10.1.1.tgz#206f344ea372d8ea176891545ee53ccc062db7bc"
integrity sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==
import-fresh@^2.0.0: import-fresh@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz" resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz"
@ -7538,6 +7558,14 @@ react-native@0.74.3:
ws "^6.2.2" ws "^6.2.2"
yargs "^17.6.2" yargs "^17.6.2"
react-redux@^9.1.2:
version "9.1.2"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-9.1.2.tgz#deba38c64c3403e9abd0c3fbeab69ffd9d8a7e4b"
integrity sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==
dependencies:
"@types/use-sync-external-store" "^0.0.3"
use-sync-external-store "^1.0.0"
react-refresh@^0.14.0, react-refresh@^0.14.2: react-refresh@^0.14.0, react-refresh@^0.14.2:
version "0.14.2" version "0.14.2"
resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz" resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz"
@ -7613,6 +7641,16 @@ recyclerlistview@^3.0.0:
prop-types "15.5.8" prop-types "15.5.8"
ts-object-utils "0.0.5" ts-object-utils "0.0.5"
redux-thunk@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-3.1.0.tgz#94aa6e04977c30e14e892eae84978c1af6058ff3"
integrity sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==
redux@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/redux/-/redux-5.0.1.tgz#97fa26881ce5746500125585d5642c77b6e9447b"
integrity sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==
regenerate-unicode-properties@^10.1.0: regenerate-unicode-properties@^10.1.0:
version "10.1.1" version "10.1.1"
resolved "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz" resolved "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz"
@ -7698,6 +7736,11 @@ requires-port@^1.0.0:
resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz"
integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==
reselect@^5.1.0:
version "5.1.1"
resolved "https://registry.yarnpkg.com/reselect/-/reselect-5.1.1.tgz#c766b1eb5d558291e5e550298adb0becc24bb72e"
integrity sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==
resolve-cwd@^3.0.0: resolve-cwd@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz" resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz"
@ -8857,6 +8900,11 @@ use-latest-callback@^0.2.1:
resolved "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.2.1.tgz" resolved "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.2.1.tgz"
integrity sha512-QWlq8Is8BGWBf883QOEQP5HWYX/kMI+JTbJ5rdtvJLmXTIh9XoHIO3PQcmQl8BU44VKxow1kbQUHa6mQSMALDQ== integrity sha512-QWlq8Is8BGWBf883QOEQP5HWYX/kMI+JTbJ5rdtvJLmXTIh9XoHIO3PQcmQl8BU44VKxow1kbQUHa6mQSMALDQ==
use-sync-external-store@^1.0.0:
version "1.2.2"
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz#c3b6390f3a30eba13200d2302dcdf1e7b57b2ef9"
integrity sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==
util-deprecate@^1.0.1, util-deprecate@~1.0.1: util-deprecate@^1.0.1, util-deprecate@~1.0.1:
version "1.0.2" version "1.0.2"
resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"