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_HA_API_URL=[YOUR_HOME_ASSISTANT_API_URL]
|
||||
EXPO_PUBLIC_HA_TOKEN=[YOUR_HOME_ASSISTANT_TOKEN]
|
||||
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] # 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_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
|
||||
@@ -196,24 +196,29 @@ export default function PermitsScreen() {
|
||||
<View className={`p-4 rounded-2xl`} style={{ backgroundColor: item.timeOffRequestType.color ? `${item.timeOffRequestType.color}25` : '#E5E7EB' }}>
|
||||
{typeIcons[item.timeOffRequestType.name]?.(item.timeOffRequestType.color)}
|
||||
</View>
|
||||
<View>
|
||||
<View className='flex-1'>
|
||||
<View className="flex-row justify-between items-center">
|
||||
<Text className="font-bold text-gray-800 text-lg">{item.timeOffRequestType.name}</Text>
|
||||
<Text className="text-base text-gray-500 mt-0.5">
|
||||
{formatDate(item.start_date?.toLocaleString())} {item.end_date ? `- ${formatDate(item.end_date.toLocaleString())}` : ''}
|
||||
</Text>
|
||||
{item.timeOffRequestType.name === 'Permesso' && (
|
||||
<Text className="text-sm text-orange-600 font-bold mt-1">
|
||||
{formatTime(item.start_time)} - {formatTime(item.end_time)}
|
||||
</Text>
|
||||
)}
|
||||
</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>
|
||||
|
||||
<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">
|
||||
{formatDate(item.start_date?.toLocaleString())} {item.end_date ? `- ${formatDate(item.end_date.toLocaleString())}` : ''}
|
||||
</Text>
|
||||
{item.timeOffRequestType.name === 'Permesso' && (
|
||||
<Text className="text-sm text-orange-600 font-bold mt-0.5">
|
||||
{formatTime(item.start_time)} - {formatTime(item.end_time)}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
</View>
|
||||
);
|
||||
|
||||
// Wrappa solo richieste "In Attesa" con Swipeable
|
||||
|
||||
@@ -4,7 +4,7 @@ export default function ProfileLayout() {
|
||||
return (
|
||||
<Stack screenOptions={{headerShown: false}}>
|
||||
<Stack.Screen name="index" />
|
||||
<Stack.Screen name="documents" />
|
||||
<Stack.Screen name="documents" options={{ animation: 'slide_from_right' }} />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import { NetworkProvider } from '@/utils/networkProvider';
|
||||
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||
import { KeyboardProvider } from "react-native-keyboard-controller";
|
||||
import { GestureHandlerRootView } from "react-native-gesture-handler";
|
||||
import { ConfigProvider } from '@/utils/configProvider';
|
||||
|
||||
export default function AppLayout() {
|
||||
return (
|
||||
@@ -13,6 +14,7 @@ export default function AppLayout() {
|
||||
<GestureHandlerRootView>
|
||||
<KeyboardProvider>
|
||||
<NetworkProvider>
|
||||
<ConfigProvider>
|
||||
<AuthProvider>
|
||||
<AlertProvider>
|
||||
<Stack screenOptions={{ headerShown: false, animation: 'flip' }}>
|
||||
@@ -21,6 +23,7 @@ export default function AppLayout() {
|
||||
</Stack>
|
||||
</AlertProvider>
|
||||
</AuthProvider>
|
||||
</ConfigProvider>
|
||||
</NetworkProvider>
|
||||
</KeyboardProvider>
|
||||
</GestureHandlerRootView>
|
||||
|
||||
@@ -64,6 +64,8 @@ export default function RequestPermitModal({ visible, types, onClose, onSubmit }
|
||||
|
||||
if (response.data.status === 'success') {
|
||||
alert.showAlert('success', 'Successo', response.data.message || 'La tua richiesta è stata inviata con successo.');
|
||||
onSubmit(requestData);
|
||||
onClose();
|
||||
} else {
|
||||
alert.showAlert('error', 'Errore', response.data.message || 'Impossibile inviare la richiesta.');
|
||||
}
|
||||
@@ -92,8 +94,6 @@ export default function RequestPermitModal({ visible, types, onClose, onSubmit }
|
||||
|
||||
try {
|
||||
await saveRequest(requestData);
|
||||
onSubmit(requestData);
|
||||
onClose();
|
||||
} catch (e) {
|
||||
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",
|
||||
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.27.1",
|
||||
"@babel/generator": "^7.28.5",
|
||||
@@ -1492,6 +1493,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz",
|
||||
"integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
@@ -3164,6 +3166,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.1.25.tgz",
|
||||
"integrity": "sha512-zQeWK9txDePWbYfqTs0C6jeRdJTm/7VhQtW/1IbJNDi9/rFIRzZule8bdQPAnf8QWUsNujRmi1J9OG/hhfbalg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@react-navigation/core": "^7.13.6",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
@@ -3362,6 +3365,7 @@
|
||||
"integrity": "sha512-Qec1E3mhALmaspIrhWt9jkQMNdw6bReVu64mjvhbhq2NFPftLPVr+l1SZgmw/66WwBNpDh7ao5AT6gF5v41PFA==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
@@ -3432,6 +3436,7 @@
|
||||
"integrity": "sha512-N9lBGA9o9aqb1hVMc9hzySbhKibHmB+N3IpoShyV6HyQYRGIhlrO5rQgttypi+yEeKsKI4idxC8Jw6gXKD4THA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.49.0",
|
||||
"@typescript-eslint/types": "8.49.0",
|
||||
@@ -3993,6 +3998,7 @@
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -4655,8 +4661,7 @@
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
|
||||
"license": "ISC",
|
||||
"peer": true
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/bplist-creator": {
|
||||
"version": "0.1.0",
|
||||
@@ -4720,6 +4725,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"baseline-browser-mapping": "^2.9.0",
|
||||
"caniuse-lite": "^1.0.30001759",
|
||||
@@ -5280,7 +5286,6 @@
|
||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
|
||||
"integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==",
|
||||
"license": "BSD-2-Clause",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"boolbase": "^1.0.0",
|
||||
"css-what": "^6.1.0",
|
||||
@@ -5297,7 +5302,6 @@
|
||||
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
|
||||
"integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"mdn-data": "2.0.14",
|
||||
"source-map": "^0.6.1"
|
||||
@@ -5311,7 +5315,6 @@
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"license": "BSD-3-Clause",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@@ -5321,7 +5324,6 @@
|
||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz",
|
||||
"integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==",
|
||||
"license": "BSD-2-Clause",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
},
|
||||
@@ -5589,7 +5591,6 @@
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
||||
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.2",
|
||||
@@ -5609,15 +5610,13 @@
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
],
|
||||
"license": "BSD-2-Clause",
|
||||
"peer": true
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/domhandler": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
||||
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
||||
"license": "BSD-2-Clause",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0"
|
||||
},
|
||||
@@ -5633,7 +5632,6 @@
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
|
||||
"integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
|
||||
"license": "BSD-2-Clause",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"dom-serializer": "^2.0.0",
|
||||
"domelementtype": "^2.3.0",
|
||||
@@ -5716,7 +5714,6 @@
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||
"license": "BSD-2-Clause",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
@@ -5948,6 +5945,7 @@
|
||||
"integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.8.0",
|
||||
"@eslint-community/regexpp": "^4.12.1",
|
||||
@@ -6144,6 +6142,7 @@
|
||||
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@rtsao/scc": "^1.1.0",
|
||||
"array-includes": "^3.1.9",
|
||||
@@ -6382,6 +6381,7 @@
|
||||
"resolved": "https://registry.npmjs.org/expo/-/expo-54.0.27.tgz",
|
||||
"integrity": "sha512-50BcJs8eqGwRiMUoWwphkRGYtKFS2bBnemxLzy0lrGVA1E6F4Q7L5h3WT6w1ehEZybtOVkfJu4Z6GWo2IJcpEA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.0",
|
||||
"@expo/cli": "54.0.18",
|
||||
@@ -6469,6 +6469,7 @@
|
||||
"resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-18.0.11.tgz",
|
||||
"integrity": "sha512-xnfrfZ7lHjb+03skhmDSYeFF7OU2K3Xn/lAeP+7RhkV2xp2f5RCKtOUYajCnYeZesvMrsUxOsbGOP2JXSOH3NA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@expo/config": "~12.0.11",
|
||||
"@expo/env": "~2.0.8"
|
||||
@@ -6575,6 +6576,7 @@
|
||||
"resolved": "https://registry.npmjs.org/expo-font/-/expo-font-14.0.10.tgz",
|
||||
"integrity": "sha512-UqyNaaLKRpj4pKAP4HZSLnuDQqueaO5tB1c/NWu5vh1/LF9ulItyyg2kF/IpeOp0DeOLk0GY0HrIXaKUMrwB+Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"fontfaceobserver": "^2.1.0"
|
||||
},
|
||||
@@ -8852,6 +8854,7 @@
|
||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
|
||||
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"jiti": "bin/jiti.js"
|
||||
}
|
||||
@@ -9467,8 +9470,7 @@
|
||||
"version": "2.0.14",
|
||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
|
||||
"integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
|
||||
"license": "CC0-1.0",
|
||||
"peer": true
|
||||
"license": "CC0-1.0"
|
||||
},
|
||||
"node_modules/memoize-one": {
|
||||
"version": "5.2.1",
|
||||
@@ -10083,7 +10085,6 @@
|
||||
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
|
||||
"integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
|
||||
"license": "BSD-2-Clause",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"boolbase": "^1.0.0"
|
||||
},
|
||||
@@ -10662,6 +10663,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.7",
|
||||
"picocolors": "^1.1.1",
|
||||
@@ -11110,6 +11112,7 @@
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
|
||||
"integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@@ -11129,6 +11132,7 @@
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
|
||||
"integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"scheduler": "^0.26.0"
|
||||
},
|
||||
@@ -11165,6 +11169,7 @@
|
||||
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.81.5.tgz",
|
||||
"integrity": "sha512-1w+/oSjEXZjMqsIvmkCRsOc8UBYv163bTWKTI8+1mxztvQPhCRYGTvZ/PL1w16xXHneIj/SLGfxWg2GWN2uexw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jest/create-cache-key-function": "^29.7.0",
|
||||
"@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",
|
||||
"integrity": "sha512-0msfJ1vRxXKVgTgvL+1ZOoYw3/0z1R+Ked0+udoJhyplC2jbVKIJ8Z1bzWdpQRCV3QcQ87Op0zJVE5DhKK2A0A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@egjs/hammerjs": "^2.0.17",
|
||||
"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",
|
||||
"integrity": "sha512-F+ZJBYiok/6Jzp1re75F/9aLzkgoQCOh4yxrnwATa8392RvM3kx+fiXXFvwcgE59v48lMwd9q0nzF1oJLXpfxQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"react-native-is-edge-to-edge": "^1.2.1",
|
||||
"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",
|
||||
"integrity": "sha512-4XGqMNj5qjUTYywJqpdWZ9IG8jgkS3h06sfVjfw5yZQZfWnRFXczi0GnYyFyCc2EBps/qFmoCH8fez//WumdVg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
@@ -11596,6 +11604,7 @@
|
||||
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.16.0.tgz",
|
||||
"integrity": "sha512-yIAyh7F/9uWkOzCi1/2FqvNvK6Wb9Y1+Kzn16SuGfN9YFJDTbwlzGRvePCNTOX0recpLQF3kc2FmvMUhyTCH1Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"react-freeze": "^1.0.0",
|
||||
"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",
|
||||
"integrity": "sha512-SO2t9/17zM4iEnFvlu2DA9jqNbzNhoUP+AItkoCOyFmDMOhUnBBznBDCYN92fGdfAkfQlWzPoez6+zLxFNsZEg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.18.6",
|
||||
"@react-native/normalize-colors": "^0.74.1",
|
||||
@@ -11789,6 +11799,7 @@
|
||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
|
||||
"integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@@ -12986,6 +12997,7 @@
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.18.tgz",
|
||||
"integrity": "sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@alloc/quick-lru": "^5.2.0",
|
||||
"arg": "^5.0.2",
|
||||
@@ -13192,6 +13204,7 @@
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -13398,6 +13411,7 @@
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
|
||||
@@ -14,6 +14,14 @@ const api = axios.create({
|
||||
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
|
||||
api.interceptors.request.use(
|
||||
async (config) => {
|
||||
|
||||
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