'use client' import { useState, useEffect } from 'react' import useContractManagement from '../hooks/useContractManagement' function fileToDataUrl(file: File): Promise { return new Promise((resolve, reject) => { const reader = new FileReader() reader.onerror = () => reject(new Error('Failed to read file')) reader.onload = () => { const result = reader.result if (typeof result === 'string') resolve(result) else reject(new Error('Invalid file result')) } reader.readAsDataURL(file) }) } function summarizeForLog(payload: Record) { const out: Record = {} for (const [k, v] of Object.entries(payload)) { if (typeof v === 'string' && (k.toLowerCase().includes('base64') || k.toLowerCase().includes('qr_code'))) { out[k] = { kind: 'base64', len: v.length, head: v.slice(0, 32) } } else if (typeof v === 'string' && v.length > 200) { out[k] = { kind: 'string', len: v.length, head: v.slice(0, 32) } } else { out[k] = v } } return out } export default function CompanySettingsPanel() { const { getCompanySettings, updateCompanySettings } = useContractManagement() const [form, setForm] = useState({ company_name: '', company_street: '', company_postal_city: '', company_country: '', }) const [hasQr60, setHasQr60] = useState(false) const [hasQr120, setHasQr120] = useState(false) const [qr60DataUrl, setQr60DataUrl] = useState('') const [qr120DataUrl, setQr120DataUrl] = useState('') const [loading, setLoading] = useState(true) const [saving, setSaving] = useState(false) const [saved, setSaved] = useState(false) const [saveError, setSaveError] = useState('') useEffect(() => { getCompanySettings() .then(data => { setForm({ company_name: data.company_name || '', company_street: data.company_street || '', company_postal_city: data.company_postal_city || '', company_country: data.company_country || '', }) const qr60 = (data as any)?.qr_code_60_base64 ?? (data as any)?.qrCode60Base64 const qr120 = (data as any)?.qr_code_120_base64 ?? (data as any)?.qrCode120Base64 setHasQr60(!!qr60) setHasQr120(!!qr120) }) .catch(() => {}) .finally(() => setLoading(false)) }, [getCompanySettings]) const handleChange = (e: React.ChangeEvent) => { const { name, value } = e.target setForm(prev => ({ ...prev, [name]: value })) setSaved(false) } const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() setSaving(true) setSaved(false) setSaveError('') try { // IMPORTANT: send `payload` (full strings), not the redacted log view. const payload: any = { ...form } if (qr60DataUrl) payload.qr_code_60_base64 = qr60DataUrl if (qr120DataUrl) payload.qr_code_120_base64 = qr120DataUrl // For logging only (redacted); never send this object. const logPayload: any = summarizeForLog(payload) try { const qr60 = payload.qr_code_60_base64 const qr120 = payload.qr_code_120_base64 console.info('[CompanySettingsPanel] updateCompanySettings payload', { logPayload, keys: Object.keys(payload), jsonLength: JSON.stringify(payload).length, qrFieldTypes: { qr_code_60_base64: qr60 ? typeof qr60 : null, qr_code_120_base64: qr120 ? typeof qr120 : null, }, qrFieldLengths: { qr_code_60_base64: typeof qr60 === 'string' ? qr60.length : null, qr_code_120_base64: typeof qr120 === 'string' ? qr120.length : null, }, }) if (qr60 && typeof qr60 !== 'string') console.warn('[CompanySettingsPanel] qr_code_60_base64 is not a string!', qr60) if (qr120 && typeof qr120 !== 'string') console.warn('[CompanySettingsPanel] qr_code_120_base64 is not a string!', qr120) } catch {} await updateCompanySettings(payload) setSaved(true) setTimeout(() => setSaved(false), 3000) } catch { setSaveError('Could not save settings.') } finally { setSaving(false) } } const handleQrUpload = async (which: '60' | '120', file: File | null) => { setSaved(false) setSaveError('') if (!file) return // Backend accepts 10MB JSON, but base64 expands the payload. // Keep a conservative limit to avoid 413 Payload Too Large. const MAX_FILE_BYTES = 7_000_000 if (file.size > MAX_FILE_BYTES) { setSaveError('QR image is too large. Please upload a smaller PNG.') return } if (file.type && file.type !== 'image/png') { setSaveError('Please upload a PNG file for the QR code.') return } try { const dataUrl = await fileToDataUrl(file) // Normalize to raw base64, to match other endpoints (e.g. company stamp upload) const m = dataUrl.match(/^data:(.+?);base64,(.*)$/) const base64 = m ? m[2] : dataUrl if (which === '60') { setQr60DataUrl(base64) setHasQr60(true) } else { setQr120DataUrl(base64) setHasQr120(true) } } catch { setSaveError('Could not read QR image file.') } } if (loading) { return (
Loading settings…
) } return (
handleQrUpload('60', e.target.files?.[0] || null)} className="block w-full text-sm text-gray-700 file:mr-4 file:py-2 file:px-4 file:rounded-lg file:border-0 file:text-sm file:font-semibold file:bg-blue-50 file:text-blue-900 hover:file:bg-blue-100" />
{qr60DataUrl ? 'Selected (will be saved on Save)' : hasQr60 ? 'Already uploaded' : 'Not uploaded'}
handleQrUpload('120', e.target.files?.[0] || null)} className="block w-full text-sm text-gray-700 file:mr-4 file:py-2 file:px-4 file:rounded-lg file:border-0 file:text-sm file:font-semibold file:bg-blue-50 file:text-blue-900 hover:file:bg-blue-100" />
{qr120DataUrl ? 'Selected (will be saved on Save)' : hasQr120 ? 'Already uploaded' : 'Not uploaded'}
{saveError && (
{saveError}
)}
{saved && ( Saved successfully )}
) }