import { useMemo, useState } from 'react'; import { ActivityIndicator, Alert, Modal, Pressable, ScrollView, Text, TextInput, View, } from 'react-native'; import { UI } from '@/constants/uiTheme'; import { useGrillePrix } from '@/hooks/useGrillePrix'; import type { GrillePrixEtat, GrillePrixRecord, GrillePrixTypeBien } from '@/types/collections'; import { formatPocketBaseError } from '@/utils/pocketbaseErrors'; const TYPES: GrillePrixTypeBien[] = ['appartement', 'maison', 'immeuble']; const ETATS: GrillePrixEtat[] = ['bon_etat', 'a_renover', 'travaux_lourds']; const TYPE_LABEL: Record = { appartement: 'Appartement', maison: 'Maison', immeuble: 'Immeuble', }; const ETAT_LABEL: Record = { bon_etat: 'Bon état', a_renover: 'À rénover', travaux_lourds: 'Travaux lourds', }; type EditorState = | { mode: 'create' } | { mode: 'edit'; row: GrillePrixRecord }; function parseNum(raw: string): number | null { const n = Number(String(raw).replace(',', '.').trim()); return Number.isFinite(n) && n >= 0 ? n : null; } export function GrillePrixTab() { const { rows, isLoading, error, createRow, updateRow, deleteRow, isMutating } = useGrillePrix(); const [editor, setEditor] = useState(null); const [typeBien, setTypeBien] = useState('appartement'); const [etat, setEtat] = useState('bon_etat'); const [pa, setPa] = useState(''); const [pr, setPr] = useState(''); const [ville, setVille] = useState(''); const moyenneLabel = useMemo(() => { const vals = rows .map((r) => r.marge_estimee_pct) .filter((x): x is number => typeof x === 'number' && !Number.isNaN(x)); if (vals.length === 0) return '—'; const m = vals.reduce((a, b) => a + b, 0) / vals.length; return `${m.toFixed(1)} %`; }, [rows]); const openCreate = () => { setTypeBien('appartement'); setEtat('bon_etat'); setPa(''); setPr(''); setVille(''); setEditor({ mode: 'create' }); }; const openEdit = (row: GrillePrixRecord) => { setTypeBien(row.type_bien); setEtat(row.etat); setPa(String(row.prix_achat_m2)); setPr(String(row.prix_revente_m2)); setVille(row.ville ?? ''); setEditor({ mode: 'edit', row }); }; const closeEditor = () => setEditor(null); const submitEditor = async () => { const achat = parseNum(pa); const revente = parseNum(pr); if (achat == null || revente == null) { Alert.alert('Saisie', 'Indique des prix au m² valides (≥ 0).'); return; } try { const payload = { type_bien: typeBien, etat, prix_achat_m2: achat, prix_revente_m2: revente, ville: ville.trim() || undefined, }; if (editor?.mode === 'create') { await createRow(payload); } else if (editor?.mode === 'edit') { await updateRow({ id: editor.row.id, input: payload }); } closeEditor(); } catch (e) { Alert.alert('Erreur', formatPocketBaseError(e)); } }; const confirmDelete = (row: GrillePrixRecord) => { Alert.alert('Supprimer cette ligne ?', `${TYPE_LABEL[row.type_bien]} · ${ETAT_LABEL[row.etat]}`, [ { text: 'Annuler', style: 'cancel' }, { text: 'Supprimer', style: 'destructive', onPress: () => void deleteRow(row.id).catch((e) => Alert.alert('Erreur', formatPocketBaseError(e))), }, ]); }; if (isLoading) { return ( ); } return ( {error ? ( {formatPocketBaseError(error)} ) : null} Type État Achat €/m² Revente €/m² Marge % Ville {rows.length === 0 ? ( Aucune ligne. Appuie sur + pour créer ton référentiel. ) : ( rows.map((r) => ( openEdit(r)} className="min-w-0 flex-1 flex-row active:bg-slate-100" > {TYPE_LABEL[r.type_bien]} {ETAT_LABEL[r.etat]} {r.prix_achat_m2} {r.prix_revente_m2} {r.marge_estimee_pct != null ? `${r.marge_estimee_pct.toFixed(1)} %` : '—'} {r.ville ?? '—'} confirmDelete(r)} className="w-20 items-center justify-center"> )) )} Marge moyenne du référentiel {moyenneLabel} + {editor?.mode === 'edit' ? 'Modifier la ligne' : 'Nouvelle ligne'} Type de bien {TYPES.map((t) => ( setTypeBien(t)} className="min-h-[48px] rounded-xl border-2 px-4 py-2" style={{ borderColor: typeBien === t ? UI.primary : UI.border, backgroundColor: typeBien === t ? '#EFF6FF' : UI.card, }} > {TYPE_LABEL[t]} ))} État {ETATS.map((t) => ( setEtat(t)} className="min-h-[48px] rounded-xl border-2 px-4 py-2" style={{ borderColor: etat === t ? UI.primary : UI.border, backgroundColor: etat === t ? '#EFF6FF' : UI.card, }} > {ETAT_LABEL[t]} ))} Prix achat (€/m²) Prix revente (€/m²) Ville (optionnel) Annuler void submitEditor()} disabled={isMutating} className="min-h-[52px] flex-1 items-center justify-center rounded-2xl" style={{ backgroundColor: UI.primary }} > {isMutating ? ( ) : ( Enregistrer )} ); }