import { Ionicons } from '@expo/vector-icons'; import * as Clipboard from 'expo-clipboard'; import type { ReactNode } from 'react'; import { useCallback, useState } from 'react'; import { ActivityIndicator, Alert, Linking, Pressable, ScrollView, Text, TextInput, View, } from 'react-native'; import { LEGI_L151_36, LEGI_L152_6, OFF_MARKET_KEYWORDS, PROSPECTION_CHECKLIST, } from '@/constants/rechercheMarche'; import { UI } from '@/constants/uiTheme'; import { useNotesProspectionRecherche } from '@/hooks/useNotesProspectionRecherche'; import { formatPocketBaseError } from '@/utils/pocketbaseErrors'; const LBC = 'https://www.leboncoin.fr/'; const MOTEUR = 'https://www.moteurimmo.fr/'; function Collapsible({ title, children, defaultOpen, }: { title: string; children: ReactNode; defaultOpen?: boolean; }) { const [open, setOpen] = useState(Boolean(defaultOpen)); return ( setOpen((o) => !o)} className="min-h-[52px] flex-row items-center justify-between px-4 py-3" > {title} {open ? {children} : null} ); } export function OpportunitesTab() { const { getState, saveChecklistItem, isLoading, isSaving } = useNotesProspectionRecherche(); const [expandedNoteId, setExpandedNoteId] = useState(null); const [noteDraft, setNoteDraft] = useState(''); const persistItem = useCallback( async (questionId: string, next: { done: boolean; note: string }) => { try { await saveChecklistItem({ questionId, data: next }); } catch (e) { Alert.alert('Sauvegarde', formatPocketBaseError(e)); } }, [saveChecklistItem], ); const openNoteEditor = (questionId: string) => { const st = getState(questionId); setExpandedNoteId(questionId); setNoteDraft(st.note); }; const saveNoteFor = async (questionId: string) => { const st = getState(questionId); await persistItem(questionId, { done: st.done, note: noteDraft.trim() }); setExpandedNoteId(null); }; const copyText = async (text: string) => { try { await Clipboard.setStringAsync(text); Alert.alert('Copié', 'Collage dans Leboncoin ou Moteur Immo.'); } catch { Alert.alert('Presse-papiers', 'Copie impossible sur cet appareil.'); } }; if (isLoading) { return ( ); } return ( {OFF_MARKET_KEYWORDS.map((k) => ( {k.label} {k.text} void copyText(k.text)} className="mt-3 min-h-[48px] items-center justify-center rounded-xl" style={{ backgroundColor: UI.primary }} > Copier ))} void Linking.openURL(LBC)} className="min-h-[52px] flex-1 min-w-[140px] items-center justify-center rounded-2xl border-2" style={{ borderColor: UI.warning, backgroundColor: '#FFFBEB' }} > Leboncoin void Linking.openURL(MOTEUR)} className="min-h-[52px] flex-1 min-w-[140px] items-center justify-center rounded-2xl border-2" style={{ borderColor: UI.warning, backgroundColor: '#FFFBEB' }} > Moteur Immo Astuce maison de ville Surface terrain max 100 m² + surface habitable min 150 m² → maisons sans jardin, moins de concurrence, idéal division. Trier par ancienneté sur Moteur Immo. 40+ mois en ligne + baisses répétées = vendeur motivé. Décote possible sous prix marché. −10 % à −24 % void Linking.openURL(MOTEUR)} className="mt-4 min-h-[52px] items-center justify-center rounded-2xl" style={{ backgroundColor: UI.danger }} > Moteur Immo — tri par ancienneté Article L151-36 1 place de parking max par logement créé en zone bien desservie. void Linking.openURL(LEGI_L151_36)} className="mt-3 min-h-[48px] items-center justify-center rounded-xl bg-white" > Ouvrir sur Légifrance → Article L152-6 Dans 500 m d'une gare ou métro → division sans obligation parking. void Linking.openURL(LEGI_L152_6)} className="mt-3 min-h-[48px] items-center justify-center rounded-xl bg-white" > Ouvrir sur Légifrance → Coche après échange ; note la réponse pour ton dossier. {PROSPECTION_CHECKLIST.map((item) => { const st = getState(item.id); const expanded = expandedNoteId === item.id; return ( void persistItem(item.id, { done: !st.done, note: st.note })} className="min-h-[48px] flex-row items-start gap-3" > {st.done ? : null} {item.label} {item.question} (expanded ? setExpandedNoteId(null) : openNoteEditor(item.id))} className="mt-3 min-h-[44px] justify-center rounded-xl px-3" style={{ backgroundColor: '#F1F5F9' }} > {expanded ? 'Fermer la note' : st.note ? 'Modifier la note' : 'Ajouter une note'} {expanded ? ( void saveNoteFor(item.id)} disabled={isSaving} className="mt-2 min-h-[48px] items-center justify-center rounded-xl" style={{ backgroundColor: UI.primary }} > {isSaving ? ( ) : ( Enregistrer la note )} ) : st.note ? ( {st.note} ) : null} ); })} ); }