'use client' import { useTranslations } from 'next-intl' import { useState, useCallback, useRef, type ChangeEvent } from 'react' import { Loader2, Trash2, Upload } from 'lucide-react' import { Button } from '@/components/ui/button' import { Label } from '@/components/ui/label' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' import { Switch } from '@/components/ui/switch' import { Textarea } from '@/components/ui/textarea' import { useToast } from '@/components/ui/use-toast' import { INVOICE_FONT_FAMILIES } from '@/lib/invoices/branding-constants' import { getErrorMessage as getUserErrorMessage } from '@/lib/errors/get-error-message' import type { CompanySettings, InvoiceFontFamily } from '@/types' interface PdfPrintSettingsProps { settings: CompanySettings onUpdate: (updates: Partial) => void } export function PdfPrintSettings({ settings, onUpdate }: PdfPrintSettingsProps) { const t = useTranslations('settings_pdf_print') const { toast } = useToast() const [lateFeeText, setLateFeeText] = useState(settings.invoice_late_fee_text || '') const [creditTermsText, setCreditTermsText] = useState(settings.invoice_credit_terms_text || '') const [isSavingFont, setIsSavingFont] = useState(false) const [isUploadingFont, setIsUploadingFont] = useState(false) const [isDeletingFont, setIsDeletingFont] = useState(false) const fontInputRef = useRef(null) const saveToggle = useCallback(async (field: string, value: boolean) => { try { const response = await fetch('/api/settings', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ [field]: value }), }) if (!response.ok) throw new Error() onUpdate({ [field]: value } as Partial) } catch { toast({ title: t('toast_save_failed'), variant: 'destructive' }) } }, [onUpdate, toast, t]) const savePosition = useCallback(async (value: 'header' | 'footer') => { try { const response = await fetch('/api/settings', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ invoice_company_name_position: value }), }) if (!response.ok) throw new Error() onUpdate({ invoice_company_name_position: value }) } catch { toast({ title: t('toast_save_failed'), variant: 'destructive' }) } }, [onUpdate, toast, t]) const saveText = useCallback(async (field: string, value: string) => { try { const response = await fetch('/api/settings', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ [field]: value || null }), }) if (!response.ok) throw new Error() onUpdate({ [field]: value || null } as Partial) } catch { toast({ title: t('toast_save_failed'), variant: 'destructive' }) } }, [onUpdate, toast, t]) const saveFont = useCallback(async (fontFamily: InvoiceFontFamily) => { setIsSavingFont(true) try { const response = await fetch('/api/settings', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ invoice_font_family: fontFamily }), }) const result = await response.json() if (!response.ok) throw new Error(result.error || t('toast_save_failed')) onUpdate({ invoice_font_family: fontFamily }) } catch (error) { toast({ title: t('toast_save_failed'), description: error instanceof Error ? getUserErrorMessage(error) : undefined, variant: 'destructive', }) } finally { setIsSavingFont(false) } }, [onUpdate, toast, t]) async function uploadFont(file: File) { setIsUploadingFont(true) try { const formData = new FormData() formData.append('file', file) const response = await fetch('/api/settings/invoice-font', { method: 'POST', body: formData, }) const result = await response.json() if (!response.ok) throw new Error(result.error || t('font_upload_failed')) onUpdate(result.data as Partial) } catch (error) { toast({ title: t('font_upload_failed'), description: error instanceof Error ? getUserErrorMessage(error) : undefined, variant: 'destructive', }) } finally { setIsUploadingFont(false) if (fontInputRef.current) fontInputRef.current.value = '' } } async function deleteFont() { setIsDeletingFont(true) try { const response = await fetch('/api/settings/invoice-font', { method: 'DELETE' }) const result = await response.json() if (!response.ok) throw new Error(result.error || t('font_delete_failed')) onUpdate(result.data as Partial) } catch (error) { toast({ title: t('font_delete_failed'), description: error instanceof Error ? getUserErrorMessage(error) : undefined, variant: 'destructive', }) } finally { setIsDeletingFont(false) } } function handleFontChange(event: ChangeEvent) { const file = event.target.files?.[0] if (file) void uploadFont(file) } const fontLabels: Record = { Helvetica: t('font_helvetica'), 'Times-Roman': t('font_times'), Courier: t('font_courier'), 'Source Sans 3': t('font_source_sans'), 'Source Serif 4': t('font_source_serif'), Custom: t('font_custom'), } return (

{t('heading')}

{t('font_help')}

{settings.invoice_custom_font_path && ( )}
{settings.invoice_custom_font_name && (

{t('font_uploaded_name', { name: settings.invoice_custom_font_name })}

)}

{t('font_file_help')}

{t('ore_rounding_help')}

saveToggle('ore_rounding', v)} />

{t('show_ocr_help')}

saveToggle('invoice_show_ocr', v)} />

{t('show_bankgiro_help')}

saveToggle('invoice_show_bankgiro', v)} />

{t('show_plusgiro_help')}

saveToggle('invoice_show_plusgiro', v)} />

{t('show_swish_help')}

saveToggle('invoice_show_swish', v)} aria-label={t('show_swish_label')} />

{t('show_logo_help')}

saveToggle('invoice_show_logo', v)} />

{t('show_company_name_help')}

saveToggle('invoice_show_company_name', v)} />
{(settings.invoice_show_company_name ?? true) && (

{t('placement_label')}

{(['header', 'footer'] as const).map((pos) => { const active = (settings.invoice_company_name_position ?? 'header') === pos return ( ) })}
)}