"use client"; import { Building, Mail, Phone, Save, Globe, BadgeDollarSign, Image, Star, Loader2, ArrowLeft, } from "lucide-react"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { useEffect, useState, useRef } from "react"; import { toast } from "sonner"; 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 { FormSkeleton } from "~/components/ui/skeleton"; import { Switch } from "~/components/ui/switch"; import { AddressForm } from "~/components/forms/address-form"; import { FloatingActionBar } from "~/components/layout/floating-action-bar"; import { api } from "~/trpc/react"; import { formatPhoneNumber, formatWebsiteUrl, formatTaxId, isValidEmail, VALIDATION_MESSAGES, PLACEHOLDERS, } from "~/lib/form-constants"; interface BusinessFormProps { businessId?: string; mode: "create" | "edit"; } interface FormData { name: string; email: string; phone: string; addressLine1: string; addressLine2: string; city: string; state: string; postalCode: string; country: string; website: string; taxId: string; logoUrl: string; isDefault: boolean; } interface FormErrors { name?: string; email?: string; phone?: string; addressLine1?: string; city?: string; state?: string; postalCode?: string; country?: string; website?: string; taxId?: string; } const initialFormData: FormData = { name: "", email: "", phone: "", addressLine1: "", addressLine2: "", city: "", state: "", postalCode: "", country: "United States", website: "", taxId: "", logoUrl: "", isDefault: false, }; export function BusinessForm({ businessId, mode }: BusinessFormProps) { const router = useRouter(); const [formData, setFormData] = useState(initialFormData); const [errors, setErrors] = useState({}); const [isSubmitting, setIsSubmitting] = useState(false); const [isDirty, setIsDirty] = useState(false); const footerRef = useRef(null); // Fetch business data if editing const { data: business, isLoading: isLoadingBusiness } = api.businesses.getById.useQuery( { id: businessId! }, { enabled: mode === "edit" && !!businessId }, ); const createBusiness = api.businesses.create.useMutation({ onSuccess: () => { toast.success("Business created successfully"); router.push("/dashboard/businesses"); }, onError: (error) => { toast.error(error.message || "Failed to create business"); }, }); const updateBusiness = api.businesses.update.useMutation({ onSuccess: () => { toast.success("Business updated successfully"); router.push("/dashboard/businesses"); }, onError: (error) => { toast.error(error.message || "Failed to update business"); }, }); // Load business data when editing useEffect(() => { if (business && mode === "edit") { setFormData({ name: business.name, email: business.email ?? "", phone: business.phone ?? "", addressLine1: business.addressLine1 ?? "", addressLine2: business.addressLine2 ?? "", city: business.city ?? "", state: business.state ?? "", postalCode: business.postalCode ?? "", country: business.country ?? "United States", website: business.website ?? "", taxId: business.taxId ?? "", logoUrl: business.logoUrl ?? "", isDefault: business.isDefault ?? false, }); } }, [business, mode]); const handleInputChange = (field: string, value: string | boolean) => { setFormData((prev) => ({ ...prev, [field]: value })); setIsDirty(true); // Clear error for this field when user starts typing if (errors[field as keyof FormErrors]) { setErrors((prev) => ({ ...prev, [field]: undefined })); } }; const handlePhoneChange = (value: string) => { const formatted = formatPhoneNumber(value); handleInputChange("phone", formatted); }; const handleTaxIdChange = (value: string) => { const formatted = formatTaxId(value, "EIN"); handleInputChange("taxId", formatted); }; const validateForm = (): boolean => { const newErrors: FormErrors = {}; // Required fields if (!formData.name.trim()) { newErrors.name = VALIDATION_MESSAGES.required; } // Email validation if (formData.email && !isValidEmail(formData.email)) { newErrors.email = VALIDATION_MESSAGES.email; } // Phone validation (basic check for US format) if (formData.phone) { const phoneDigits = formData.phone.replace(/\D/g, ""); if (phoneDigits.length > 0 && phoneDigits.length < 10) { newErrors.phone = VALIDATION_MESSAGES.phone; } } // Address validation if any address field is filled const hasAddressData = formData.addressLine1 || formData.city || formData.state || formData.postalCode; if (hasAddressData) { if (!formData.addressLine1) newErrors.addressLine1 = VALIDATION_MESSAGES.required; if (!formData.city) newErrors.city = VALIDATION_MESSAGES.required; if (!formData.country) newErrors.country = VALIDATION_MESSAGES.required; if (formData.country === "United States") { if (!formData.state) newErrors.state = VALIDATION_MESSAGES.required; if (!formData.postalCode) newErrors.postalCode = VALIDATION_MESSAGES.required; } } setErrors(newErrors); return Object.keys(newErrors).length === 0; }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!validateForm()) { toast.error("Please correct the errors in the form"); return; } setIsSubmitting(true); try { // Format website URL before submission const dataToSubmit = { ...formData, website: formData.website ? formatWebsiteUrl(formData.website) : "", }; if (mode === "create") { await createBusiness.mutateAsync(dataToSubmit); } else { await updateBusiness.mutateAsync({ id: businessId!, ...dataToSubmit, }); } } finally { setIsSubmitting(false); } }; const handleCancel = () => { if (isDirty) { const confirmed = window.confirm( "You have unsaved changes. Are you sure you want to leave?", ); if (!confirmed) return; } router.push("/dashboard/businesses"); }; if (mode === "edit" && isLoadingBusiness) { return ; } return (
{/* Main Form Container - styled like data table */}
{/* Basic Information */}
Basic Information

Enter your business details

handleInputChange("name", e.target.value)} placeholder={PLACEHOLDERS.name} className={`${errors.name ? "border-destructive" : ""}`} disabled={isSubmitting} /> {errors.name && (

{errors.name}

)}
handleTaxIdChange(e.target.value)} placeholder={PLACEHOLDERS.taxId} className={`${errors.taxId ? "border-destructive" : ""}`} disabled={isSubmitting} maxLength={10} /> {errors.taxId && (

{errors.taxId}

)}
handleInputChange("email", e.target.value)} placeholder={PLACEHOLDERS.email} className={`${errors.email ? "border-destructive" : ""}`} disabled={isSubmitting} /> {errors.email && (

{errors.email}

)}
handlePhoneChange(e.target.value)} placeholder={PLACEHOLDERS.phone} className={`${errors.phone ? "border-destructive" : ""}`} disabled={isSubmitting} /> {errors.phone && (

{errors.phone}

)}
handleInputChange("website", e.target.value)} placeholder={PLACEHOLDERS.website} className={`${errors.website ? "border-destructive" : ""}`} disabled={isSubmitting} /> {errors.website && (

{errors.website}

)}
{/* Address */}
Business Address

Your business location

{/* Settings */}
Settings

Configure business preferences

Set this as your default business for new invoices

handleInputChange("isDefault", checked) } disabled={isSubmitting} />
{/* Form Actions - original position */}

{mode === "create" ? "Creating a new business" : "Editing business details"}

); }