import { CameraView, useCameraPermissions } from 'expo-camera'; import { router } from 'expo-router'; import { useRef, useState } from 'react'; import { Platform, Text, TextInput, View } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import { useAssets } from '@/api/exploitation'; import { useHorsLigne } from '@/auth/session'; import { BoutonTel } from '@/composants/ui'; import { analyseScan } from '@/lib/scan'; import { useTokens } from '@/theme/tokens'; /** Écran 4 de la maquette R4 (D4) : le QR de l'étiquette A6 contient l'URL * portail `…/q/REF` — la résolution se fait D'ABORD dans le parc déjà en * cache (donc en sous-sol aussi). Repli : saisie de la référence. */ export default function PageScanner() { const t = useTokens(); const horsLigne = useHorsLigne(); const [permission, demanderPermission] = useCameraPermissions(); const { data: assets, refetch } = useAssets(); const [manuel, setManuel] = useState(''); const [erreur, setErreur] = useState(null); const dernierScan = useRef(0); const resoudre = async (brut: string) => { const reference = analyseScan(brut); if (!reference) { setErreur('Ce code n’est pas une étiquette SIOP.'); return; } // 1 · le parc en cache (fonctionne hors-ligne) let appareil = (assets ?? []).find((a) => a.reference.toUpperCase() === reference); // 2 · sinon, un rafraîchissement si le réseau est là if (!appareil && !horsLigne) { const frais = await refetch(); appareil = (frais.data ?? []).find((a) => a.reference.toUpperCase() === reference); } if (!appareil) { setErreur( horsLigne ? `« ${reference} » n'est pas dans le parc synchronisé — réessayez au retour du réseau.` : `Aucun appareil « ${reference} » dans le parc.`, ); return; } setErreur(null); setManuel(''); router.push(`/ascenseur/${appareil.id}`); }; const surScan = ({ data }: { data: string }) => { const maintenant = Date.now(); if (maintenant - dernierScan.current < 1500) return; // anti-rafale dernierScan.current = maintenant; void resoudre(data); }; const cameraUtilisable = Platform.OS !== 'web' && permission?.granted; return ( Scanner {cameraUtilisable ? ( Visez le QR de l’étiquette de cabine ) : ( {Platform.OS === 'web' ? 'Caméra indisponible sur web — saisissez la référence ci-dessous.' : 'L’appareil photo sert uniquement à lire les étiquettes du parc.'} {Platform.OS !== 'web' && !permission?.granted ? ( void demanderPermission()} /> ) : null} )} { setManuel(v); setErreur(null); }} onSubmitEditing={() => void resoudre(manuel)} style={{ flex: 1, backgroundColor: t.surface, borderColor: t.bordureForte, borderWidth: 1.5, borderRadius: 10, paddingHorizontal: 12, paddingVertical: 10, color: t.encre, fontFamily: 'Manrope_600SemiBold', }} /> void resoudre(manuel)} /> {erreur ? ( {erreur} ) : null} ); }