import { useEffect, useRef, useState } from 'react'; import { AlertCircle, CheckCircle2, Loader2 } from 'lucide-react'; import { useOrganizationServiceContext } from '../../../services/OrganizationService.tsx'; import { Button } from '../../../components/ui/button.tsx'; import { Input } from '../../../components/ui/input.tsx'; import { Label } from '../../../components/ui/label.tsx'; import { Alert, AlertDescription } from '../../../components/ui/alert.tsx'; import { getOrganizationTaxRate } from '../../../utils/organizationTaxRate'; import './TaxSettingsSection.css'; import { relayServerFailure } from '../../../utils/fetchFailureMessage'; import { READ_BACK_FAILED, useBillingDefaultSave } from '../BillingPage/useBillingDefaultSave'; const parseRate = (raw: string): number | undefined => { if (raw.trim() === '') { return undefined; } const parsed = Number(raw); if (!Number.isFinite(parsed) || parsed < 0 || parsed > 100) { return undefined; } return parsed; }; const TaxSettingsSection = () => { const { updateTaxSettings } = useOrganizationServiceContext(); const [rate, setRate] = useState('0'); const [saving, setSaving] = useState(false); const [saveError, setSaveError] = useState(); const [saveSuccess, setSaveSuccess] = useState(false); // Seeded from the practice on screen whenever it, or the person signed in, changes; whatever was saving is retired. const seed = useRef(() => undefined as void); const { organization, practiceId, save, readBack, unsettled, checksHere } = useBillingDefaultSave('organization-tax-settings', 'tax', () => seed.current()); seed.current = () => { setRate(String(getOrganizationTaxRate(organization ?? undefined))); setSaving(false); setSaveError(undefined); setSaveSuccess(false); }; useEffect(() => { seed.current(); }, [practiceId]); const parsedRate = parseRate(rate); const canSave = parsedRate !== undefined && !unsettled; const handleSave = async () => { if (parsedRate === undefined) { setSaveError('Enter a tax rate between 0 and 100.'); return; } setSaving(true); setSaveError(undefined); setSaveSuccess(false); const result = await save((transport) => updateTaxSettings({ ratePercent: parsedRate }, transport)); if (result.outcome === 'retired') return; setSaving(false); if (result.outcome === 'saved') { setSaveSuccess(true); } else if (result.outcome !== 'unconfirmed' && result.outcome !== 'held') { console.error('Error saving tax settings:', result.error); setSaveError(relayServerFailure(result.error, 'Failed to save tax settings. Please try again.')); } }; const checkSaved = async () => { setSaving(true); const fresh = await readBack(); if (fresh === 'retired') return; setSaving(false); if (!fresh) { setSaveError(READ_BACK_FAILED); return; } setRate(String(getOrganizationTaxRate(fresh))); setSaveError(undefined); }; return (

Sales Tax

Set the sales tax rate applied to taxable invoice line items. The rate is frozen onto each invoice when it's created — changing it here does not affect invoices already issued.

{(saveError || unsettled) && ( {saveError ?? unsettled} )} {saveSuccess && ( Tax settings saved. )}
{ setRate(event.target.value); setSaveSuccess(false); setSaveError(undefined); }} /> %
{checksHere && ( )}
); }; export default TaxSettingsSection;