import { createFileRoute } from "@tanstack/react-router"; import { useEffect, useRef, useState } from "react"; import { supabase } from "@/integrations/supabase/client"; import { useAuth } from "@/lib/auth"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { Loader2, Upload, Trash2, Building2 } from "lucide-react"; import { toast } from "sonner"; export const Route = createFileRoute("/settings/")({ component: CompanySettingsPage, }); const EMPTY = { company_name: "", contact_email: "", contact_phone: "", website: "", address_line1: "", address_line2: "", city: "", state: "", postal_code: "", country: "", invoice_prefix: "", default_tax_rate: "", footer_note: "", logo_storage_path: "" as string | null | "", }; function CompanySettingsPage() { const { user } = useAuth(); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [uploading, setUploading] = useState(false); const [recordId, setRecordId] = useState(null); const [form, setForm] = useState({ ...EMPTY }); const [logoUrl, setLogoUrl] = useState(null); const fileInput = useRef(null); const load = async () => { setLoading(true); const { data } = await supabase .from("firm_settings") .select("*") .order("updated_at", { ascending: false }) .limit(1) .maybeSingle(); if (data) { setRecordId(data.id); setForm({ company_name: data.company_name ?? "", contact_email: data.contact_email ?? "", contact_phone: data.contact_phone ?? "", website: data.website ?? "", address_line1: data.address_line1 ?? "", address_line2: data.address_line2 ?? "", city: data.city ?? "", state: data.state ?? "", postal_code: data.postal_code ?? "", country: data.country ?? "", invoice_prefix: data.invoice_prefix ?? "", default_tax_rate: data.default_tax_rate != null ? String(data.default_tax_rate) : "", footer_note: data.footer_note ?? "", logo_storage_path: data.logo_storage_path ?? "", }); if (data.logo_storage_path) { const { data: pub } = supabase.storage .from("firm-logos") .getPublicUrl(data.logo_storage_path); setLogoUrl(pub.publicUrl); } else { setLogoUrl(null); } } setLoading(false); }; useEffect(() => { load(); }, []); const update = (k: keyof typeof EMPTY, v: string) => setForm((f) => ({ ...f, [k]: v })); const onLogoFile = async (file: File) => { setUploading(true); const ext = file.name.split(".").pop() || "png"; const path = `firm-${Date.now()}.${ext}`; const { error } = await supabase.storage .from("firm-logos") .upload(path, file, { upsert: true, contentType: file.type }); if (error) { setUploading(false); toast.error("Upload failed", { description: error.message }); return; } setForm((f) => ({ ...f, logo_storage_path: path })); const { data: pub } = supabase.storage .from("firm-logos") .getPublicUrl(path); setLogoUrl(pub.publicUrl); setUploading(false); toast.success("Logo uploaded — remember to save"); }; const removeLogo = () => { setForm((f) => ({ ...f, logo_storage_path: "" })); setLogoUrl(null); }; const save = async () => { setSaving(true); const payload: any = { company_name: form.company_name || null, contact_email: form.contact_email || null, contact_phone: form.contact_phone || null, website: form.website || null, address_line1: form.address_line1 || null, address_line2: form.address_line2 || null, city: form.city || null, state: form.state || null, postal_code: form.postal_code || null, country: form.country || null, invoice_prefix: form.invoice_prefix || null, default_tax_rate: form.default_tax_rate ? parseFloat(form.default_tax_rate) : null, footer_note: form.footer_note || null, logo_storage_path: form.logo_storage_path || null, updated_by: user?.id, }; const { error } = recordId ? await supabase.from("firm_settings").update(payload).eq("id", recordId) : await supabase.from("firm_settings").insert(payload); setSaving(false); if (error) { toast.error("Could not save", { description: error.message }); return; } toast.success("Settings saved"); load(); }; if (loading) { return (
); } return (
Company logo
{logoUrl ? ( Firm logo ) : ( )}
{ const f = e.target.files?.[0]; if (f) onLogoFile(f); }} />
{logoUrl && ( )}

PNG, JPG or SVG recommended. Max ~2 MB.

Company information update("company_name", e.target.value)} /> update("website", e.target.value)} placeholder="https://" /> update("contact_email", e.target.value)} /> update("contact_phone", e.target.value)} /> update("address_line1", e.target.value)} /> update("address_line2", e.target.value)} /> update("city", e.target.value)} /> update("state", e.target.value)} /> update("postal_code", e.target.value)} /> update("country", e.target.value)} /> Invoice defaults update("invoice_prefix", e.target.value)} placeholder="e.g. INV-" /> update("default_tax_rate", e.target.value)} />