import { useEffect, useState } from "react"; import { Alert, KeyboardAvoidingView, Platform, ScrollView, StyleSheet, Switch, Text, View, } from "react-native"; import { Button } from "@/components/ui/Button"; import { Card } from "@/components/ui/Card"; import { Input } from "@/components/ui/Input"; import { fonts, spacing } from "@/constants/theme"; import { useAppTheme } from "@/contexts/ThemeContext"; import type { ThemeColors } from "@/lib/theme-palette"; import { useThemedStyles } from "@/lib/use-themed-styles"; import { api } from "@/lib/trpc"; type BusinessFormValues = { name: string; nickname: string; email: string; phone: string; addressLine1: string; addressLine2: string; city: string; state: string; postalCode: string; country: string; website: string; taxId: string; isDefault: boolean; }; const emptyValues: BusinessFormValues = { name: "", nickname: "", email: "", phone: "", addressLine1: "", addressLine2: "", city: "", state: "", postalCode: "", country: "United States", website: "", taxId: "", isDefault: false, }; type BusinessFormProps = { mode: "create" | "edit"; businessId?: string; scrollPadding: number; onSaved: () => void; onDeleted?: () => void; }; export function BusinessForm({ mode, businessId, scrollPadding, onSaved, onDeleted, }: BusinessFormProps) { const { colors } = useAppTheme(); const styles = useThemedStyles(createBusinessFormStyles); const utils = api.useUtils(); const businessQuery = api.businesses.getById.useQuery( { id: businessId ?? "" }, { enabled: mode === "edit" && Boolean(businessId) }, ); const [values, setValues] = useState(emptyValues); const [fieldError, setFieldError] = useState(null); const switchProps = { trackColor: { false: colors.switchTrackOff, true: colors.switchTrackOn }, thumbColor: Platform.OS === "android" ? colors.switchThumb : undefined, ios_backgroundColor: colors.switchIosBackground, }; useEffect(() => { const business = businessQuery.data; if (!business) return; setValues({ name: business.name, nickname: business.nickname ?? "", 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 ?? "", isDefault: business.isDefault ?? false, }); }, [businessQuery.data]); const createBusiness = api.businesses.create.useMutation({ onSuccess: () => { void utils.businesses.getAll.invalidate(); onSaved(); }, onError: (err) => setFieldError(err.message), }); const updateBusiness = api.businesses.update.useMutation({ onSuccess: () => { void utils.businesses.getAll.invalidate(); if (businessId) void utils.businesses.getById.invalidate({ id: businessId }); onSaved(); }, onError: (err) => setFieldError(err.message), }); const deleteBusiness = api.businesses.delete.useMutation({ onSuccess: () => { void utils.businesses.getAll.invalidate(); onDeleted?.(); }, onError: (err) => Alert.alert("Could not delete business", err.message), }); function patch(field: K, value: BusinessFormValues[K]) { setValues((prev) => ({ ...prev, [field]: value })); setFieldError(null); } function buildPayload() { return { name: values.name.trim(), nickname: values.nickname.trim(), email: values.email.trim(), phone: values.phone.trim(), addressLine1: values.addressLine1.trim(), addressLine2: values.addressLine2.trim(), city: values.city.trim(), state: values.state.trim(), postalCode: values.postalCode.trim(), country: values.country.trim() || "United States", website: values.website.trim(), taxId: values.taxId.trim(), isDefault: values.isDefault, }; } function handleSave() { if (!values.name.trim()) { setFieldError("Business name is required"); return; } const payload = buildPayload(); if (mode === "create") { createBusiness.mutate(payload); return; } if (!businessId) return; updateBusiness.mutate({ id: businessId, ...payload }); } function confirmDelete() { if (!businessId) return; Alert.alert( "Delete business", "This cannot be undone. Businesses with invoices cannot be deleted.", [ { text: "Cancel", style: "cancel" }, { text: "Delete", style: "destructive", onPress: () => deleteBusiness.mutate({ id: businessId }), }, ], ); } const saving = createBusiness.isPending || updateBusiness.isPending; return ( patch("name", v)} /> patch("nickname", v)} placeholder="Optional short name" /> patch("email", v)} keyboardType="email-address" autoCapitalize="none" /> patch("phone", v)} keyboardType="phone-pad" /> patch("website", v)} autoCapitalize="none" keyboardType="url" placeholder="https://" /> patch("taxId", v)} placeholder="Optional" /> Default business Used for new invoices when none is selected patch("isDefault", v)} {...switchProps} /> patch("addressLine1", v)} /> patch("addressLine2", v)} /> patch("city", v)} /> patch("state", v)} /> patch("postalCode", v)} /> patch("country", v)} /> {fieldError ? {fieldError} : null}