fix perm and camera
This commit is contained in:
parent
ebf0d5b6ec
commit
bb0f242dd5
@ -150,25 +150,54 @@ const TimeClockPage = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const stopScanner = () => {
|
||||
const controls = qrControlsRef.current;
|
||||
qrControlsRef.current = null;
|
||||
const scannerSessionRef = useRef(0);
|
||||
|
||||
const stopScanner = () => {
|
||||
// Invalide immédiatement toute session de scan en cours
|
||||
scannerSessionRef.current += 1;
|
||||
|
||||
// Arrêter les contrôles ZXing
|
||||
if (qrControlsRef.current) {
|
||||
try {
|
||||
controls?.stop();
|
||||
} catch (stopError) {
|
||||
console.warn('Arrêt du lecteur QR déjà effectué.', stopError);
|
||||
qrControlsRef.current.stop();
|
||||
} catch (error) {
|
||||
console.warn('Impossible d’arrêter le scanner QR.', error);
|
||||
}
|
||||
|
||||
if (videoRef.current) {
|
||||
videoRef.current.pause();
|
||||
qrControlsRef.current = null;
|
||||
}
|
||||
|
||||
// Arrêter explicitement la caméra
|
||||
if (videoRef.current?.srcObject) {
|
||||
const stream = videoRef.current.srcObject;
|
||||
|
||||
stream.getTracks().forEach((track) => {
|
||||
try {
|
||||
track.stop();
|
||||
} catch (error) {
|
||||
console.warn('Impossible d’arrêter la piste caméra.', error);
|
||||
}
|
||||
});
|
||||
|
||||
videoRef.current.srcObject = null;
|
||||
}
|
||||
};
|
||||
|
||||
const handleQrResult = async (code) => {
|
||||
setScanConflict(null);
|
||||
const closeScanner = () => {
|
||||
stopScanner();
|
||||
setIsScannerDialogOpen(false);
|
||||
};
|
||||
|
||||
const handleQrResult = async (code, sessionId) => {
|
||||
// Si cette session n’est plus active, on ignore le résultat
|
||||
if (scannerSessionRef.current !== sessionId) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Fermer immédiatement la caméra
|
||||
closeScanner();
|
||||
|
||||
setScanConflict(null);
|
||||
|
||||
try {
|
||||
const response = await timeApi.scanTimeEntry(code);
|
||||
@ -176,7 +205,11 @@ const TimeClockPage = () => {
|
||||
await loadTimeEntries();
|
||||
} catch (scanError) {
|
||||
if (scanError.code === 409 && scanError.conflict) {
|
||||
setScanConflict({ code, type: scanError.conflict, message: scanError.message });
|
||||
setScanConflict({
|
||||
code,
|
||||
type: scanError.conflict,
|
||||
message: scanError.message,
|
||||
});
|
||||
} else {
|
||||
setError(scanError.message);
|
||||
}
|
||||
@ -185,12 +218,15 @@ const TimeClockPage = () => {
|
||||
|
||||
const resolveScanConflict = async (resolution) => {
|
||||
if (!scanConflict) return;
|
||||
|
||||
setError('');
|
||||
|
||||
try {
|
||||
const response = await timeApi.scanTimeEntry(scanConflict.code, {
|
||||
resolution,
|
||||
time: conflictTime,
|
||||
});
|
||||
|
||||
setScanMessage(response.message);
|
||||
setScanConflict(null);
|
||||
await loadTimeEntries();
|
||||
@ -199,26 +235,37 @@ const TimeClockPage = () => {
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => () => stopScanner(), []);
|
||||
// Nettoyage lors du démontage
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
stopScanner();
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Gestion du scanner QR
|
||||
useEffect(() => {
|
||||
if (!isScannerDialogOpen) {
|
||||
return undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
const sessionId = scannerSessionRef.current;
|
||||
let cancelled = false;
|
||||
let reader = null;
|
||||
|
||||
const startReader = async () => {
|
||||
// Attendre que Radix ait réellement monté le DialogContent
|
||||
// Attendre que DialogContent soit réellement monté
|
||||
await new Promise((resolve) => {
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(resolve);
|
||||
});
|
||||
});
|
||||
|
||||
if (cancelled || !videoRef.current) {
|
||||
console.warn('Vidéo du scanner non disponible.');
|
||||
// Le dialog a pu être fermé pendant l’attente
|
||||
if (
|
||||
cancelled ||
|
||||
scannerSessionRef.current !== sessionId ||
|
||||
!videoRef.current
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -234,33 +281,51 @@ const TimeClockPage = () => {
|
||||
},
|
||||
videoRef.current,
|
||||
(result) => {
|
||||
if (!result || cancelled) {
|
||||
if (
|
||||
!result ||
|
||||
cancelled ||
|
||||
scannerSessionRef.current !== sessionId
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
handleQrResult(result.getText());
|
||||
setIsScannerDialogOpen(false);
|
||||
},
|
||||
handleQrResult(result.getText(), sessionId);
|
||||
}
|
||||
);
|
||||
|
||||
if (cancelled) {
|
||||
// La fermeture peut avoir eu lieu pendant l’initialisation
|
||||
if (
|
||||
cancelled ||
|
||||
scannerSessionRef.current !== sessionId
|
||||
) {
|
||||
try {
|
||||
controls.stop();
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
'Impossible d’arrêter le scanner après annulation.',
|
||||
error
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
qrControlsRef.current = controls;
|
||||
} catch (scannerError) {
|
||||
if (cancelled) {
|
||||
if (
|
||||
cancelled ||
|
||||
scannerSessionRef.current !== sessionId
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.error('Erreur scanner QR:', scannerError);
|
||||
|
||||
setError(
|
||||
'Impossible d’accéder à la caméra. Vérifiez les permissions et utilisez HTTPS sur le réseau.',
|
||||
'Impossible d’accéder à la caméra. Vérifiez les permissions et utilisez HTTPS sur le réseau.'
|
||||
);
|
||||
|
||||
stopScanner();
|
||||
closeScanner();
|
||||
}
|
||||
};
|
||||
|
||||
@ -269,26 +334,51 @@ const TimeClockPage = () => {
|
||||
return () => {
|
||||
cancelled = true;
|
||||
|
||||
// Invalide cette session
|
||||
if (scannerSessionRef.current === sessionId) {
|
||||
scannerSessionRef.current += 1;
|
||||
}
|
||||
|
||||
try {
|
||||
reader?.reset();
|
||||
} catch (resetError) {
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
'Réinitialisation du lecteur QR ignorée.',
|
||||
resetError,
|
||||
error
|
||||
);
|
||||
}
|
||||
|
||||
const controls = qrControlsRef.current;
|
||||
qrControlsRef.current = null;
|
||||
|
||||
// Arrêter les contrôles ZXing
|
||||
if (qrControlsRef.current) {
|
||||
try {
|
||||
controls?.stop();
|
||||
} catch (stopError) {
|
||||
qrControlsRef.current.stop();
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
'Arrêt du lecteur QR ignoré.',
|
||||
stopError,
|
||||
'Impossible d’arrêter les contrôles QR.',
|
||||
error
|
||||
);
|
||||
}
|
||||
|
||||
qrControlsRef.current = null;
|
||||
}
|
||||
|
||||
// Arrêter explicitement toutes les pistes caméra
|
||||
if (videoRef.current?.srcObject) {
|
||||
const stream = videoRef.current.srcObject;
|
||||
|
||||
stream.getTracks().forEach((track) => {
|
||||
try {
|
||||
track.stop();
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
'Impossible d’arrêter la piste caméra.',
|
||||
error
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
videoRef.current.srcObject = null;
|
||||
}
|
||||
};
|
||||
}, [isScannerDialogOpen]);
|
||||
|
||||
@ -303,7 +393,7 @@ const TimeClockPage = () => {
|
||||
window.location.hostname !== '192.168.1.19'
|
||||
) {
|
||||
setError(
|
||||
'La caméra nécessite une connexion HTTPS sur cette adresse réseau.',
|
||||
'La caméra nécessite une connexion HTTPS sur cette adresse réseau.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
@ -313,6 +403,9 @@ const TimeClockPage = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
// Nouvelle session de scanner
|
||||
scannerSessionRef.current += 1;
|
||||
|
||||
setIsScannerDialogOpen(true);
|
||||
};
|
||||
|
||||
@ -377,10 +470,10 @@ const TimeClockPage = () => {
|
||||
<Dialog
|
||||
open={isScannerDialogOpen}
|
||||
onOpenChange={(open) => {
|
||||
setIsScannerDialogOpen(open);
|
||||
|
||||
if (!open) {
|
||||
stopScanner();
|
||||
if (open) {
|
||||
setIsScannerDialogOpen(true);
|
||||
} else {
|
||||
closeScanner();
|
||||
}
|
||||
}}
|
||||
>
|
||||
@ -412,7 +505,7 @@ const TimeClockPage = () => {
|
||||
/>
|
||||
|
||||
<Button
|
||||
onClick={() => setIsScannerDialogOpen(false)}
|
||||
onClick={closeScanner}
|
||||
variant="secondary"
|
||||
className="mt-2"
|
||||
>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user