Add multilanguage support
This commit is contained in:
parent
f8cbcb2908
commit
fc53bb14a0
15 changed files with 489 additions and 92 deletions
|
@ -3,6 +3,8 @@ import { Stack } from 'expo-router';
|
||||||
import { StyleSheet, TextInput, TouchableOpacity } from 'react-native';
|
import { StyleSheet, TextInput, TouchableOpacity } from 'react-native';
|
||||||
import { router } from 'expo-router';
|
import { router } from 'expo-router';
|
||||||
import DeviceInfo from 'react-native-device-info';
|
import DeviceInfo from 'react-native-device-info';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import Ionicons from '@expo/vector-icons/Ionicons';
|
||||||
|
|
||||||
import { ThemedText } from '@/lib/components/ThemedText';
|
import { ThemedText } from '@/lib/components/ThemedText';
|
||||||
import { ThemedView } from '@/lib/components/ThemedView';
|
import { ThemedView } from '@/lib/components/ThemedView';
|
||||||
|
@ -17,13 +19,14 @@ import { setSession } from '@/lib/store/dataStore';
|
||||||
export default function OnboardStartScreen() {
|
export default function OnboardStartScreen() {
|
||||||
const colorScheme = useColorScheme() ?? 'light';
|
const colorScheme = useColorScheme() ?? 'light';
|
||||||
const { setToken } = useToken();
|
const { setToken } = useToken();
|
||||||
|
const { t } = useTranslation();
|
||||||
const [ name, setName ] = React.useState( '' );
|
const [ name, setName ] = React.useState( '' );
|
||||||
const [ zipcode, setZipcode ] = React.useState( '' );
|
const [ zipcode, setZipcode ] = React.useState( '' );
|
||||||
const [ houseNumber, setHouseNumber ] = React.useState( '' );
|
const [ houseNumber, setHouseNumber ] = React.useState( '' );
|
||||||
|
|
||||||
const start = () => {
|
const start = () => {
|
||||||
if (name === '' || zipcode === '' || houseNumber === '') {
|
if (name === '' || zipcode === '' || houseNumber === '') {
|
||||||
Message.error( 'Niet alle gegevens zijn ingevuld!' );
|
Message.error( t( "onboarding.missing-info" ) );
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -47,7 +50,7 @@ export default function OnboardStartScreen() {
|
||||||
setToken( token );
|
setToken( token );
|
||||||
router.replace( "/(tabs)" );
|
router.replace( "/(tabs)" );
|
||||||
|
|
||||||
store.dispatch(setSession(response.session));
|
store.dispatch( setSession( response.session ) );
|
||||||
|
|
||||||
Message.success( response.message );
|
Message.success( response.message );
|
||||||
}
|
}
|
||||||
|
@ -59,32 +62,32 @@ export default function OnboardStartScreen() {
|
||||||
<Stack.Screen options={{ title: 'Welkom' }}/>
|
<Stack.Screen options={{ title: 'Welkom' }}/>
|
||||||
<ThemedView style={styles.container}>
|
<ThemedView style={styles.container}>
|
||||||
<ThemedView style={styles.heading}>
|
<ThemedView style={styles.heading}>
|
||||||
<ThemedText type="title">Welkom bij </ThemedText>
|
<ThemedText type="title">{t( "onboarding.welcome" )} </ThemedText>
|
||||||
<ThemedText type="title" style={{ color: Colors[ colorScheme ].tint }}>Kliko</ThemedText>
|
<ThemedText type="title" style={{ color: Colors[ colorScheme ].tint }}>Kliko</ThemedText>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
|
|
||||||
<ThemedView style={styles.inputContainer}>
|
<ThemedView style={styles.inputContainer}>
|
||||||
<ThemedText>Wat is je naam?</ThemedText>
|
<ThemedText>{t( "onboarding.your-name" )}</ThemedText>
|
||||||
<TextInput
|
<TextInput
|
||||||
style={styles.input}
|
style={styles.input}
|
||||||
onChangeText={setName}
|
onChangeText={setName}
|
||||||
placeholder={'Je naam'}
|
placeholder={t( "onboarding.name" )}
|
||||||
value={name}
|
value={name}
|
||||||
/>
|
/>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
|
|
||||||
<ThemedView style={styles.inputContainer}>
|
<ThemedView style={styles.inputContainer}>
|
||||||
<ThemedText>Wat is je postcode en huisnummer?</ThemedText>
|
<ThemedText>{t( "onboarding.your-address" )}</ThemedText>
|
||||||
<TextInput
|
<TextInput
|
||||||
style={styles.input}
|
style={styles.input}
|
||||||
onChangeText={setZipcode}
|
onChangeText={setZipcode}
|
||||||
placeholder={'Postcode'}
|
placeholder={t( "onboarding.zipcode" )}
|
||||||
value={zipcode}
|
value={zipcode}
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
style={styles.input}
|
style={styles.input}
|
||||||
onChangeText={setHouseNumber}
|
onChangeText={setHouseNumber}
|
||||||
placeholder={'Huisnummer'}
|
placeholder={t( "onboarding.house-number" )}
|
||||||
value={houseNumber}
|
value={houseNumber}
|
||||||
keyboardType="numeric"
|
keyboardType="numeric"
|
||||||
/>
|
/>
|
||||||
|
@ -92,7 +95,10 @@ export default function OnboardStartScreen() {
|
||||||
|
|
||||||
|
|
||||||
<TouchableOpacity style={{ ...styles.button, backgroundColor: Colors[ colorScheme ].tint }} onPress={start}>
|
<TouchableOpacity style={{ ...styles.button, backgroundColor: Colors[ colorScheme ].tint }} onPress={start}>
|
||||||
<ThemedText style={{ color: '#fff' }}>Start</ThemedText>
|
<ThemedText style={{ color: Colors.white }}>
|
||||||
|
{t( "onboarding.start" )}
|
||||||
|
</ThemedText>
|
||||||
|
<Ionicons name={"arrow-forward"} size={18} style={styles.buttonIcon}/>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
</>
|
</>
|
||||||
|
@ -129,5 +135,13 @@ const styles = StyleSheet.create( {
|
||||||
paddingLeft: 40,
|
paddingLeft: 40,
|
||||||
paddingRight: 40,
|
paddingRight: 40,
|
||||||
marginTop: 30,
|
marginTop: 30,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
|
buttonIcon: {
|
||||||
|
marginLeft: 15,
|
||||||
|
paddingTop: 2,
|
||||||
|
color: Colors.white
|
||||||
|
}
|
||||||
} );
|
} );
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { SafeAreaView, ScrollView, StyleSheet, Switch, TouchableOpacity, } from
|
||||||
import { useNavigation } from '@react-navigation/native';
|
import { useNavigation } from '@react-navigation/native';
|
||||||
import { DateTimePickerAndroid, DateTimePickerEvent } from '@react-native-community/datetimepicker';
|
import { DateTimePickerAndroid, DateTimePickerEvent } from '@react-native-community/datetimepicker';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { Colors } from '@/lib/constants/Colors';
|
import { Colors } from '@/lib/constants/Colors';
|
||||||
import { useColorScheme } from '@/lib/hooks/useColorScheme';
|
import { useColorScheme } from '@/lib/hooks/useColorScheme';
|
||||||
|
@ -19,6 +20,7 @@ export default function CategoryScreen() {
|
||||||
const colorScheme = useColorScheme() ?? 'light';
|
const colorScheme = useColorScheme() ?? 'light';
|
||||||
const navigation = useNavigation();
|
const navigation = useNavigation();
|
||||||
const { token } = useToken();
|
const { token } = useToken();
|
||||||
|
const { t } = useTranslation();
|
||||||
const session = useSelector( (state: any) => state.data.session );
|
const session = useSelector( (state: any) => state.data.session );
|
||||||
|
|
||||||
const [ sessionSet, setSessionSet ] = useState( false );
|
const [ sessionSet, setSessionSet ] = useState( false );
|
||||||
|
@ -34,7 +36,7 @@ export default function CategoryScreen() {
|
||||||
// Set page title
|
// Set page title
|
||||||
useEffect( () => {
|
useEffect( () => {
|
||||||
// Set page title
|
// Set page title
|
||||||
navigation.setOptions( { title: ( 'Notificaties' ) } );
|
navigation.setOptions( { title: ( t( "notifications" ) ) } );
|
||||||
}, [] );
|
}, [] );
|
||||||
|
|
||||||
// Set session data
|
// Set session data
|
||||||
|
@ -80,8 +82,8 @@ export default function CategoryScreen() {
|
||||||
onChange,
|
onChange,
|
||||||
mode: 'time',
|
mode: 'time',
|
||||||
is24Hour: true,
|
is24Hour: true,
|
||||||
positiveButton: { label: 'Kies' },
|
positiveButton: { label: t( "choose" ) },
|
||||||
negativeButton: { label: 'Sluiten' },
|
negativeButton: { label: t( "close" ) },
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,14 +99,14 @@ export default function CategoryScreen() {
|
||||||
if (currentEdit === 'dayBefore') {
|
if (currentEdit === 'dayBefore') {
|
||||||
const minDate = new Date( `1970-01-01T16:00` );
|
const minDate = new Date( `1970-01-01T16:00` );
|
||||||
if (minDate > selectedDate) {
|
if (minDate > selectedDate) {
|
||||||
Message.error( 'Meldingen voor 16:00 worden niet ondersteund' );
|
Message.error( t( "notifications-before-16-00" ) );
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const minDate = new Date( `1970-01-01T09:00` );
|
const minDate = new Date( `1970-01-01T09:00` );
|
||||||
if (minDate < selectedDate) {
|
if (minDate < selectedDate) {
|
||||||
Message.error( 'Meldingen na 09:00 worden niet ondersteund' );
|
Message.error( t( "notifications-after-09-00" ) );
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -141,7 +143,7 @@ export default function CategoryScreen() {
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
store.dispatch( setSession( response.session ) );
|
store.dispatch( setSession( response.session ) );
|
||||||
} else {
|
} else {
|
||||||
Message.error( 'Er ging iets mis. Probeer het later opnieuw.' );
|
Message.error( t( "something-went-wrong" ) );
|
||||||
}
|
}
|
||||||
} )
|
} )
|
||||||
}
|
}
|
||||||
|
@ -159,19 +161,19 @@ export default function CategoryScreen() {
|
||||||
style={styles.listSwitch}
|
style={styles.listSwitch}
|
||||||
onValueChange={() => toggleDate( 'dayBefore' )}
|
onValueChange={() => toggleDate( 'dayBefore' )}
|
||||||
/>
|
/>
|
||||||
<ThemedText type="defaultSemiBold">Dag van te voren</ThemedText>
|
<ThemedText type="defaultSemiBold">{t( "day-before" )}</ThemedText>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
|
|
||||||
{isDayBeforeEnabled ?
|
{isDayBeforeEnabled ?
|
||||||
(
|
(
|
||||||
<TouchableOpacity style={styles.listEdit} onPress={() => selectTime( 'dayBefore' )}>
|
<TouchableOpacity style={styles.listEdit} onPress={() => selectTime( 'dayBefore' )}>
|
||||||
<ThemedText style={styles.listEditText}>Om {dayBefore}</ThemedText>
|
<ThemedText style={styles.listEditText}>{t( "at" )} {dayBefore}</ThemedText>
|
||||||
<ThemedIcon size={18} name="chevron-forward" style={styles.listEditIcon}/>
|
<ThemedIcon size={18} name="chevron-forward" style={styles.listEditIcon}/>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
) :
|
) :
|
||||||
(
|
(
|
||||||
<ThemedText style={styles.listEdit}>
|
<ThemedText style={styles.listEdit}>
|
||||||
<ThemedText style={styles.listEditText}>Uit</ThemedText>
|
<ThemedText style={styles.listEditText}>{t( "off" )}</ThemedText>
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -188,19 +190,19 @@ export default function CategoryScreen() {
|
||||||
style={styles.listSwitch}
|
style={styles.listSwitch}
|
||||||
onValueChange={() => toggleDate( 'sameDay' )}
|
onValueChange={() => toggleDate( 'sameDay' )}
|
||||||
/>
|
/>
|
||||||
<ThemedText type="defaultSemiBold">Op de ophaaldag</ThemedText>
|
<ThemedText type="defaultSemiBold">{t( "same-day" )}</ThemedText>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
|
|
||||||
{isSameDayEnabled ?
|
{isSameDayEnabled ?
|
||||||
(
|
(
|
||||||
<TouchableOpacity style={styles.listEdit} onPress={() => selectTime( 'sameDay' )}>
|
<TouchableOpacity style={styles.listEdit} onPress={() => selectTime( 'sameDay' )}>
|
||||||
<ThemedText style={styles.listEditText}>Om {sameDay}</ThemedText>
|
<ThemedText style={styles.listEditText}>{t( "at" )} {sameDay}</ThemedText>
|
||||||
<ThemedIcon size={18} name="chevron-forward" style={styles.listEditIcon}/>
|
<ThemedIcon size={18} name="chevron-forward" style={styles.listEditIcon}/>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
) :
|
) :
|
||||||
(
|
(
|
||||||
<ThemedView style={styles.listEdit}>
|
<ThemedView style={styles.listEdit}>
|
||||||
<ThemedText style={styles.listEditText}>Uit</ThemedText>
|
<ThemedText style={styles.listEditText}>{t( "off" )}</ThemedText>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,7 @@ import {
|
||||||
SafeAreaView,
|
SafeAreaView,
|
||||||
StatusBar,
|
StatusBar,
|
||||||
Image,
|
Image,
|
||||||
TouchableOpacity,
|
TouchableOpacity
|
||||||
View,
|
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
|
|
||||||
import React, { useState, useEffect, useRef } from 'react';
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
|
@ -13,6 +12,7 @@ import { router } from 'expo-router';
|
||||||
import type { AutocompleteDropdownRef } from 'react-native-autocomplete-dropdown'
|
import type { AutocompleteDropdownRef } from 'react-native-autocomplete-dropdown'
|
||||||
import { AutocompleteDropdown } from 'react-native-autocomplete-dropdown';
|
import { AutocompleteDropdown } from 'react-native-autocomplete-dropdown';
|
||||||
import Modal from "react-native-modal";
|
import Modal from "react-native-modal";
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { ThemedText } from '@/lib/components/ThemedText';
|
import { ThemedText } from '@/lib/components/ThemedText';
|
||||||
import { ThemedView } from '@/lib/components/ThemedView';
|
import { ThemedView } from '@/lib/components/ThemedView';
|
||||||
|
@ -25,6 +25,7 @@ import { setViewCategory } from '@/lib/store/dataStore';
|
||||||
|
|
||||||
export default function ExploreScreen() {
|
export default function ExploreScreen() {
|
||||||
const colorScheme = useColorScheme() ?? 'light';
|
const colorScheme = useColorScheme() ?? 'light';
|
||||||
|
const { t } = useTranslation();
|
||||||
const [ categories, setCategories ] = useState( [] );
|
const [ categories, setCategories ] = useState( [] );
|
||||||
const [ types, setTypes ] = useState( [] );
|
const [ types, setTypes ] = useState( [] );
|
||||||
const [ activeCategory, setActiveCategory ] = useState<any | null>( null );
|
const [ activeCategory, setActiveCategory ] = useState<any | null>( null );
|
||||||
|
@ -78,29 +79,29 @@ export default function ExploreScreen() {
|
||||||
<ThemedView>
|
<ThemedView>
|
||||||
<ScrollView style={styles.container}>
|
<ScrollView style={styles.container}>
|
||||||
<ThemedView style={styles.titleContainer}>
|
<ThemedView style={styles.titleContainer}>
|
||||||
<ThemedText type="title">Wat moet waar?</ThemedText>
|
<ThemedText type="title">{t( "what-where" )}</ThemedText>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
|
|
||||||
<ThemedView style={styles.titleContainer}>
|
<ThemedView style={styles.titleContainer}>
|
||||||
<ThemedText type="title" style={{ color: Colors[ colorScheme ].tint }}>en waarom?</ThemedText>
|
<ThemedText type="title" style={{ color: Colors[ colorScheme ].tint }}>{t( "what-why" )}</ThemedText>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
|
|
||||||
<ThemedView style={styles.searchContainer}>
|
<ThemedView style={styles.searchContainer}>
|
||||||
<ThemedText type="defaultSemiBold">Wat wilt u scheiden?</ThemedText>
|
<ThemedText type="defaultSemiBold">{t( "what-separate" )}</ThemedText>
|
||||||
<AutocompleteDropdown
|
<AutocompleteDropdown
|
||||||
ref={searchRef}
|
ref={searchRef}
|
||||||
controller={controller => {
|
controller={controller => {
|
||||||
dropdownController.current = controller
|
dropdownController.current = controller
|
||||||
}}
|
}}
|
||||||
textInputProps={{
|
textInputProps={{
|
||||||
placeholder: 'Wat wilt u scheiden?',
|
placeholder: t( "what-separate" ),
|
||||||
autoCorrect: false,
|
autoCorrect: false,
|
||||||
autoCapitalize: 'none',
|
autoCapitalize: 'none',
|
||||||
}}
|
}}
|
||||||
clearOnFocus={false}
|
clearOnFocus={false}
|
||||||
closeOnBlur={false}
|
closeOnBlur={false}
|
||||||
closeOnSubmit={false}
|
closeOnSubmit={false}
|
||||||
emptyResultText={'Niks gevonden'}
|
emptyResultText={t( "nothing-found" )}
|
||||||
onSelectItem={selectItem}
|
onSelectItem={selectItem}
|
||||||
dataSet={categories}
|
dataSet={categories}
|
||||||
showClear={false}
|
showClear={false}
|
||||||
|
@ -108,7 +109,7 @@ export default function ExploreScreen() {
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
|
|
||||||
<ThemedView style={styles.categoriesContainer}>
|
<ThemedView style={styles.categoriesContainer}>
|
||||||
<ThemedText type="defaultSemiBold">Of kies een categorie:</ThemedText>
|
<ThemedText type="defaultSemiBold">{t( "choose-category" )}:</ThemedText>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
|
|
||||||
<ThemedView style={styles.listContainer}>
|
<ThemedView style={styles.listContainer}>
|
||||||
|
@ -146,14 +147,14 @@ export default function ExploreScreen() {
|
||||||
}
|
}
|
||||||
|
|
||||||
<ThemedView style={{ alignItems: 'center' }}>
|
<ThemedView style={{ alignItems: 'center' }}>
|
||||||
<ThemedText type="defaultSemiBold">Beschrijving:</ThemedText>
|
<ThemedText type="defaultSemiBold">{t( "description" )}:</ThemedText>
|
||||||
<ThemedText>{activeCategory?.description}</ThemedText>
|
<ThemedText>{activeCategory?.description}</ThemedText>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
|
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
onPress={() => setActiveCategory( null )}
|
onPress={() => setActiveCategory( null )}
|
||||||
style={{ ...styles.modalClose, backgroundColor: Colors[ colorScheme ].tint }}>
|
style={{ ...styles.modalClose, backgroundColor: Colors[ colorScheme ].tint }}>
|
||||||
<ThemedText style={{ color: '#fff' }}>Sluiten</ThemedText>
|
<ThemedText style={{ color: '#fff' }}>{t( "close" )}</ThemedText>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
@ -5,6 +5,7 @@ import CalendarPicker from 'react-native-calendar-picker';
|
||||||
import { useIsFocused } from '@react-navigation/core';
|
import { useIsFocused } from '@react-navigation/core';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { LogLevel, OneSignal } from 'react-native-onesignal';
|
import { LogLevel, OneSignal } from 'react-native-onesignal';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { ThemedText } from '@/lib/components/ThemedText';
|
import { ThemedText } from '@/lib/components/ThemedText';
|
||||||
import { ThemedView } from '@/lib/components/ThemedView';
|
import { ThemedView } from '@/lib/components/ThemedView';
|
||||||
|
@ -19,9 +20,10 @@ import { ThemedIcon } from '@/lib/components/ThemedIcon';
|
||||||
export default function HomeScreen() {
|
export default function HomeScreen() {
|
||||||
const colorScheme = useColorScheme() ?? 'light';
|
const colorScheme = useColorScheme() ?? 'light';
|
||||||
const isFocused = useIsFocused();
|
const isFocused = useIsFocused();
|
||||||
|
const { t } = useTranslation();
|
||||||
const session = useSelector( (state: any) => state.data.session );
|
const session = useSelector( (state: any) => state.data.session );
|
||||||
const reloadCalendar = useSelector( (state: any) => state.data.reloadCalendar );
|
const reloadCalendar = useSelector( (state: any) => state.data.reloadCalendar );
|
||||||
const { token, isLoading } = useToken();
|
const { token } = 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>( [] );
|
||||||
|
@ -68,6 +70,21 @@ export default function HomeScreen() {
|
||||||
}
|
}
|
||||||
}, [ reloadCalendar, isFocused ] );
|
}, [ reloadCalendar, isFocused ] );
|
||||||
|
|
||||||
|
const getGreeting = () => {
|
||||||
|
const myDate = new Date();
|
||||||
|
const hours = myDate.getHours();
|
||||||
|
|
||||||
|
if (hours < 12) {
|
||||||
|
return t( "greeting.morning" );
|
||||||
|
} else if (hours >= 12 && hours <= 17) {
|
||||||
|
return t( "greeting.afternoon" );
|
||||||
|
} else if (hours >= 17 && hours <= 24) {
|
||||||
|
return t( "greeting.evening" );
|
||||||
|
}
|
||||||
|
|
||||||
|
return t( "greeting.hello" );
|
||||||
|
}
|
||||||
|
|
||||||
// Load calendar data
|
// Load calendar data
|
||||||
const loadCalendar = () => {
|
const loadCalendar = () => {
|
||||||
Request.post( 'calendar', { token: token } ).then( (response) => {
|
Request.post( 'calendar', { token: token } ).then( (response) => {
|
||||||
|
@ -116,26 +133,34 @@ export default function HomeScreen() {
|
||||||
nextComponent={
|
nextComponent={
|
||||||
<ThemedIcon size={28} name="chevron-forward"/>
|
<ThemedIcon size={28} name="chevron-forward"/>
|
||||||
}
|
}
|
||||||
weekdays={[ "Ma", "Di", "Woe", "Do", "Vrij", "Zat", "Zo" ]}
|
weekdays={[
|
||||||
|
t( "days.mon" ),
|
||||||
|
t( "days.tue" ),
|
||||||
|
t( "days.wed" ),
|
||||||
|
t( "days.thu" ),
|
||||||
|
t( "days.fri" ),
|
||||||
|
t( "days.sat" ),
|
||||||
|
t( "days.sun" ),
|
||||||
|
]}
|
||||||
months={[
|
months={[
|
||||||
"Januari",
|
t( "months.january" ),
|
||||||
"Februari",
|
t( "months.february" ),
|
||||||
"Maart",
|
t( "months.march" ),
|
||||||
"April",
|
t( "months.april" ),
|
||||||
"Mei",
|
t( "months.may" ),
|
||||||
"Juni",
|
t( "months.june" ),
|
||||||
"Juli",
|
t( "months.july" ),
|
||||||
"Augustus",
|
t( "months.august" ),
|
||||||
"September",
|
t( "months.september" ),
|
||||||
"Oktober",
|
t( "months.october" ),
|
||||||
"November",
|
t( "months.november" ),
|
||||||
"December",
|
t( "months.december" ),
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
|
|
||||||
<ThemedView style={styles.legendaContainer}>
|
<ThemedView style={styles.legendaContainer}>
|
||||||
<ThemedText type='subtitle'>Legenda:</ThemedText>
|
<ThemedText type='subtitle'>{t( "legenda" )}:</ThemedText>
|
||||||
<List
|
<List
|
||||||
data={types}
|
data={types}
|
||||||
viewStyle={styles.legendaList}
|
viewStyle={styles.legendaList}
|
||||||
|
@ -153,21 +178,6 @@ export default function HomeScreen() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getGreeting() {
|
|
||||||
const myDate = new Date();
|
|
||||||
const hours = myDate.getHours();
|
|
||||||
|
|
||||||
if (hours < 12) {
|
|
||||||
return 'Goedemorgen';
|
|
||||||
} else if (hours >= 12 && hours <= 17) {
|
|
||||||
return 'Goedemiddag';
|
|
||||||
} else if (hours >= 17 && hours <= 24) {
|
|
||||||
return 'Goedenavond';
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'Hallo';
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = StyleSheet.create( {
|
const styles = StyleSheet.create( {
|
||||||
container: {
|
container: {
|
||||||
padding: 25,
|
padding: 25,
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { Image, SafeAreaView, ScrollView, StatusBar, StyleSheet, Switch, View, D
|
||||||
import Mapbox, { Callout, Camera, MapView, PointAnnotation } from "@rnmapbox/maps";
|
import Mapbox, { Callout, Camera, MapView, PointAnnotation } from "@rnmapbox/maps";
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { useIsFocused } from '@react-navigation/core';
|
import { useIsFocused } from '@react-navigation/core';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
Mapbox.setAccessToken( "pk.eyJ1IjoibWFhcnRlbnZyOTgiLCJhIjoiY2x6ZDFqMGp1MGVyejJrczhqcXpvYm9iYiJ9.XvYcL62dWiJQiFmG6mOoug" );
|
Mapbox.setAccessToken( "pk.eyJ1IjoibWFhcnRlbnZyOTgiLCJhIjoiY2x6ZDFqMGp1MGVyejJrczhqcXpvYm9iYiJ9.XvYcL62dWiJQiFmG6mOoug" );
|
||||||
|
|
||||||
|
@ -17,6 +18,7 @@ export default function MapScreen() {
|
||||||
const colorScheme = useColorScheme() ?? 'light';
|
const colorScheme = useColorScheme() ?? 'light';
|
||||||
const isFocused = useIsFocused();
|
const isFocused = useIsFocused();
|
||||||
const session = useSelector((state: any) => state.data.session);
|
const session = useSelector((state: any) => state.data.session);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const [ types, setTypes ] = useState<any>( [] );
|
const [ types, setTypes ] = useState<any>( [] );
|
||||||
const [ coordinates, setCoordinates ] = useState<any>( [] );
|
const [ coordinates, setCoordinates ] = useState<any>( [] );
|
||||||
|
@ -85,11 +87,11 @@ export default function MapScreen() {
|
||||||
<ThemedView style={styles.container}>
|
<ThemedView style={styles.container}>
|
||||||
<ThemedView>
|
<ThemedView>
|
||||||
<ThemedView style={styles.titleContainer}>
|
<ThemedView style={styles.titleContainer}>
|
||||||
<ThemedText type="title">Afvalcontainers</ThemedText>
|
<ThemedText type="title">{t( "garbage-bins" )}</ThemedText>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
|
|
||||||
<ThemedView style={styles.titleContainer}>
|
<ThemedView style={styles.titleContainer}>
|
||||||
<ThemedText type="title" style={{ color: Colors[ colorScheme ].tint }}>in de buurt</ThemedText>
|
<ThemedText type="title" style={{ color: Colors[ colorScheme ].tint }}>{t( "nearby" )}</ThemedText>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
|
|
||||||
<ThemedView style={styles.mapContainer}>
|
<ThemedView style={styles.mapContainer}>
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
ScrollView,
|
ScrollView,
|
||||||
SafeAreaView,
|
SafeAreaView,
|
||||||
StatusBar,
|
StatusBar,
|
||||||
TouchableOpacity,
|
TouchableOpacity,
|
||||||
Alert,
|
Alert, Image,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { useRouter } from 'expo-router';
|
import { useRouter } from 'expo-router';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { BottomSheet, BottomSheetRefType } from 'react-native-select-bottom-list';
|
||||||
|
|
||||||
|
|
||||||
import { ThemedText } from '@/lib/components/ThemedText';
|
import { ThemedText } from '@/lib/components/ThemedText';
|
||||||
import { ThemedView } from '@/lib/components/ThemedView';
|
import { ThemedView } from '@/lib/components/ThemedView';
|
||||||
|
@ -21,10 +24,12 @@ import CustomModal from '@/lib/components/EditModal';
|
||||||
import { store } from '@/lib/store/store';
|
import { store } from '@/lib/store/store';
|
||||||
import { setSession, setReloadCalendar } from '@/lib/store/dataStore';
|
import { setSession, setReloadCalendar } from '@/lib/store/dataStore';
|
||||||
import { ThemedIcon } from '@/lib/components/ThemedIcon';
|
import { ThemedIcon } from '@/lib/components/ThemedIcon';
|
||||||
|
import List from '@/lib/components/List';
|
||||||
|
|
||||||
export default function SettingsScreen() {
|
export default function SettingsScreen() {
|
||||||
const colorScheme = useColorScheme() ?? 'light';
|
const colorScheme = useColorScheme() ?? 'light';
|
||||||
const { token, setToken } = useToken();
|
const { token, setToken } = useToken();
|
||||||
|
const { t, i18n } = useTranslation();
|
||||||
const session = useSelector( (state: any) => state.data.session );
|
const session = useSelector( (state: any) => state.data.session );
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
@ -39,6 +44,10 @@ export default function SettingsScreen() {
|
||||||
const [ city, setCity ] = React.useState( '3' );
|
const [ city, setCity ] = React.useState( '3' );
|
||||||
const [ addressModalVisible, setAddressModalVisible ] = useState( false );
|
const [ addressModalVisible, setAddressModalVisible ] = useState( false );
|
||||||
|
|
||||||
|
// Language
|
||||||
|
const [ language, setLanguage ] = useState( 'nl' );
|
||||||
|
const sheetRef = useRef<BottomSheetRefType>( null );
|
||||||
|
|
||||||
useEffect( () => {
|
useEffect( () => {
|
||||||
setSessionData( session );
|
setSessionData( session );
|
||||||
}, [ session ] );
|
}, [ session ] );
|
||||||
|
@ -53,6 +62,9 @@ export default function SettingsScreen() {
|
||||||
setHouseNumber( session.address.houseNumber );
|
setHouseNumber( session.address.houseNumber );
|
||||||
setStreet( session.address.street );
|
setStreet( session.address.street );
|
||||||
setCity( session.address.city );
|
setCity( session.address.city );
|
||||||
|
|
||||||
|
// Language
|
||||||
|
setLanguage(session.language);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle save settings
|
// Handle save settings
|
||||||
|
@ -75,6 +87,10 @@ export default function SettingsScreen() {
|
||||||
addressChanged = true;
|
addressChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inputValues.language) {
|
||||||
|
postData[ 'language' ] = inputValues.language;
|
||||||
|
}
|
||||||
|
|
||||||
Request.post( 'sessions/update', postData )
|
Request.post( 'sessions/update', postData )
|
||||||
.then( (response) => {
|
.then( (response) => {
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
|
@ -84,32 +100,46 @@ export default function SettingsScreen() {
|
||||||
store.dispatch( setSession( response.session ) )
|
store.dispatch( setSession( response.session ) )
|
||||||
store.dispatch( setReloadCalendar( addressChanged ) )
|
store.dispatch( setReloadCalendar( addressChanged ) )
|
||||||
|
|
||||||
Message.success( 'Opgeslagen!' )
|
Message.success( t( "saved" ) )
|
||||||
} else {
|
} else {
|
||||||
Message.error( response.message );
|
Message.error( response.message );
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const openLanguageSelect = () => {
|
||||||
|
sheetRef.current?.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeLanguage = (lang: string) => {
|
||||||
|
sheetRef.current?.close();
|
||||||
|
|
||||||
|
i18n.changeLanguage( lang ).then( () => {
|
||||||
|
setLanguage(lang);
|
||||||
|
|
||||||
|
handleSave( { language: lang } );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
// Remove session data and logout
|
// Remove session data and logout
|
||||||
const logout = () => {
|
const logout = () => {
|
||||||
Alert.alert( 'Uitloggen', 'Weet je het zeker?', [
|
Alert.alert( t( "logout" ), t( "are-you-sure" ), [
|
||||||
{
|
{
|
||||||
text: 'Annuleren',
|
text: t( "cancel" ),
|
||||||
style: 'cancel',
|
style: 'cancel',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Ja',
|
text: t( "ja" ),
|
||||||
onPress: () => {
|
onPress: () => {
|
||||||
Request.post( 'sessions/delete' ).then( (response) => {
|
Request.post( 'sessions/delete' ).then( (response) => {
|
||||||
if (!response.success) {
|
if (!response.success) {
|
||||||
Message.success( 'Je bent uitgelogd' );
|
Message.success( t( "logged-out" ) );
|
||||||
|
|
||||||
setToken( null );
|
setToken( null );
|
||||||
|
|
||||||
router.replace( '/(onboarding)/start' );
|
router.replace( '/(onboarding)/start' );
|
||||||
} else {
|
} else {
|
||||||
Message.error( 'Er is iets mis gegaan. Probeer het later opnieuw!' )
|
Message.error( t( "something-went-wrong" ) )
|
||||||
}
|
}
|
||||||
} )
|
} )
|
||||||
}
|
}
|
||||||
|
@ -122,14 +152,14 @@ export default function SettingsScreen() {
|
||||||
<ThemedView style={styles.container}>
|
<ThemedView style={styles.container}>
|
||||||
<ScrollView>
|
<ScrollView>
|
||||||
<ThemedView style={styles.titleContainer}>
|
<ThemedView style={styles.titleContainer}>
|
||||||
<ThemedText type="title">Instellingen</ThemedText>
|
<ThemedText type="title">{t( "settings" )}</ThemedText>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
|
|
||||||
<ThemedView style={styles.listContainer}>
|
<ThemedView style={styles.listContainer}>
|
||||||
<ThemedView style={styles.listItem}>
|
<ThemedView style={styles.listItem}>
|
||||||
<ThemedView style={styles.listTitle}>
|
<ThemedView style={styles.listTitle}>
|
||||||
<ThemedIcon name="person-outline" size={20} style={styles.listIcon}/>
|
<ThemedIcon name="person-outline" size={20} style={styles.listIcon}/>
|
||||||
<ThemedText type="defaultSemiBold">Naam</ThemedText>
|
<ThemedText type="defaultSemiBold">{t( "name" )}</ThemedText>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
|
|
||||||
<TouchableOpacity style={styles.listEdit} onPress={() => setNameModalVisible( true )}>
|
<TouchableOpacity style={styles.listEdit} onPress={() => setNameModalVisible( true )}>
|
||||||
|
@ -141,7 +171,7 @@ export default function SettingsScreen() {
|
||||||
<ThemedView style={styles.listItem}>
|
<ThemedView style={styles.listItem}>
|
||||||
<ThemedView style={styles.listTitle}>
|
<ThemedView style={styles.listTitle}>
|
||||||
<ThemedIcon size={20} name="trail-sign-outline" style={styles.listIcon}/>
|
<ThemedIcon size={20} name="trail-sign-outline" style={styles.listIcon}/>
|
||||||
<ThemedText type="defaultSemiBold">Adres</ThemedText>
|
<ThemedText type="defaultSemiBold">{t( "address" )}</ThemedText>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
|
|
||||||
<TouchableOpacity style={styles.listEdit} onPress={() => setAddressModalVisible( true )}>
|
<TouchableOpacity style={styles.listEdit} onPress={() => setAddressModalVisible( true )}>
|
||||||
|
@ -153,11 +183,23 @@ export default function SettingsScreen() {
|
||||||
<ThemedView style={styles.listItem}>
|
<ThemedView style={styles.listItem}>
|
||||||
<ThemedView style={styles.listTitle}>
|
<ThemedView style={styles.listTitle}>
|
||||||
<ThemedIcon size={20} name="notifications-outline" style={styles.listIcon}/>
|
<ThemedIcon size={20} name="notifications-outline" style={styles.listIcon}/>
|
||||||
<ThemedText type="defaultSemiBold">Notificaties</ThemedText>
|
<ThemedText type="defaultSemiBold">{t( "notifications" )}</ThemedText>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
|
|
||||||
<TouchableOpacity style={styles.listEdit} onPress={() => router.push( '/(settings)/notifications' )}>
|
<TouchableOpacity style={styles.listEdit} onPress={() => router.push( '/(settings)/notifications' )}>
|
||||||
<ThemedText style={styles.listEditText}>Wijzigen</ThemedText>
|
<ThemedText style={styles.listEditText}>{t( "change" )}</ThemedText>
|
||||||
|
<ThemedIcon size={18} name="chevron-forward" style={styles.listEditIcon}/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</ThemedView>
|
||||||
|
|
||||||
|
<ThemedView style={styles.listItem}>
|
||||||
|
<ThemedView style={styles.listTitle}>
|
||||||
|
<ThemedIcon size={20} name="language-outline" style={styles.listIcon}/>
|
||||||
|
<ThemedText type="defaultSemiBold">{t( "language" )}</ThemedText>
|
||||||
|
</ThemedView>
|
||||||
|
|
||||||
|
<TouchableOpacity style={styles.listEdit} onPress={openLanguageSelect}>
|
||||||
|
<ThemedText style={styles.listEditText}>{t( "languages." + language )}</ThemedText>
|
||||||
<ThemedIcon size={18} name="chevron-forward" style={styles.listEditIcon}/>
|
<ThemedIcon size={18} name="chevron-forward" style={styles.listEditIcon}/>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
|
@ -166,7 +208,7 @@ export default function SettingsScreen() {
|
||||||
<ThemedText>
|
<ThemedText>
|
||||||
<TouchableOpacity onPress={logout}>
|
<TouchableOpacity onPress={logout}>
|
||||||
<ThemedText type="defaultSemiBold" style={styles.logout}>
|
<ThemedText type="defaultSemiBold" style={styles.logout}>
|
||||||
Uitloggen
|
{t( "logout" )}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
|
@ -174,39 +216,63 @@ export default function SettingsScreen() {
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
|
|
||||||
<CustomModal
|
<CustomModal
|
||||||
title="Naam wijzigen"
|
title={t( "modal.name.title" )}
|
||||||
visible={nameModalVisible}
|
visible={nameModalVisible}
|
||||||
onClose={() => setNameModalVisible( false )}
|
onClose={() => setNameModalVisible( false )}
|
||||||
onSave={handleSave}
|
onSave={handleSave}
|
||||||
fields={[
|
fields={[
|
||||||
{
|
{
|
||||||
name: 'name',
|
name: 'name',
|
||||||
placeholder: 'Je naam',
|
placeholder: t( "modal.name.your-name" ),
|
||||||
defaultValue: name,
|
defaultValue: name,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<CustomModal
|
<CustomModal
|
||||||
title="Adres wijzigen"
|
title={t( "modal.address.title" )}
|
||||||
visible={addressModalVisible}
|
visible={addressModalVisible}
|
||||||
onClose={() => setAddressModalVisible( false )}
|
onClose={() => setAddressModalVisible( false )}
|
||||||
onSave={handleSave}
|
onSave={handleSave}
|
||||||
fields={[
|
fields={[
|
||||||
{
|
{
|
||||||
name: 'zipcode',
|
name: 'zipcode',
|
||||||
title: 'Postcode',
|
title: t( "modal.address.zipcode" ),
|
||||||
placeholder: 'Je postcode',
|
placeholder: t( "modal.address.your-zipcode" ),
|
||||||
defaultValue: zipcode,
|
defaultValue: zipcode,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'houseNumber',
|
name: 'houseNumber',
|
||||||
title: 'Huisnummer',
|
title: t( "modal.address.house-number" ),
|
||||||
placeholder: 'Je huis nummer',
|
placeholder: t( "modal.address.your-house-number" ),
|
||||||
defaultValue: houseNumber,
|
defaultValue: houseNumber,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<BottomSheet ref={sheetRef} presentationStyle={'overFullScreen'}>
|
||||||
|
<ThemedView>
|
||||||
|
<List
|
||||||
|
data={[
|
||||||
|
{
|
||||||
|
name: t( "languages.nl" ),
|
||||||
|
key: "nl",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: t( "languages.en" ),
|
||||||
|
key: "en",
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
viewStyle={styles.languagesList}
|
||||||
|
renderItem={(item: any, index: any) => (
|
||||||
|
<TouchableOpacity style={styles.languagesListItem} key={index} onPress={() => changeLanguage( item.key )}>
|
||||||
|
<ThemedText type="defaultSemiBold">{item.name}</ThemedText>
|
||||||
|
<ThemedIcon name={'chevron-forward'} size={18}/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</ThemedView>
|
||||||
|
</BottomSheet>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -262,4 +328,20 @@ const styles = StyleSheet.create( {
|
||||||
logout: {
|
logout: {
|
||||||
color: Colors.red,
|
color: Colors.red,
|
||||||
},
|
},
|
||||||
|
languagesList: {
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
padding: 25,
|
||||||
|
},
|
||||||
|
languagesListItem: {
|
||||||
|
display: 'flex',
|
||||||
|
gap: 8,
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
paddingBottom: 15,
|
||||||
|
marginBottom: 15,
|
||||||
|
borderBottomWidth: 1,
|
||||||
|
borderBottomColor: '#f2f2f2',
|
||||||
|
}
|
||||||
} );
|
} );
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { Redirect, router, useRouter } from 'expo-router';
|
import { Redirect, useRouter } from 'expo-router';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { ThemedText } from '@/lib/components/ThemedText';
|
import { ThemedText } from '@/lib/components/ThemedText';
|
||||||
import { ThemedView } from '@/lib/components/ThemedView';
|
import { ThemedView } from '@/lib/components/ThemedView';
|
||||||
|
@ -7,15 +8,17 @@ import { useToken } from '@/lib/context/AppProvider';
|
||||||
import { Request } from '@/lib/services/request';
|
import { Request } from '@/lib/services/request';
|
||||||
import { store } from '@/lib/store/store';
|
import { store } from '@/lib/store/store';
|
||||||
import { setSession } from '@/lib/store/dataStore';
|
import { setSession } from '@/lib/store/dataStore';
|
||||||
|
import '@/lib/localization/i18n';
|
||||||
|
|
||||||
|
|
||||||
export default function OnboardStartScreen() {
|
export default function OnboardStartScreen() {
|
||||||
const { token, isLoading } = useToken();
|
const { token, isLoading } = useToken();
|
||||||
|
const { i18n } = useTranslation();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const loadingScreen = () => (
|
const loadingScreen = () => (
|
||||||
<ThemedView>
|
<ThemedView>
|
||||||
<ThemedText>Laden...</ThemedText>
|
<ThemedText>Loading...</ThemedText>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -26,6 +29,9 @@ export default function OnboardStartScreen() {
|
||||||
// Save to store
|
// Save to store
|
||||||
store.dispatch(setSession(response.session))
|
store.dispatch(setSession(response.session))
|
||||||
|
|
||||||
|
// Set language
|
||||||
|
i18n.changeLanguage(response.session.language);
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
router.replace( '/(tabs)' );
|
router.replace( '/(tabs)' );
|
||||||
} else {
|
} else {
|
||||||
|
|
93
assets/languages/en.json
Normal file
93
assets/languages/en.json
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
{
|
||||||
|
"onboarding": {
|
||||||
|
"missing-info": "Not all information has been filled in!",
|
||||||
|
"welcome": "Welcome to",
|
||||||
|
"your-name": "What is your name?",
|
||||||
|
"name": "Your name",
|
||||||
|
"your-address": "What is your address?",
|
||||||
|
"zipcode": "Zipcode",
|
||||||
|
"house-number": "House number",
|
||||||
|
"start": "Start"
|
||||||
|
},
|
||||||
|
"greeting": {
|
||||||
|
"hello": "Hello",
|
||||||
|
"morning": "Good morning",
|
||||||
|
"afternoon": "Good afternoon",
|
||||||
|
"evening": "Good evening"
|
||||||
|
},
|
||||||
|
"months": {
|
||||||
|
"january": "January",
|
||||||
|
"february": "February",
|
||||||
|
"march": "March",
|
||||||
|
"april": "April",
|
||||||
|
"may": "May",
|
||||||
|
"june": "June",
|
||||||
|
"july": "July",
|
||||||
|
"august": "August",
|
||||||
|
"september": "September",
|
||||||
|
"october": "October",
|
||||||
|
"november": "November",
|
||||||
|
"december": "December"
|
||||||
|
},
|
||||||
|
"days": {
|
||||||
|
"mon": "Mon",
|
||||||
|
"tue": "Tue",
|
||||||
|
"wed": "Wed",
|
||||||
|
"thu": "Thu",
|
||||||
|
"fri": "Fri",
|
||||||
|
"sat": "Sat",
|
||||||
|
"sun": "Sun"
|
||||||
|
},
|
||||||
|
"legenda": "Legend",
|
||||||
|
"garbage-bins": "Garbage bins",
|
||||||
|
"nearby": "nearby",
|
||||||
|
"what-where": "What goes where?",
|
||||||
|
"what-why": "and why?",
|
||||||
|
"what-separate": "What do you want to separate?",
|
||||||
|
"nothing-found": "Nothing found",
|
||||||
|
"choose-category": "Or choose a category",
|
||||||
|
"description": "Description",
|
||||||
|
"close": "Close",
|
||||||
|
"saved": "Saved!",
|
||||||
|
"are-you-sure": "Are you sure?",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"yes": "Yes",
|
||||||
|
"logged-out": "You are logged out",
|
||||||
|
"something-went-wrong": "Something went wrong. Please try again later!",
|
||||||
|
"settings": "Settings",
|
||||||
|
"name": "Name",
|
||||||
|
"address": "Address",
|
||||||
|
"language": "Language",
|
||||||
|
"languages": {
|
||||||
|
"nl": "Dutch",
|
||||||
|
"en": "English"
|
||||||
|
},
|
||||||
|
"notifications": "Notifications",
|
||||||
|
"change": "Change",
|
||||||
|
"logout": "Logout",
|
||||||
|
"modal": {
|
||||||
|
"name": {
|
||||||
|
"title": "Change name",
|
||||||
|
"your-name": "Your name"
|
||||||
|
},
|
||||||
|
"address": {
|
||||||
|
"title": "Change address",
|
||||||
|
"zipcode": "Zip code",
|
||||||
|
"your-zipcode": "Your zip code",
|
||||||
|
"house-number": "House number",
|
||||||
|
"your-house-number": "Your house number"
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"title": "Edit your details:",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"save": "Save"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"choose": "Choose",
|
||||||
|
"notifications-before-16-00": "Meldingen voor 16:00 worden niet ondersteund",
|
||||||
|
"notifications-after-09-00": "Meldingen na 09:00 worden niet ondersteund",
|
||||||
|
"day-before": "A day before",
|
||||||
|
"same-day": "At the same day",
|
||||||
|
"off": "Off",
|
||||||
|
"at": "at"
|
||||||
|
}
|
2
assets/languages/index.tsx
Normal file
2
assets/languages/index.tsx
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export { default as en } from "./en.json";
|
||||||
|
export { default as nl } from "./nl.json";
|
93
assets/languages/nl.json
Normal file
93
assets/languages/nl.json
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
{
|
||||||
|
"onboarding": {
|
||||||
|
"missing-info": "Niet alle gegevens zijn ingevuld!",
|
||||||
|
"welcome": "Welkom bij",
|
||||||
|
"your-name": "Wat is je naam?",
|
||||||
|
"name": "Je naam",
|
||||||
|
"your-address": "Wat is je adres?",
|
||||||
|
"zipcode": "Postcode",
|
||||||
|
"house-number": "Huisnummer",
|
||||||
|
"start": "Start"
|
||||||
|
},
|
||||||
|
"greeting": {
|
||||||
|
"hello": "Hallo",
|
||||||
|
"morning": "Goedemorgen",
|
||||||
|
"afternoon": "Goedemiddag",
|
||||||
|
"evening": "Goedenavond"
|
||||||
|
},
|
||||||
|
"months": {
|
||||||
|
"january": "Januari",
|
||||||
|
"february": "Februari",
|
||||||
|
"march": "Maart",
|
||||||
|
"april": "April",
|
||||||
|
"may": "Mei",
|
||||||
|
"june": "Juni",
|
||||||
|
"july": "Juli",
|
||||||
|
"august": "Augustus",
|
||||||
|
"september": "September",
|
||||||
|
"october": "Oktober",
|
||||||
|
"november": "November",
|
||||||
|
"december": "December"
|
||||||
|
},
|
||||||
|
"days": {
|
||||||
|
"mon": "Ma",
|
||||||
|
"tue": "Di",
|
||||||
|
"wed": "Woe",
|
||||||
|
"thu": "Do",
|
||||||
|
"fri": "Vrij",
|
||||||
|
"sat": "Zat",
|
||||||
|
"sun": "Zon"
|
||||||
|
},
|
||||||
|
"legenda": "Legenda",
|
||||||
|
"garbage-bins": "Afvalcontainers",
|
||||||
|
"nearby": "in de buurt",
|
||||||
|
"what-where": "Wat moet waar?",
|
||||||
|
"what-why": "en waarom?",
|
||||||
|
"what-separate": "Wat wilt u scheiden?",
|
||||||
|
"nothing-found": "Niks gevonden",
|
||||||
|
"choose-category": "Of kies een categorie",
|
||||||
|
"description": "Beschrijving",
|
||||||
|
"close": "Sluiten",
|
||||||
|
"saved": "Opgeslagen!",
|
||||||
|
"are-you-sure": "Weet je het zeker?",
|
||||||
|
"cancel": "Annuleren",
|
||||||
|
"yes": "Ja",
|
||||||
|
"logged-out": "Je bent uitgelogd",
|
||||||
|
"something-went-wrong": "Er is iets mis gegaan. Probeer het later opnieuw!",
|
||||||
|
"settings": "Instellingen",
|
||||||
|
"name": "Naam",
|
||||||
|
"address": "Adres",
|
||||||
|
"language": "Taal",
|
||||||
|
"languages": {
|
||||||
|
"nl": "Nederlands",
|
||||||
|
"en": "Engels"
|
||||||
|
},
|
||||||
|
"notifications": "Notificaties",
|
||||||
|
"change": "Wijzigen",
|
||||||
|
"logout": "Uitloggen",
|
||||||
|
"modal": {
|
||||||
|
"name": {
|
||||||
|
"title": "Naam wijzigen",
|
||||||
|
"your-name": "Je naam"
|
||||||
|
},
|
||||||
|
"address": {
|
||||||
|
"title": "Adres wijzigen",
|
||||||
|
"zipcode": "Postcode",
|
||||||
|
"your-zipcode": "Je postcode",
|
||||||
|
"house-number": "Huisnummer",
|
||||||
|
"your-house-number": "Je huisnummer"
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"title": "Pas je gegevens aan:",
|
||||||
|
"cancel": "Annuleren",
|
||||||
|
"save": "Opslaan"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"choose": "Kies",
|
||||||
|
"notifications-before-16-00": "Meldingen voor 16:00 worden niet ondersteund",
|
||||||
|
"notifications-after-09-00": "Meldingen na 09:00 worden niet ondersteund",
|
||||||
|
"day-before": "Dag van te voren",
|
||||||
|
"same-day": "Op de ophaaldag",
|
||||||
|
"off": "Uit",
|
||||||
|
"at": "Om"
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import {
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import Modal from "react-native-modal";
|
import Modal from "react-native-modal";
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { Colors } from '@/lib/constants/Colors';
|
import { Colors } from '@/lib/constants/Colors';
|
||||||
import { ThemedView } from '@/lib/components/ThemedView';
|
import { ThemedView } from '@/lib/components/ThemedView';
|
||||||
|
@ -29,6 +30,7 @@ interface EditModalProps {
|
||||||
const CustomModal: React.FC<EditModalProps> = ({ title, visible, onClose, onSave, fields }) => {
|
const CustomModal: React.FC<EditModalProps> = ({ title, visible, onClose, onSave, fields }) => {
|
||||||
const colorScheme = useColorScheme() ?? 'light';
|
const colorScheme = useColorScheme() ?? 'light';
|
||||||
const [ inputValues, setInputValues ] = useState<Record<string, string>>( {} );
|
const [ inputValues, setInputValues ] = useState<Record<string, string>>( {} );
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
useEffect( () => {
|
useEffect( () => {
|
||||||
const initialValues: Record<string, string> = {};
|
const initialValues: Record<string, string> = {};
|
||||||
|
@ -54,13 +56,13 @@ const CustomModal: React.FC<EditModalProps> = ({ title, visible, onClose, onSave
|
||||||
return (
|
return (
|
||||||
<Modal isVisible={visible} useNativeDriverForBackdrop={true}>
|
<Modal isVisible={visible} useNativeDriverForBackdrop={true}>
|
||||||
<ThemedView style={{ ...styles.view, backgroundColor: Colors[ colorScheme ].background }}>
|
<ThemedView style={{ ...styles.view, backgroundColor: Colors[ colorScheme ].background }}>
|
||||||
<ThemedText style={styles.text}>{title ? title : 'Pas je gegevens aan:'}</ThemedText>
|
<ThemedText style={styles.text}>{title ? title : t( "modal.default.title" )}</ThemedText>
|
||||||
|
|
||||||
{fields.map( (field, index) => (
|
{fields.map( (field, index) => (
|
||||||
<ThemedView key={index} style={styles.inputContainer}>
|
<ThemedView key={index} style={styles.inputContainer}>
|
||||||
{field.title && <ThemedText style={styles.inputTitle}>{field.title}</ThemedText>}
|
{field.title && <ThemedText style={styles.inputTitle}>{field.title}</ThemedText>}
|
||||||
<TextInput
|
<TextInput
|
||||||
style={[styles.input, {color: Colors[ colorScheme ].text}]}
|
style={[ styles.input, { color: Colors[ colorScheme ].text } ]}
|
||||||
placeholder={field.placeholder}
|
placeholder={field.placeholder}
|
||||||
onChangeText={(text) => handleInputChange( field.name, text )}
|
onChangeText={(text) => handleInputChange( field.name, text )}
|
||||||
value={inputValues[ field.name ] || ''}
|
value={inputValues[ field.name ] || ''}
|
||||||
|
@ -73,11 +75,11 @@ const CustomModal: React.FC<EditModalProps> = ({ title, visible, onClose, onSave
|
||||||
<ThemedView style={styles.buttonContainer}>
|
<ThemedView style={styles.buttonContainer}>
|
||||||
<TouchableOpacity onPress={onClose || ( () => {
|
<TouchableOpacity onPress={onClose || ( () => {
|
||||||
} )}>
|
} )}>
|
||||||
<ThemedText style={[ styles.textStyle, styles.buttonClose ]}>Annuleren</ThemedText>
|
<ThemedText style={[ styles.textStyle, styles.buttonClose ]}>{t( "modal.default.cancel" )}</ThemedText>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
|
||||||
<TouchableOpacity style={styles.buttonSave} onPress={handleSave}>
|
<TouchableOpacity style={styles.buttonSave} onPress={handleSave}>
|
||||||
<ThemedText style={styles.textStyle}>Opslaan</ThemedText>
|
<ThemedText style={styles.textStyle}>{t( "modal.default.save" )}</ThemedText>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
|
|
54
lib/localization/i18n.tsx
Normal file
54
lib/localization/i18n.tsx
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import i18n from 'i18next';
|
||||||
|
import { initReactI18next } from 'react-i18next';
|
||||||
|
import { en, nl } from "@/assets/languages";
|
||||||
|
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||||
|
|
||||||
|
const STORE_LANGUAGE_KEY = "settings.lang";
|
||||||
|
|
||||||
|
const languageDetectorPlugin = {
|
||||||
|
type: "languageDetector",
|
||||||
|
async: true,
|
||||||
|
init: () => { },
|
||||||
|
detect: async function (callback: (lang: string) => void) {
|
||||||
|
try {
|
||||||
|
// get stored language from Async storage
|
||||||
|
// put your own language detection logic here
|
||||||
|
await AsyncStorage.getItem(STORE_LANGUAGE_KEY).then((language) => {
|
||||||
|
if (language) {
|
||||||
|
//if language was stored before, use this language in the app
|
||||||
|
return callback(language);
|
||||||
|
} else {
|
||||||
|
//if language was not stored yet, use english
|
||||||
|
return callback("nl");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Error reading language", error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
cacheUserLanguage: async function (language: string) {
|
||||||
|
try {
|
||||||
|
//save a user's language choice in Async storage
|
||||||
|
await AsyncStorage.setItem(STORE_LANGUAGE_KEY, language);
|
||||||
|
} catch (error) { }
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const resources = {
|
||||||
|
en: {
|
||||||
|
translation: en,
|
||||||
|
},
|
||||||
|
nl: {
|
||||||
|
translation: nl,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
i18n.use(initReactI18next).use(languageDetectorPlugin).init({
|
||||||
|
resources,
|
||||||
|
compatibilityJSON: 'v3',
|
||||||
|
fallbackLng: "nl",
|
||||||
|
interpolation: {
|
||||||
|
escapeValue: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
export default i18n;
|
|
@ -8,6 +8,7 @@ const dataStore = createSlice( {
|
||||||
token: '',
|
token: '',
|
||||||
name: '',
|
name: '',
|
||||||
device: '',
|
device: '',
|
||||||
|
language: 'nl',
|
||||||
address: {
|
address: {
|
||||||
id: 0,
|
id: 0,
|
||||||
zipcode: '',
|
zipcode: '',
|
||||||
|
|
|
@ -36,10 +36,12 @@
|
||||||
"expo-status-bar": "~1.12.1",
|
"expo-status-bar": "~1.12.1",
|
||||||
"expo-system-ui": "~3.0.7",
|
"expo-system-ui": "~3.0.7",
|
||||||
"expo-web-browser": "~13.0.3",
|
"expo-web-browser": "~13.0.3",
|
||||||
|
"i18next": "^23.12.2",
|
||||||
"install": "^0.13.0",
|
"install": "^0.13.0",
|
||||||
"onesignal-expo-plugin": "^2.0.3",
|
"onesignal-expo-plugin": "^2.0.3",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
|
"react-i18next": "^15.0.1",
|
||||||
"react-native": "0.74.3",
|
"react-native": "0.74.3",
|
||||||
"react-native-autocomplete-dropdown": "3.1.5",
|
"react-native-autocomplete-dropdown": "3.1.5",
|
||||||
"react-native-calendar-picker": "^8.0.0",
|
"react-native-calendar-picker": "^8.0.0",
|
||||||
|
@ -52,6 +54,7 @@
|
||||||
"react-native-render-html": "^6.3.4",
|
"react-native-render-html": "^6.3.4",
|
||||||
"react-native-safe-area-context": "4.10.5",
|
"react-native-safe-area-context": "4.10.5",
|
||||||
"react-native-screens": "3.31.1",
|
"react-native-screens": "3.31.1",
|
||||||
|
"react-native-select-bottom-list": "^1.0.7",
|
||||||
"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",
|
||||||
|
|
34
yarn.lock
34
yarn.lock
|
@ -773,7 +773,7 @@
|
||||||
resolved "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz"
|
resolved "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz"
|
||||||
integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==
|
integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==
|
||||||
|
|
||||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.13.10", "@babel/runtime@^7.18.6", "@babel/runtime@^7.20.0":
|
"@babel/runtime@^7.0.0", "@babel/runtime@^7.13.10", "@babel/runtime@^7.18.6", "@babel/runtime@^7.20.0", "@babel/runtime@^7.23.2", "@babel/runtime@^7.24.8":
|
||||||
version "7.25.0"
|
version "7.25.0"
|
||||||
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz"
|
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz"
|
||||||
integrity sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==
|
integrity sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==
|
||||||
|
@ -4950,6 +4950,13 @@ html-escaper@^2.0.0:
|
||||||
resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz"
|
resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz"
|
||||||
integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
|
integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
|
||||||
|
|
||||||
|
html-parse-stringify@^3.0.1:
|
||||||
|
version "3.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2"
|
||||||
|
integrity sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==
|
||||||
|
dependencies:
|
||||||
|
void-elements "3.1.0"
|
||||||
|
|
||||||
htmlparser2@^7.1.2:
|
htmlparser2@^7.1.2:
|
||||||
version "7.2.0"
|
version "7.2.0"
|
||||||
resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz"
|
resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz"
|
||||||
|
@ -4998,6 +5005,13 @@ hyphenate-style-name@^1.0.3:
|
||||||
resolved "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz"
|
resolved "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz"
|
||||||
integrity sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==
|
integrity sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==
|
||||||
|
|
||||||
|
i18next@^23.12.2:
|
||||||
|
version "23.12.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/i18next/-/i18next-23.12.2.tgz#c5b44bb95e4d4a5908a51577fa06c63dc2f650a4"
|
||||||
|
integrity sha512-XIeh5V+bi8SJSWGL3jqbTEBW5oD6rbP5L+E7dVQh1MNTxxYef0x15rhJVcRb7oiuq4jLtgy2SD8eFlf6P2cmqg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.23.2"
|
||||||
|
|
||||||
iconv-lite@0.6.3, iconv-lite@^0.6.2:
|
iconv-lite@0.6.3, iconv-lite@^0.6.2:
|
||||||
version "0.6.3"
|
version "0.6.3"
|
||||||
resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz"
|
resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz"
|
||||||
|
@ -7380,6 +7394,14 @@ react-freeze@^1.0.0:
|
||||||
resolved "https://registry.npmjs.org/react-freeze/-/react-freeze-1.0.4.tgz"
|
resolved "https://registry.npmjs.org/react-freeze/-/react-freeze-1.0.4.tgz"
|
||||||
integrity sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA==
|
integrity sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA==
|
||||||
|
|
||||||
|
react-i18next@^15.0.1:
|
||||||
|
version "15.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-15.0.1.tgz#fc662d93829ecb39683fe2757a47ebfbc5c912a0"
|
||||||
|
integrity sha512-NwxLqNM6CLbeGA9xPsjits0EnXdKgCRSS6cgkgOdNcPXqL+1fYNl8fBg1wmnnHvFy812Bt4IWTPE9zjoPmFj3w==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.24.8"
|
||||||
|
html-parse-stringify "^3.0.1"
|
||||||
|
|
||||||
"react-is@^16.12.0 || ^17.0.0 || ^18.0.0", react-is@^16.13.0, react-is@^16.13.1, react-is@^16.7.0:
|
"react-is@^16.12.0 || ^17.0.0 || ^18.0.0", react-is@^16.13.0, react-is@^16.13.1, react-is@^16.7.0:
|
||||||
version "16.13.1"
|
version "16.13.1"
|
||||||
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
|
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
|
||||||
|
@ -7520,6 +7542,11 @@ react-native-screens@3.31.1:
|
||||||
react-freeze "^1.0.0"
|
react-freeze "^1.0.0"
|
||||||
warn-once "^0.1.0"
|
warn-once "^0.1.0"
|
||||||
|
|
||||||
|
react-native-select-bottom-list@^1.0.7:
|
||||||
|
version "1.0.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-native-select-bottom-list/-/react-native-select-bottom-list-1.0.7.tgz#ef4c9f2520218c442a70c5000fd74e1a12030722"
|
||||||
|
integrity sha512-yzdQwchhdi1lZO973jxOkRF9BksWK/uzVZBoYUENkWYoLumSIR6iozUiFcpAGpy06XFtvy2dJtM7K3Wah2JpzA==
|
||||||
|
|
||||||
react-native-size-matters@^0.4.0:
|
react-native-size-matters@^0.4.0:
|
||||||
version "0.4.2"
|
version "0.4.2"
|
||||||
resolved "https://registry.npmjs.org/react-native-size-matters/-/react-native-size-matters-0.4.2.tgz"
|
resolved "https://registry.npmjs.org/react-native-size-matters/-/react-native-size-matters-0.4.2.tgz"
|
||||||
|
@ -9017,6 +9044,11 @@ vlq@^1.0.0:
|
||||||
resolved "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz"
|
resolved "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz"
|
||||||
integrity sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==
|
integrity sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==
|
||||||
|
|
||||||
|
void-elements@3.1.0:
|
||||||
|
version "3.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09"
|
||||||
|
integrity sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==
|
||||||
|
|
||||||
w3c-xmlserializer@^4.0.0:
|
w3c-xmlserializer@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz"
|
resolved "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue