import React, { useState } from 'react'; import { Alert, Image, ScrollView, StyleSheet, Text, View } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { useLocalSearchParams, useRouter } from 'expo-router'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { api, DocCategory, Document } from '@/api'; import { useT } from '@/i18n'; import { AppBar } from '@/components/AppBar'; import { Badge, Button, Card, IconButton, Loading } from '@/components/ui'; import { CategoryPill, ExpiryBadge } from '@/components/domain'; import { PdfView } from '@/components/PdfView'; import { getLocalFile, openInSystemViewer, shareDocument } from '@/lib/documentFile'; import { formatBytes, formatDate } from '@/lib/format'; import { colors, fontSize, radii, spacing } from '@/theme'; export default function DocumentDetailScreen() { const { id, propertyId } = useLocalSearchParams<{ id: string; propertyId?: string }>(); const docId = Number(id); const pid = propertyId ? Number(propertyId) : undefined; const router = useRouter(); const qc = useQueryClient(); const t = useT(); const [deleting, setDeleting] = useState(false); const [busy, setBusy] = useState<'open' | 'share' | null>(null); // Prefer the cached list entry; fetch only if we arrived without one. const listQuery = useQuery({ queryKey: ['documents', pid], queryFn: () => api.documents.listByProperty(pid as number), enabled: pid != null, }); const cached = listQuery.data?.find((d: Document) => d.id === docId); const singleQuery = useQuery({ queryKey: ['document', docId], queryFn: () => api.documents.get(docId), enabled: !cached && pid == null, }); const doc: Document | undefined = cached ?? singleQuery.data; const catsQuery = useQuery({ queryKey: ['categories'], queryFn: () => api.reference.categories() }); const catName = (slug: string) => catsQuery.data?.find((c: DocCategory) => c.slug === slug)?.name ?? slug; // Downloaded with the bearer header, for the preview and the phone's viewer. const fileQuery = useQuery({ queryKey: ['document-file', docId], queryFn: () => getLocalFile(doc as Document), enabled: !!doc?.fileUri, retry: false, }); const removeMutation = useMutation({ mutationFn: () => api.documents.remove(docId), onSuccess: () => { qc.invalidateQueries({ queryKey: ['documents'] }); qc.invalidateQueries({ queryKey: ['all-documents'] }); qc.invalidateQueries({ queryKey: ['properties'] }); router.back(); }, }); function confirmDelete() { Alert.alert(t('document.deleteTitle'), t('document.deleteBody'), [ { text: t('common.cancel'), style: 'cancel' }, { text: t('common.delete'), style: 'destructive', onPress: () => { setDeleting(true); removeMutation.mutate(undefined, { onSettled: () => setDeleting(false) }); }, }, ]); } async function onOpen() { if (!doc) return; setBusy('open'); try { await openInSystemViewer(doc); } catch (e: any) { Alert.alert(t('document.cannotOpen'), e?.message ?? t('document.cannotOpenBody')); } finally { setBusy(null); } } async function onShare() { if (!doc) return; setBusy('share'); try { await shareDocument(doc); } catch (e: any) { Alert.alert(t('document.cannotSave'), e?.message ?? t('document.cannotSaveBody')); } finally { setBusy(null); } } if (!doc) { return ( ); } const isImage = doc.mimeType.startsWith('image/'); const fileReady = !!fileQuery.data; const fileError = fileQuery.error as Error | undefined; return ( router.push(`/document/edit/${docId}?propertyId=${pid ?? ''}`)} /> } /> {doc.expiryStatus === 'expiring' || doc.expiryStatus === 'expired' ? ( router.push(`/document/edit/${docId}?propertyId=${pid ?? ''}`)} style={[ styles.banner, doc.expiryStatus === 'expired' ? { backgroundColor: colors.dangerBg, borderColor: '#f0c2c9' } : { backgroundColor: colors.warningBg, borderColor: '#f0dcae' }, ]} > {doc.expiryStatus === 'expired' ? t('document.expired') : t('document.expiringSoon')} {doc.expiryDate ? t('document.expiresOn', { date: formatDate(doc.expiryDate) }) : t('document.checkExpiry')} ) : null} {/* Preview — always from the downloaded local copy, never a raw URL. */} {fileQuery.isLoading ? ( ) : fileError ? ( {fileError.message} ) : isImage && fileReady ? ( ) : fileReady ? ( ) : ( )} {doc.pageCount ? ( ) : null} {doc.name}