feat: enhance configuration management, add update checks, and improve UI components
This commit is contained in:
12
.env.example
12
.env.example
@@ -1,4 +1,10 @@
|
|||||||
EXPO_PUBLIC_API_URL=[YOUR_API_URL]
|
EXPO_PUBLIC_API_URL=[YOUR_API_URL] # backend API URL (used for development, it overrides the one provided by the gateway)
|
||||||
EXPO_PUBLIC_HA_API_URL=[YOUR_HOME_ASSISTANT_API_URL]
|
|
||||||
EXPO_PUBLIC_HA_TOKEN=[YOUR_HOME_ASSISTANT_TOKEN]
|
EXPO_PUBLIC_HA_API_URL=[YOUR_HOME_ASSISTANT_API_URL] # Home Assistant API URL
|
||||||
|
EXPO_PUBLIC_HA_TOKEN=[YOUR_HOME_ASSISTANT_TOKEN] # Home Assistant Long-Lived Access Token
|
||||||
|
|
||||||
EXPO_PUBLIC_ENABLE_NFC=[true|false]
|
EXPO_PUBLIC_ENABLE_NFC=[true|false]
|
||||||
|
|
||||||
|
EXPO_PUBLIC_GW_API_URL=[YOUR_GW_API_URL] # Gateway API URL
|
||||||
|
EXPO_PUBLIC_GW_UUID=[YOUR_GW_UUID] # Gateway UUID
|
||||||
|
EXPO_PUBLIC_GW_API_TOKEN=[YOUR_GW_API_TOKEN] # Gateway API Token
|
||||||
@@ -2,7 +2,7 @@ import { Redirect, Tabs } from 'expo-router';
|
|||||||
import { Home, Clock, Zap, CalendarIcon, Building } from 'lucide-react-native';
|
import { Home, Clock, Zap, CalendarIcon, Building } from 'lucide-react-native';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import { AuthContext } from '@/utils/authContext';
|
import { AuthContext } from '@/utils/authContext';
|
||||||
import {useSafeAreaInsets} from "react-native-safe-area-context";
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||||
|
|
||||||
export default function ProtectedLayout() {
|
export default function ProtectedLayout() {
|
||||||
const authState = useContext(AuthContext);
|
const authState = useContext(AuthContext);
|
||||||
@@ -32,9 +32,9 @@ export default function ProtectedLayout() {
|
|||||||
tabBarActiveTintColor: '#099499',
|
tabBarActiveTintColor: '#099499',
|
||||||
tabBarInactiveTintColor: '#9ca3af',
|
tabBarInactiveTintColor: '#9ca3af',
|
||||||
tabBarLabelStyle: {
|
tabBarLabelStyle: {
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: '600',
|
fontWeight: '600',
|
||||||
marginTop: 4
|
marginTop: 4
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
backBehavior='history'
|
backBehavior='history'
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ export default function PermitsScreen() {
|
|||||||
const deletePermitRequest = async (id: number, itemRef?: React.ElementRef<typeof Swipeable> | null) => {
|
const deletePermitRequest = async (id: number, itemRef?: React.ElementRef<typeof Swipeable> | null) => {
|
||||||
try {
|
try {
|
||||||
itemRef?.close();
|
itemRef?.close();
|
||||||
await api.post(`/time-off-request/delete-request`, {id: id});
|
await api.post(`/time-off-request/delete-request`, { id: id });
|
||||||
// Optimistic update
|
// Optimistic update
|
||||||
setPermits(prevPermits => prevPermits.filter(p => p.id !== id));
|
setPermits(prevPermits => prevPermits.filter(p => p.id !== id));
|
||||||
alert.showAlert('success', 'Richiesta eliminata', 'La richiesta è stata eliminata con successo.');
|
alert.showAlert('success', 'Richiesta eliminata', 'La richiesta è stata eliminata con successo.');
|
||||||
@@ -136,7 +136,7 @@ export default function PermitsScreen() {
|
|||||||
onPress={() => confirmDelete(item, swipeableRef.current)}
|
onPress={() => confirmDelete(item, swipeableRef.current)}
|
||||||
className="bg-red-500 justify-center items-center px-6 rounded-3xl ml-3"
|
className="bg-red-500 justify-center items-center px-6 rounded-3xl ml-3"
|
||||||
activeOpacity={0.7}
|
activeOpacity={0.7}
|
||||||
style={{margin: 2}}
|
style={{ margin: 2 }}
|
||||||
>
|
>
|
||||||
<View className="items-center gap-1">
|
<View className="items-center gap-1">
|
||||||
<Trash2 size={24} color="white" strokeWidth={2.5} pointerEvents="none" />
|
<Trash2 size={24} color="white" strokeWidth={2.5} pointerEvents="none" />
|
||||||
@@ -196,23 +196,28 @@ export default function PermitsScreen() {
|
|||||||
<View className={`p-4 rounded-2xl`} style={{ backgroundColor: item.timeOffRequestType.color ? `${item.timeOffRequestType.color}25` : '#E5E7EB' }}>
|
<View className={`p-4 rounded-2xl`} style={{ backgroundColor: item.timeOffRequestType.color ? `${item.timeOffRequestType.color}25` : '#E5E7EB' }}>
|
||||||
{typeIcons[item.timeOffRequestType.name]?.(item.timeOffRequestType.color)}
|
{typeIcons[item.timeOffRequestType.name]?.(item.timeOffRequestType.color)}
|
||||||
</View>
|
</View>
|
||||||
<View>
|
<View className='flex-1'>
|
||||||
<Text className="font-bold text-gray-800 text-lg">{item.timeOffRequestType.name}</Text>
|
<View className="flex-row justify-between items-center">
|
||||||
|
<Text className="font-bold text-gray-800 text-lg">{item.timeOffRequestType.name}</Text>
|
||||||
|
<View className={`px-3 py-1.5 rounded-lg ${item.status === 1 ? 'bg-green-100' : item.status === 0 ? 'bg-red-100' : 'bg-yellow-100'}`}>
|
||||||
|
<Text className={`text-xs font-bold uppercase tracking-wide ${item.status === 1 ? 'text-green-700' : item.status === 0 ? 'text-red-700' : 'text-yellow-700'}`}>
|
||||||
|
{item.status === 1 ? 'Approvata' : item.status === 0 ? 'Rifiutata' : 'In Attesa'}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Text className="text-sm text-gray-600 mt-0.5 leading-tight">{item.message}</Text>
|
||||||
<Text className="text-base text-gray-500 mt-0.5">
|
<Text className="text-base text-gray-500 mt-0.5">
|
||||||
{formatDate(item.start_date?.toLocaleString())} {item.end_date ? `- ${formatDate(item.end_date.toLocaleString())}` : ''}
|
{formatDate(item.start_date?.toLocaleString())} {item.end_date ? `- ${formatDate(item.end_date.toLocaleString())}` : ''}
|
||||||
</Text>
|
</Text>
|
||||||
{item.timeOffRequestType.name === 'Permesso' && (
|
{item.timeOffRequestType.name === 'Permesso' && (
|
||||||
<Text className="text-sm text-orange-600 font-bold mt-1">
|
<Text className="text-sm text-orange-600 font-bold mt-0.5">
|
||||||
{formatTime(item.start_time)} - {formatTime(item.end_time)}
|
{formatTime(item.start_time)} - {formatTime(item.end_time)}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<View className={`px-3 py-1.5 rounded-lg ${item.status===1 ? 'bg-green-100' : item.status===0 ? 'bg-red-100' : 'bg-yellow-100'}`}>
|
|
||||||
<Text className={`text-xs font-bold uppercase tracking-wide ${item.status===1 ? 'text-green-700' : item.status===0 ? 'text-red-700' : 'text-yellow-700'}`}>
|
|
||||||
{item.status===1 ? 'Approvata' : item.status===0 ? 'Rifiutata' : 'In Attesa'}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -228,7 +233,7 @@ export default function PermitsScreen() {
|
|||||||
rightThreshold={40}
|
rightThreshold={40}
|
||||||
friction={2}
|
friction={2}
|
||||||
overshootFriction={8}
|
overshootFriction={8}
|
||||||
containerStyle={{padding: 2}}
|
containerStyle={{ padding: 2 }}
|
||||||
>
|
>
|
||||||
{cardContent}
|
{cardContent}
|
||||||
</Swipeable>
|
</Swipeable>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ export default function ProfileLayout() {
|
|||||||
return (
|
return (
|
||||||
<Stack screenOptions={{headerShown: false}}>
|
<Stack screenOptions={{headerShown: false}}>
|
||||||
<Stack.Screen name="index" />
|
<Stack.Screen name="index" />
|
||||||
<Stack.Screen name="documents" />
|
<Stack.Screen name="documents" options={{ animation: 'slide_from_right' }} />
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,8 @@ import { AlertProvider } from '@/components/AlertComponent';
|
|||||||
import { NetworkProvider } from '@/utils/networkProvider';
|
import { NetworkProvider } from '@/utils/networkProvider';
|
||||||
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||||
import { KeyboardProvider } from "react-native-keyboard-controller";
|
import { KeyboardProvider } from "react-native-keyboard-controller";
|
||||||
import {GestureHandlerRootView} from "react-native-gesture-handler";
|
import { GestureHandlerRootView } from "react-native-gesture-handler";
|
||||||
|
import { ConfigProvider } from '@/utils/configProvider';
|
||||||
|
|
||||||
export default function AppLayout() {
|
export default function AppLayout() {
|
||||||
return (
|
return (
|
||||||
@@ -13,14 +14,16 @@ export default function AppLayout() {
|
|||||||
<GestureHandlerRootView>
|
<GestureHandlerRootView>
|
||||||
<KeyboardProvider>
|
<KeyboardProvider>
|
||||||
<NetworkProvider>
|
<NetworkProvider>
|
||||||
<AuthProvider>
|
<ConfigProvider>
|
||||||
<AlertProvider>
|
<AuthProvider>
|
||||||
<Stack screenOptions={{ headerShown: false, animation: 'flip' }}>
|
<AlertProvider>
|
||||||
<Stack.Screen name="(protected)" />
|
<Stack screenOptions={{ headerShown: false, animation: 'flip' }}>
|
||||||
<Stack.Screen name="login" />
|
<Stack.Screen name="(protected)" />
|
||||||
</Stack>
|
<Stack.Screen name="login" />
|
||||||
</AlertProvider>
|
</Stack>
|
||||||
</AuthProvider>
|
</AlertProvider>
|
||||||
|
</AuthProvider>
|
||||||
|
</ConfigProvider>
|
||||||
</NetworkProvider>
|
</NetworkProvider>
|
||||||
</KeyboardProvider>
|
</KeyboardProvider>
|
||||||
</GestureHandlerRootView>
|
</GestureHandlerRootView>
|
||||||
|
|||||||
@@ -64,6 +64,8 @@ export default function RequestPermitModal({ visible, types, onClose, onSubmit }
|
|||||||
|
|
||||||
if (response.data.status === 'success') {
|
if (response.data.status === 'success') {
|
||||||
alert.showAlert('success', 'Successo', response.data.message || 'La tua richiesta è stata inviata con successo.');
|
alert.showAlert('success', 'Successo', response.data.message || 'La tua richiesta è stata inviata con successo.');
|
||||||
|
onSubmit(requestData);
|
||||||
|
onClose();
|
||||||
} else {
|
} else {
|
||||||
alert.showAlert('error', 'Errore', response.data.message || 'Impossibile inviare la richiesta.');
|
alert.showAlert('error', 'Errore', response.data.message || 'Impossibile inviare la richiesta.');
|
||||||
}
|
}
|
||||||
@@ -92,8 +94,6 @@ export default function RequestPermitModal({ visible, types, onClose, onSubmit }
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await saveRequest(requestData);
|
await saveRequest(requestData);
|
||||||
onSubmit(requestData);
|
|
||||||
onClose();
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
alert.showAlert("error", "Errore", "Impossibile inviare la richiesta.");
|
alert.showAlert("error", "Errore", "Impossibile inviare la richiesta.");
|
||||||
}
|
}
|
||||||
|
|||||||
43
components/UpdateScreen.tsx
Normal file
43
components/UpdateScreen.tsx
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { View, Text, TouchableOpacity } from 'react-native';
|
||||||
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||||
|
import { CloudDownload } from 'lucide-react-native';
|
||||||
|
|
||||||
|
interface UpdateScreenProps {
|
||||||
|
onUpdate: () => void;
|
||||||
|
isOpeningStore?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function UpdateScreen({ onUpdate, isOpeningStore = false }: UpdateScreenProps) {
|
||||||
|
return (
|
||||||
|
<SafeAreaView className="flex-1 bg-white">
|
||||||
|
<View className="flex-1 items-center justify-center px-8">
|
||||||
|
{/* Icon */}
|
||||||
|
<View className="bg-gray-100 p-6 rounded-full mb-6">
|
||||||
|
<CloudDownload size={64} className="text-[#099499]" pointerEvents="none" />
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Text className="text-2xl font-bold text-gray-800 mb-2 text-center">
|
||||||
|
Aggiornamento Richiesto
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Text className="text-base text-gray-500 text-center mb-10 leading-6">
|
||||||
|
È disponibile una nuova versione dell'applicazione.{'\n'}Per continuare a utilizzarla è necessario effettuare l'aggiornamento.
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
{/* Update Button */}
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={onUpdate}
|
||||||
|
disabled={isOpeningStore}
|
||||||
|
className={`flex-row items-center justify-center w-full py-4 rounded-xl gap-4 ${
|
||||||
|
isOpeningStore ? 'bg-gray-300' : 'bg-[#099499] active:bg-[#077f83]'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<Text className="text-white font-bold text-lg">
|
||||||
|
{isOpeningStore ? 'Apertura store...' : 'Aggiorna Ora'}
|
||||||
|
</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
</SafeAreaView>
|
||||||
|
);
|
||||||
|
}
|
||||||
44
package-lock.json
generated
44
package-lock.json
generated
@@ -111,6 +111,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
|
||||||
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
|
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.27.1",
|
"@babel/code-frame": "^7.27.1",
|
||||||
"@babel/generator": "^7.28.5",
|
"@babel/generator": "^7.28.5",
|
||||||
@@ -1492,6 +1493,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz",
|
||||||
"integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==",
|
"integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
@@ -3164,6 +3166,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.1.25.tgz",
|
"resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.1.25.tgz",
|
||||||
"integrity": "sha512-zQeWK9txDePWbYfqTs0C6jeRdJTm/7VhQtW/1IbJNDi9/rFIRzZule8bdQPAnf8QWUsNujRmi1J9OG/hhfbalg==",
|
"integrity": "sha512-zQeWK9txDePWbYfqTs0C6jeRdJTm/7VhQtW/1IbJNDi9/rFIRzZule8bdQPAnf8QWUsNujRmi1J9OG/hhfbalg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-navigation/core": "^7.13.6",
|
"@react-navigation/core": "^7.13.6",
|
||||||
"escape-string-regexp": "^4.0.0",
|
"escape-string-regexp": "^4.0.0",
|
||||||
@@ -3362,6 +3365,7 @@
|
|||||||
"integrity": "sha512-Qec1E3mhALmaspIrhWt9jkQMNdw6bReVu64mjvhbhq2NFPftLPVr+l1SZgmw/66WwBNpDh7ao5AT6gF5v41PFA==",
|
"integrity": "sha512-Qec1E3mhALmaspIrhWt9jkQMNdw6bReVu64mjvhbhq2NFPftLPVr+l1SZgmw/66WwBNpDh7ao5AT6gF5v41PFA==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"csstype": "^3.0.2"
|
"csstype": "^3.0.2"
|
||||||
}
|
}
|
||||||
@@ -3432,6 +3436,7 @@
|
|||||||
"integrity": "sha512-N9lBGA9o9aqb1hVMc9hzySbhKibHmB+N3IpoShyV6HyQYRGIhlrO5rQgttypi+yEeKsKI4idxC8Jw6gXKD4THA==",
|
"integrity": "sha512-N9lBGA9o9aqb1hVMc9hzySbhKibHmB+N3IpoShyV6HyQYRGIhlrO5rQgttypi+yEeKsKI4idxC8Jw6gXKD4THA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.49.0",
|
"@typescript-eslint/scope-manager": "8.49.0",
|
||||||
"@typescript-eslint/types": "8.49.0",
|
"@typescript-eslint/types": "8.49.0",
|
||||||
@@ -3993,6 +3998,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@@ -4655,8 +4661,7 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||||
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
|
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
|
||||||
"license": "ISC",
|
"license": "ISC"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/bplist-creator": {
|
"node_modules/bplist-creator": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
@@ -4720,6 +4725,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.9.0",
|
"baseline-browser-mapping": "^2.9.0",
|
||||||
"caniuse-lite": "^1.0.30001759",
|
"caniuse-lite": "^1.0.30001759",
|
||||||
@@ -5280,7 +5286,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
|
||||||
"integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==",
|
"integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"boolbase": "^1.0.0",
|
"boolbase": "^1.0.0",
|
||||||
"css-what": "^6.1.0",
|
"css-what": "^6.1.0",
|
||||||
@@ -5297,7 +5302,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
|
||||||
"integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
|
"integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"mdn-data": "2.0.14",
|
"mdn-data": "2.0.14",
|
||||||
"source-map": "^0.6.1"
|
"source-map": "^0.6.1"
|
||||||
@@ -5311,7 +5315,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -5321,7 +5324,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz",
|
||||||
"integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==",
|
"integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
},
|
},
|
||||||
@@ -5589,7 +5591,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
||||||
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"domelementtype": "^2.3.0",
|
"domelementtype": "^2.3.0",
|
||||||
"domhandler": "^5.0.2",
|
"domhandler": "^5.0.2",
|
||||||
@@ -5609,15 +5610,13 @@
|
|||||||
"url": "https://github.com/sponsors/fb55"
|
"url": "https://github.com/sponsors/fb55"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/domhandler": {
|
"node_modules/domhandler": {
|
||||||
"version": "5.0.3",
|
"version": "5.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
||||||
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"domelementtype": "^2.3.0"
|
"domelementtype": "^2.3.0"
|
||||||
},
|
},
|
||||||
@@ -5633,7 +5632,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
|
||||||
"integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
|
"integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dom-serializer": "^2.0.0",
|
"dom-serializer": "^2.0.0",
|
||||||
"domelementtype": "^2.3.0",
|
"domelementtype": "^2.3.0",
|
||||||
@@ -5716,7 +5714,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||||
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.12"
|
"node": ">=0.12"
|
||||||
},
|
},
|
||||||
@@ -5948,6 +5945,7 @@
|
|||||||
"integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==",
|
"integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.8.0",
|
"@eslint-community/eslint-utils": "^4.8.0",
|
||||||
"@eslint-community/regexpp": "^4.12.1",
|
"@eslint-community/regexpp": "^4.12.1",
|
||||||
@@ -6144,6 +6142,7 @@
|
|||||||
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rtsao/scc": "^1.1.0",
|
"@rtsao/scc": "^1.1.0",
|
||||||
"array-includes": "^3.1.9",
|
"array-includes": "^3.1.9",
|
||||||
@@ -6382,6 +6381,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/expo/-/expo-54.0.27.tgz",
|
"resolved": "https://registry.npmjs.org/expo/-/expo-54.0.27.tgz",
|
||||||
"integrity": "sha512-50BcJs8eqGwRiMUoWwphkRGYtKFS2bBnemxLzy0lrGVA1E6F4Q7L5h3WT6w1ehEZybtOVkfJu4Z6GWo2IJcpEA==",
|
"integrity": "sha512-50BcJs8eqGwRiMUoWwphkRGYtKFS2bBnemxLzy0lrGVA1E6F4Q7L5h3WT6w1ehEZybtOVkfJu4Z6GWo2IJcpEA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.0",
|
"@babel/runtime": "^7.20.0",
|
||||||
"@expo/cli": "54.0.18",
|
"@expo/cli": "54.0.18",
|
||||||
@@ -6469,6 +6469,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-18.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-18.0.11.tgz",
|
||||||
"integrity": "sha512-xnfrfZ7lHjb+03skhmDSYeFF7OU2K3Xn/lAeP+7RhkV2xp2f5RCKtOUYajCnYeZesvMrsUxOsbGOP2JXSOH3NA==",
|
"integrity": "sha512-xnfrfZ7lHjb+03skhmDSYeFF7OU2K3Xn/lAeP+7RhkV2xp2f5RCKtOUYajCnYeZesvMrsUxOsbGOP2JXSOH3NA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expo/config": "~12.0.11",
|
"@expo/config": "~12.0.11",
|
||||||
"@expo/env": "~2.0.8"
|
"@expo/env": "~2.0.8"
|
||||||
@@ -6575,6 +6576,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/expo-font/-/expo-font-14.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/expo-font/-/expo-font-14.0.10.tgz",
|
||||||
"integrity": "sha512-UqyNaaLKRpj4pKAP4HZSLnuDQqueaO5tB1c/NWu5vh1/LF9ulItyyg2kF/IpeOp0DeOLk0GY0HrIXaKUMrwB+Q==",
|
"integrity": "sha512-UqyNaaLKRpj4pKAP4HZSLnuDQqueaO5tB1c/NWu5vh1/LF9ulItyyg2kF/IpeOp0DeOLk0GY0HrIXaKUMrwB+Q==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fontfaceobserver": "^2.1.0"
|
"fontfaceobserver": "^2.1.0"
|
||||||
},
|
},
|
||||||
@@ -8852,6 +8854,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
|
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
|
||||||
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
|
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"jiti": "bin/jiti.js"
|
"jiti": "bin/jiti.js"
|
||||||
}
|
}
|
||||||
@@ -9467,8 +9470,7 @@
|
|||||||
"version": "2.0.14",
|
"version": "2.0.14",
|
||||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
|
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
|
||||||
"integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
|
"integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
|
||||||
"license": "CC0-1.0",
|
"license": "CC0-1.0"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/memoize-one": {
|
"node_modules/memoize-one": {
|
||||||
"version": "5.2.1",
|
"version": "5.2.1",
|
||||||
@@ -10083,7 +10085,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
|
||||||
"integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
|
"integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"boolbase": "^1.0.0"
|
"boolbase": "^1.0.0"
|
||||||
},
|
},
|
||||||
@@ -10662,6 +10663,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.7",
|
"nanoid": "^3.3.7",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
@@ -11110,6 +11112,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
|
||||||
"integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
|
"integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -11129,6 +11132,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
|
||||||
"integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
|
"integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"scheduler": "^0.26.0"
|
"scheduler": "^0.26.0"
|
||||||
},
|
},
|
||||||
@@ -11165,6 +11169,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.81.5.tgz",
|
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.81.5.tgz",
|
||||||
"integrity": "sha512-1w+/oSjEXZjMqsIvmkCRsOc8UBYv163bTWKTI8+1mxztvQPhCRYGTvZ/PL1w16xXHneIj/SLGfxWg2GWN2uexw==",
|
"integrity": "sha512-1w+/oSjEXZjMqsIvmkCRsOc8UBYv163bTWKTI8+1mxztvQPhCRYGTvZ/PL1w16xXHneIj/SLGfxWg2GWN2uexw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jest/create-cache-key-function": "^29.7.0",
|
"@jest/create-cache-key-function": "^29.7.0",
|
||||||
"@react-native/assets-registry": "0.81.5",
|
"@react-native/assets-registry": "0.81.5",
|
||||||
@@ -11505,6 +11510,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.28.0.tgz",
|
||||||
"integrity": "sha512-0msfJ1vRxXKVgTgvL+1ZOoYw3/0z1R+Ked0+udoJhyplC2jbVKIJ8Z1bzWdpQRCV3QcQ87Op0zJVE5DhKK2A0A==",
|
"integrity": "sha512-0msfJ1vRxXKVgTgvL+1ZOoYw3/0z1R+Ked0+udoJhyplC2jbVKIJ8Z1bzWdpQRCV3QcQ87Op0zJVE5DhKK2A0A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@egjs/hammerjs": "^2.0.17",
|
"@egjs/hammerjs": "^2.0.17",
|
||||||
"hoist-non-react-statics": "^3.3.0",
|
"hoist-non-react-statics": "^3.3.0",
|
||||||
@@ -11558,6 +11564,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-4.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-4.1.6.tgz",
|
||||||
"integrity": "sha512-F+ZJBYiok/6Jzp1re75F/9aLzkgoQCOh4yxrnwATa8392RvM3kx+fiXXFvwcgE59v48lMwd9q0nzF1oJLXpfxQ==",
|
"integrity": "sha512-F+ZJBYiok/6Jzp1re75F/9aLzkgoQCOh4yxrnwATa8392RvM3kx+fiXXFvwcgE59v48lMwd9q0nzF1oJLXpfxQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react-native-is-edge-to-edge": "^1.2.1",
|
"react-native-is-edge-to-edge": "^1.2.1",
|
||||||
"semver": "7.7.2"
|
"semver": "7.7.2"
|
||||||
@@ -11586,6 +11593,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.6.2.tgz",
|
||||||
"integrity": "sha512-4XGqMNj5qjUTYywJqpdWZ9IG8jgkS3h06sfVjfw5yZQZfWnRFXczi0GnYyFyCc2EBps/qFmoCH8fez//WumdVg==",
|
"integrity": "sha512-4XGqMNj5qjUTYywJqpdWZ9IG8jgkS3h06sfVjfw5yZQZfWnRFXczi0GnYyFyCc2EBps/qFmoCH8fez//WumdVg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "*",
|
"react": "*",
|
||||||
"react-native": "*"
|
"react-native": "*"
|
||||||
@@ -11596,6 +11604,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.16.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.16.0.tgz",
|
||||||
"integrity": "sha512-yIAyh7F/9uWkOzCi1/2FqvNvK6Wb9Y1+Kzn16SuGfN9YFJDTbwlzGRvePCNTOX0recpLQF3kc2FmvMUhyTCH1Q==",
|
"integrity": "sha512-yIAyh7F/9uWkOzCi1/2FqvNvK6Wb9Y1+Kzn16SuGfN9YFJDTbwlzGRvePCNTOX0recpLQF3kc2FmvMUhyTCH1Q==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react-freeze": "^1.0.0",
|
"react-freeze": "^1.0.0",
|
||||||
"react-native-is-edge-to-edge": "^1.2.1",
|
"react-native-is-edge-to-edge": "^1.2.1",
|
||||||
@@ -11647,6 +11656,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.21.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.21.2.tgz",
|
||||||
"integrity": "sha512-SO2t9/17zM4iEnFvlu2DA9jqNbzNhoUP+AItkoCOyFmDMOhUnBBznBDCYN92fGdfAkfQlWzPoez6+zLxFNsZEg==",
|
"integrity": "sha512-SO2t9/17zM4iEnFvlu2DA9jqNbzNhoUP+AItkoCOyFmDMOhUnBBznBDCYN92fGdfAkfQlWzPoez6+zLxFNsZEg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.18.6",
|
"@babel/runtime": "^7.18.6",
|
||||||
"@react-native/normalize-colors": "^0.74.1",
|
"@react-native/normalize-colors": "^0.74.1",
|
||||||
@@ -11789,6 +11799,7 @@
|
|||||||
"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",
|
||||||
"integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==",
|
"integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -12986,6 +12997,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.18.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.18.tgz",
|
||||||
"integrity": "sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==",
|
"integrity": "sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alloc/quick-lru": "^5.2.0",
|
"@alloc/quick-lru": "^5.2.0",
|
||||||
"arg": "^5.0.2",
|
"arg": "^5.0.2",
|
||||||
@@ -13192,6 +13204,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@@ -13398,6 +13411,7 @@
|
|||||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
|
|||||||
@@ -14,6 +14,14 @@ const api = axios.create({
|
|||||||
timeout: 10000, // 10 seconds timeout
|
timeout: 10000, // 10 seconds timeout
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Export function to update base URL
|
||||||
|
export const setApiBaseUrl = (url: string) => {
|
||||||
|
if (url) {
|
||||||
|
api.defaults.baseURL = url;
|
||||||
|
console.log(`[API] Base URL updated to: ${url}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Interceptor: Adds the token to EVERY request if it exists
|
// Interceptor: Adds the token to EVERY request if it exists
|
||||||
api.interceptors.request.use(
|
api.interceptors.request.use(
|
||||||
async (config) => {
|
async (config) => {
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export function AuthProvider({ children }: PropsWithChildren) {
|
|||||||
const savedToken = await SecureStore.getItemAsync(KEY_TOKEN);
|
const savedToken = await SecureStore.getItemAsync(KEY_TOKEN);
|
||||||
|
|
||||||
if (savedToken) {
|
if (savedToken) {
|
||||||
console.log("Token trovato: ", savedToken);
|
console.log("Token trovato:", savedToken);
|
||||||
|
|
||||||
// Call backend to verify token and fetch user data
|
// Call backend to verify token and fetch user data
|
||||||
// Note: api.ts already adds the Authorization header thanks to the interceptor (if configured to read from SecureStore)
|
// Note: api.ts already adds the Authorization header thanks to the interceptor (if configured to read from SecureStore)
|
||||||
|
|||||||
87
utils/configProvider.tsx
Normal file
87
utils/configProvider.tsx
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
import React, { createContext, useState, useEffect, ReactNode } from 'react';
|
||||||
|
import { Linking, Platform } from 'react-native';
|
||||||
|
import Constants from 'expo-constants';
|
||||||
|
import axios from 'axios';
|
||||||
|
import LoadingScreen from '@/components/LoadingScreen';
|
||||||
|
import UpdateScreen from '@/components/UpdateScreen';
|
||||||
|
import { isUpdateAvailable } from '@/utils/version';
|
||||||
|
import { setApiBaseUrl } from './api';
|
||||||
|
|
||||||
|
interface ConfigContextProps {
|
||||||
|
children: ReactNode
|
||||||
|
};
|
||||||
|
|
||||||
|
// Context (useful if you want to trigger manual checks from inside the app in the future)
|
||||||
|
export const ConfigContext = createContext({});
|
||||||
|
|
||||||
|
const GW_API = process.env.EXPO_PUBLIC_GW_API_URL;
|
||||||
|
const GW_UUID = process.env.EXPO_PUBLIC_GW_UUID;
|
||||||
|
const GW_TOKEN = process.env.EXPO_PUBLIC_GW_API_TOKEN;
|
||||||
|
|
||||||
|
export const ConfigProvider = ({ children }: ConfigContextProps) => {
|
||||||
|
const [isChecking, setIsChecking] = useState(true);
|
||||||
|
const [needsUpdate, setNeedsUpdate] = useState(false);
|
||||||
|
const [updateUrl, setUpdateUrl] = useState('');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const checkAppVersion = async () => {
|
||||||
|
try {
|
||||||
|
|
||||||
|
const apiUrl = `${GW_API}${GW_UUID}`;
|
||||||
|
const response = await axios.get(apiUrl, {
|
||||||
|
headers: { "x-access-tokens": GW_TOKEN }
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update API URL: prioritize environment variable (override) over gateway response
|
||||||
|
setApiBaseUrl(process.env.EXPO_PUBLIC_API_URL || response.data.url);
|
||||||
|
|
||||||
|
const currentVersion = Constants.expoConfig?.version;
|
||||||
|
console.log("Versione attuale dell'app:", currentVersion);
|
||||||
|
|
||||||
|
const latestVersion = response.data.version;
|
||||||
|
console.log("Versione più recente disponibile:", latestVersion);
|
||||||
|
|
||||||
|
// Check if an update is needed
|
||||||
|
if (isUpdateAvailable(currentVersion, latestVersion)) {
|
||||||
|
setNeedsUpdate(true);
|
||||||
|
setUpdateUrl(Platform.OS === 'ios' ? response.data.app_url_ios : response.data.app_url_android);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Errore durante il controllo della versione:", error);
|
||||||
|
setNeedsUpdate(false);
|
||||||
|
} finally {
|
||||||
|
setIsChecking(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
checkAppVersion();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleUpdate = async () => {
|
||||||
|
if (updateUrl) {
|
||||||
|
Linking.openURL(updateUrl);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Loading state
|
||||||
|
if (isChecking) {
|
||||||
|
return (
|
||||||
|
<LoadingScreen />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update state: blocks children rendering
|
||||||
|
if (needsUpdate) {
|
||||||
|
return (
|
||||||
|
<UpdateScreen onUpdate={handleUpdate} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version is up to date
|
||||||
|
return (
|
||||||
|
<ConfigContext.Provider value={{ isChecking, needsUpdate }}>
|
||||||
|
{children}
|
||||||
|
</ConfigContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
27
utils/version.ts
Normal file
27
utils/version.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* Compare two version strings.
|
||||||
|
* Returns true if 'latest' is greater than 'current' (an update is available).
|
||||||
|
*/
|
||||||
|
export const isUpdateAvailable = (currentVersion: string | undefined, latestVersion: string) => {
|
||||||
|
if (!currentVersion || !latestVersion) return false;
|
||||||
|
|
||||||
|
// Split strings into an array of numbers: "1.2.10" -> [1, 2, 10]
|
||||||
|
const currentParts = currentVersion.split('.').map(Number);
|
||||||
|
const latestParts = latestVersion.split('.').map(Number);
|
||||||
|
const maxLength = Math.max(currentParts.length, latestParts.length);
|
||||||
|
|
||||||
|
for (let i = 0; i < maxLength; i++) {
|
||||||
|
// If a part is missing, we consider it as 0 (e.g. "1.0" -> [1, 0, 0])
|
||||||
|
const current = currentParts[i] || 0;
|
||||||
|
const latest = latestParts[i] || 0;
|
||||||
|
|
||||||
|
if (current < latest) {
|
||||||
|
return true; // It needs an update
|
||||||
|
}
|
||||||
|
if (current > latest) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user