From 9de8ad5f3ed6c307e683847500dcc4c95e9bd3ec Mon Sep 17 00:00:00 2001 From: Gilles Soulier Date: Mon, 25 May 2026 15:52:41 +0200 Subject: [PATCH] fix(gps): erreur explicite + saisie manuelle si GPS indisponible (HTTP/laptop) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit navigator.geolocation est undefined sur HTTP hors localhost (contexte non sécurisé). - Message d'erreur visible selon le cas (permission, HTTPS, timeout) - Fallback : deux champs lat/lon s'affichent automatiquement - TodoForm : bouton GPS toujours actif (plus disabled sur navigator.geolocation) Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/components/notes/NoteForm.tsx | 105 ++++++++++++++------- frontend/src/components/todos/TodoForm.tsx | 48 +++++++++- 2 files changed, 117 insertions(+), 36 deletions(-) diff --git a/frontend/src/components/notes/NoteForm.tsx b/frontend/src/components/notes/NoteForm.tsx index b599e0f..1f86648 100644 --- a/frontend/src/components/notes/NoteForm.tsx +++ b/frontend/src/components/notes/NoteForm.tsx @@ -30,6 +30,8 @@ export default function NoteForm({ initialValues, onSubmit, onCancel, submitLabe const [gpsLat, setGpsLat] = useState(initialValues?.gps_lat ?? undefined) const [gpsLon, setGpsLon] = useState(initialValues?.gps_lon ?? undefined) const [gpsLoading, setGpsLoading] = useState(false) + const [gpsError, setGpsError] = useState(null) + const [gpsManual, setGpsManual] = useState(false) const [saving, setSaving] = useState(false) const [error, setError] = useState(null) const contentRef = useRef(null) @@ -39,19 +41,37 @@ export default function NoteForm({ initialValues, onSubmit, onCancel, submitLabe } function handleGps() { - if (!navigator.geolocation) return + setGpsError(null) + if (!navigator.geolocation) { + setGpsError('GPS non disponible (HTTPS requis hors localhost)') + setGpsManual(true) + return + } setGpsLoading(true) navigator.geolocation.getCurrentPosition( pos => { setGpsLat(pos.coords.latitude) setGpsLon(pos.coords.longitude) setGpsLoading(false) + setGpsManual(false) + }, + err => { + setGpsLoading(false) + if (err.code === 1) setGpsError('Permission refusée') + else if (err.code === 2) setGpsError('Position indisponible — saisie manuelle ?') + else setGpsError('Délai dépassé — saisie manuelle ?') + setGpsManual(true) }, - () => setGpsLoading(false), { timeout: 8000 }, ) } + function handleManualCoord(field: 'lat' | 'lon', val: string) { + const n = parseFloat(val.replace(',', '.')) + if (field === 'lat') setGpsLat(isNaN(n) ? undefined : n) + else setGpsLon(isNaN(n) ? undefined : n) + } + async function handleSubmit() { if (!content.trim()) return setSaving(true) @@ -112,36 +132,57 @@ export default function NoteForm({ initialValues, onSubmit, onCancel, submitLabe {/* GPS */} -
- - {gpsLat && ( - <> - - {gpsLat.toFixed(5)}, {gpsLon?.toFixed(5)} - - - +
+
+ + {gpsLat != null && ( + <> + + {gpsLat.toFixed(5)}, {gpsLon?.toFixed(5)} + + + + )} +
+ + {gpsError && ( + + {gpsError} + + )} + + {gpsManual && gpsLat == null && ( +
+ handleManualCoord('lat', e.target.value)} + /> + handleManualCoord('lon', e.target.value)} + /> +
)}
diff --git a/frontend/src/components/todos/TodoForm.tsx b/frontend/src/components/todos/TodoForm.tsx index 54be8f5..9d8ad65 100644 --- a/frontend/src/components/todos/TodoForm.tsx +++ b/frontend/src/components/todos/TodoForm.tsx @@ -69,6 +69,8 @@ export default function TodoForm({ onSubmit, onCancel, initialValues, submitLabe const [photoPath, setPhotoPath] = useState(initialValues?.photo_path ?? undefined) const [photoLoading, setPhotoLoading] = useState(false) const [gpsLoading, setGpsLoading] = useState(false) + const [gpsError, setGpsError] = useState(null) + const [gpsManual, setGpsManual] = useState(false) const [loading, setLoading] = useState(false) const fileRef = useRef(null) @@ -109,18 +111,37 @@ export default function TodoForm({ onSubmit, onCancel, initialValues, submitLabe }, []) function handleGps() { - if (!navigator.geolocation) return + setGpsError(null) + if (!navigator.geolocation) { + setGpsError('GPS non disponible (HTTPS requis hors localhost)') + setGpsManual(true) + return + } setGpsLoading(true) navigator.geolocation.getCurrentPosition( pos => { setGpsLat(pos.coords.latitude) setGpsLng(pos.coords.longitude) setGpsLoading(false) + setGpsManual(false) }, - () => setGpsLoading(false) + err => { + setGpsLoading(false) + if (err.code === 1) setGpsError('Permission refusée') + else if (err.code === 2) setGpsError('Position indisponible — saisie manuelle ?') + else setGpsError('Délai dépassé — saisie manuelle ?') + setGpsManual(true) + }, + { timeout: 8000 }, ) } + function handleManualCoord(field: 'lat' | 'lng', val: string) { + const n = parseFloat(val.replace(',', '.')) + if (field === 'lat') setGpsLat(isNaN(n) ? undefined : n) + else setGpsLng(isNaN(n) ? undefined : n) + } + async function handleSubmit(e: React.FormEvent) { e.preventDefault() if (!title.trim()) return @@ -296,7 +317,7 @@ export default function TodoForm({ onSubmit, onCancel, initialValues, submitLabe
{/* Boutons */}