useScanDetail :
- Nouvelle méthode setLocation(coords) qui persiste latitude / longitude
(top-level pour MapScreen.hasLocation), locationCapturedAt et
l'objet location.{latitude, longitude} dans AsyncStorage + state local
ScanDetailScreen :
- handleAddLocation appelle requestAndGetLocation() (useScanLocation hook
existant) puis setLocation()
- État addingLocation : bouton désactivé + opacity 0.6 + ActivityIndicator
spinner à la place de l'icône MapPin + label 'Localisation en cours...'
- Toast success / error + hapticSuccess en cas de succès
- La carte location bascule automatiquement vers l'affichage des coords
une fois persisté → la plante apparaît aussi sur MapScreen et
SearchScreen mode Map
i18n :
- myPlants.toasts.locationAdded
- myPlants.detail.locating
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
110 lines
3.2 KiB
TypeScript
110 lines
3.2 KiB
TypeScript
import { useState, useEffect, useCallback } from 'react';
|
|
import { storage } from '@/services/storage';
|
|
import type { ScanRecord } from '@/types/detection';
|
|
|
|
export function useScanDetail(scanId: string) {
|
|
const [scan, setScan] = useState<ScanRecord | null>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
const load = useCallback(async () => {
|
|
setLoading(true);
|
|
setError(null);
|
|
const all = await storage.get<ScanRecord[]>(storage.KEYS.SCAN_HISTORY);
|
|
const found = all?.find((s) => s.id === scanId) ?? null;
|
|
if (!found) setError('Scan not found');
|
|
setScan(found);
|
|
setLoading(false);
|
|
}, [scanId]);
|
|
|
|
useEffect(() => {
|
|
load();
|
|
}, [load]);
|
|
|
|
const toggleFavorite = useCallback(async () => {
|
|
const all = await storage.get<ScanRecord[]>(storage.KEYS.SCAN_HISTORY);
|
|
if (!all) return;
|
|
const updated = all.map((s) =>
|
|
s.id === scanId ? { ...s, isFavorite: !s.isFavorite } : s,
|
|
);
|
|
await storage.set(storage.KEYS.SCAN_HISTORY, updated);
|
|
setScan((prev) => (prev ? { ...prev, isFavorite: !prev.isFavorite } : prev));
|
|
}, [scanId]);
|
|
|
|
const deleteScan = useCallback(async () => {
|
|
const all = await storage.get<ScanRecord[]>(storage.KEYS.SCAN_HISTORY);
|
|
if (!all) return;
|
|
const updated = all.filter((s) => s.id !== scanId);
|
|
await storage.set(storage.KEYS.SCAN_HISTORY, updated);
|
|
}, [scanId]);
|
|
|
|
const renameScan = useCallback(
|
|
async (newName: string) => {
|
|
const trimmed = newName.trim();
|
|
const all = await storage.get<ScanRecord[]>(storage.KEYS.SCAN_HISTORY);
|
|
if (!all) return;
|
|
const updated = all.map((s) =>
|
|
s.id === scanId
|
|
? { ...s, customName: trimmed.length > 0 ? trimmed : undefined }
|
|
: s,
|
|
);
|
|
await storage.set(storage.KEYS.SCAN_HISTORY, updated);
|
|
setScan((prev) =>
|
|
prev
|
|
? { ...prev, customName: trimmed.length > 0 ? trimmed : undefined }
|
|
: prev,
|
|
);
|
|
},
|
|
[scanId],
|
|
);
|
|
|
|
const setLocation = useCallback(
|
|
async (coords: { latitude: number; longitude: number }) => {
|
|
const capturedAt = new Date().toISOString();
|
|
const all = await storage.get<ScanRecord[]>(storage.KEYS.SCAN_HISTORY);
|
|
if (!all) return;
|
|
const updated = all.map((s) =>
|
|
s.id === scanId
|
|
? {
|
|
...s,
|
|
latitude: coords.latitude,
|
|
longitude: coords.longitude,
|
|
locationCapturedAt: capturedAt,
|
|
location: {
|
|
latitude: coords.latitude,
|
|
longitude: coords.longitude,
|
|
},
|
|
}
|
|
: s,
|
|
);
|
|
await storage.set(storage.KEYS.SCAN_HISTORY, updated);
|
|
setScan((prev) =>
|
|
prev
|
|
? {
|
|
...prev,
|
|
latitude: coords.latitude,
|
|
longitude: coords.longitude,
|
|
locationCapturedAt: capturedAt,
|
|
location: {
|
|
latitude: coords.latitude,
|
|
longitude: coords.longitude,
|
|
},
|
|
}
|
|
: prev,
|
|
);
|
|
},
|
|
[scanId],
|
|
);
|
|
|
|
return {
|
|
scan,
|
|
loading,
|
|
error,
|
|
toggleFavorite,
|
|
deleteScan,
|
|
renameScan,
|
|
setLocation,
|
|
refetch: load,
|
|
};
|
|
}
|