165 lines
5.3 KiB
TypeScript
165 lines
5.3 KiB
TypeScript
import { Link, Stack, useLocalSearchParams } from 'expo-router';
|
|
import {
|
|
ActivityIndicator,
|
|
Linking,
|
|
Pressable,
|
|
ScrollView,
|
|
Text,
|
|
View,
|
|
} from 'react-native';
|
|
|
|
import { labelContactCategorie } from '@/constants/contactCategories';
|
|
import { useContactBiens, useContactDetail } from '@/hooks/useContacts';
|
|
import { getCurrentUserId } from '@/services/pocketbase';
|
|
import { formatPocketBaseError } from '@/utils/pocketbaseErrors';
|
|
|
|
function routeParamId(raw: string | string[] | undefined): string | undefined {
|
|
if (raw == null) return undefined;
|
|
return Array.isArray(raw) ? raw[0] : raw;
|
|
}
|
|
|
|
function openTel(raw?: string | null) {
|
|
if (!raw?.trim()) return;
|
|
void Linking.openURL(`tel:${raw.replace(/\s/g, '')}`);
|
|
}
|
|
|
|
function openMail(raw?: string | null) {
|
|
if (!raw?.trim()) return;
|
|
void Linking.openURL(`mailto:${raw.trim()}`);
|
|
}
|
|
|
|
export default function ContactDetailScreen() {
|
|
const { id: rawId } = useLocalSearchParams<{ id?: string | string[] }>();
|
|
const id = routeParamId(rawId);
|
|
const uid = getCurrentUserId();
|
|
|
|
const q = useContactDetail(id);
|
|
const biensQ = useContactBiens(id);
|
|
|
|
if (!id) {
|
|
return (
|
|
<>
|
|
<Stack.Screen options={{ title: 'Contact', headerShown: true }} />
|
|
<View className="flex-1 items-center justify-center p-6">
|
|
<Text>Identifiant manquant.</Text>
|
|
</View>
|
|
</>
|
|
);
|
|
}
|
|
|
|
if (q.isPending) {
|
|
return (
|
|
<>
|
|
<Stack.Screen options={{ title: '…', headerShown: true }} />
|
|
<View className="flex-1 items-center justify-center">
|
|
<ActivityIndicator color="#1D4ED8" />
|
|
</View>
|
|
</>
|
|
);
|
|
}
|
|
|
|
if (q.error || !q.data) {
|
|
return (
|
|
<>
|
|
<Stack.Screen options={{ title: 'Erreur', headerShown: true }} />
|
|
<View className="flex-1 items-center justify-center p-6">
|
|
<Text className="text-center text-red-700">
|
|
{q.error ? formatPocketBaseError(q.error) : 'Introuvable.'}
|
|
</Text>
|
|
</View>
|
|
</>
|
|
);
|
|
}
|
|
|
|
const c = q.data;
|
|
if (uid && c.user !== uid) {
|
|
return (
|
|
<>
|
|
<Stack.Screen options={{ title: 'Contact', headerShown: true }} />
|
|
<View className="flex-1 items-center justify-center p-6">
|
|
<Text>Accès refusé.</Text>
|
|
</View>
|
|
</>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<Stack.Screen options={{ title: c.nom, headerShown: true }} />
|
|
<ScrollView className="flex-1 bg-slate-50 p-4">
|
|
<Text className="text-xl font-bold text-slate-900">
|
|
{c.prenom ? `${c.prenom} ` : ''}
|
|
{c.nom}
|
|
</Text>
|
|
{c.societe ? <Text className="mt-1 text-slate-600">{c.societe}</Text> : null}
|
|
<Text className="mt-3 text-sm text-slate-500">Catégorie</Text>
|
|
<Text className="text-base text-slate-900">{labelContactCategorie(c.categorie)}</Text>
|
|
|
|
{c.email ? (
|
|
<>
|
|
<Text className="mt-3 text-sm text-slate-500">Email</Text>
|
|
<Pressable onPress={() => openMail(c.email)}>
|
|
<Text className="text-base text-blue-700">{c.email}</Text>
|
|
</Pressable>
|
|
</>
|
|
) : null}
|
|
{c.telephone ? (
|
|
<>
|
|
<Text className="mt-3 text-sm text-slate-500">Téléphone</Text>
|
|
<Pressable onPress={() => openTel(c.telephone)}>
|
|
<Text className="text-base text-blue-700">{c.telephone}</Text>
|
|
</Pressable>
|
|
</>
|
|
) : null}
|
|
{c.telephone_2 ? (
|
|
<>
|
|
<Text className="mt-3 text-sm text-slate-500">Téléphone 2</Text>
|
|
<Pressable onPress={() => openTel(c.telephone_2)}>
|
|
<Text className="text-base text-blue-700">{c.telephone_2}</Text>
|
|
</Pressable>
|
|
</>
|
|
) : null}
|
|
{(c.ville || c.zone_intervention) ? (
|
|
<>
|
|
<Text className="mt-3 text-sm text-slate-500">Localisation</Text>
|
|
<Text className="text-base text-slate-900">
|
|
{[c.ville, c.zone_intervention].filter(Boolean).join(' · ')}
|
|
</Text>
|
|
</>
|
|
) : null}
|
|
|
|
{c.notes ? (
|
|
<>
|
|
<Text className="mt-5 text-lg font-bold text-slate-900">Notes</Text>
|
|
<Text className="mt-1 text-slate-800">{c.notes}</Text>
|
|
</>
|
|
) : null}
|
|
|
|
<Text className="mt-6 text-lg font-bold text-slate-900">Biens associés</Text>
|
|
{biensQ.isPending ? (
|
|
<ActivityIndicator className="mt-2" color="#1D4ED8" />
|
|
) : biensQ.error ? (
|
|
<Text className="mt-2 text-red-700">{formatPocketBaseError(biensQ.error)}</Text>
|
|
) : (biensQ.data?.length ?? 0) === 0 ? (
|
|
<Text className="mt-2 text-slate-600">Aucun bien lié (source contact).</Text>
|
|
) : (
|
|
<View className="mt-2 gap-2">
|
|
{biensQ.data!.map((b) => (
|
|
<Link key={b.id} href={`/bien/${b.id}`} asChild>
|
|
<Pressable className="rounded-xl border border-slate-200 bg-white px-3 py-3">
|
|
<Text className="font-semibold text-slate-900">
|
|
{b.titre?.trim() || `${b.ville ?? ''} (${b.type_bien ?? 'bien'})`.trim()}
|
|
</Text>
|
|
<Text className="text-sm text-slate-500">
|
|
{[b.adresse, b.code_postal, b.ville].filter(Boolean).join(', ')}
|
|
</Text>
|
|
</Pressable>
|
|
</Link>
|
|
))}
|
|
</View>
|
|
)}
|
|
</ScrollView>
|
|
</>
|
|
);
|
|
}
|