import { useMemo } from "react"; import { ActivityIndicator, Pressable, StyleSheet, Text, View, type StyleProp, type ViewStyle, } from "react-native"; import { WebView } from "react-native-webview"; import { fonts, radii, spacing } from "@/constants/theme"; import { useAppTheme } from "@/contexts/ThemeContext"; import { canPreviewPdfInput, type InvoicePdfPreviewInput, } from "@/lib/invoice-pdf-input"; import type { ThemeColors } from "@/lib/theme-palette"; import { useThemedStyles } from "@/lib/use-themed-styles"; import { api } from "@/lib/trpc"; type InvoicePdfPreviewProps = { input: InvoicePdfPreviewInput | null; height?: number; style?: StyleProp; }; function buildPdfHtml(contentType: string, base64: string) { return ` `; } export function InvoicePdfPreview({ input, height = 560, style, }: InvoicePdfPreviewProps) { const { colors } = useAppTheme(); const styles = useThemedStyles(createPreviewStyles); const enabled = canPreviewPdfInput(input); const { data, isLoading, isFetching, error, refetch } = api.invoices.previewPdf.useQuery(input!, { enabled, refetchOnWindowFocus: false, staleTime: 5_000, }); const html = useMemo(() => { if (!data?.base64) return null; return buildPdfHtml(data.contentType, data.base64); }, [data]); if (!enabled) { return ( Select a client and add a description to every line item to preview the PDF. ); } if (isLoading && !html) { return ( Generating preview… ); } if (error) { return ( {error.message} void refetch()}> Try again ); } if (!html) { return ( PDF preview will appear here. ); } return ( {isFetching ? ( ) : null} ); } const createPreviewStyles = (colors: ThemeColors) => StyleSheet.create({ wrapper: { gap: spacing.xs, }, frame: { overflow: "hidden", borderRadius: radii.lg, borderWidth: 1, borderColor: colors.border, backgroundColor: colors.muted, }, webview: { flex: 1, backgroundColor: "transparent", }, centered: { alignItems: "center", justifyContent: "center", padding: spacing.lg, gap: spacing.sm, }, placeholder: { fontFamily: fonts.body, fontSize: 14, lineHeight: 20, color: colors.mutedForeground, textAlign: "center", padding: spacing.lg, }, loadingText: { fontFamily: fonts.body, fontSize: 13, color: colors.mutedForeground, }, errorText: { fontFamily: fonts.body, fontSize: 14, color: colors.destructive, textAlign: "center", }, retry: { fontFamily: fonts.bodySemiBold, fontSize: 14, }, refreshing: { position: "absolute", top: spacing.sm, right: spacing.sm, zIndex: 2, borderRadius: radii.pill, backgroundColor: colors.card, padding: spacing.xs, }, });