# Phone Number Formatting All phone numbers in SPQ are **stored as raw digits** (no formatting) and **displayed/input as `555-555-5555`** (hyphen-separated, no parentheses). ## Shared Utility: `src/lib/phone.ts` Two exports: - **`formatPhoneInput(raw: string): string`** — live input mask for onChange. Strips non-digits, inserts hyphens as user types. - `""` → `""` - `"555"` → `"555"` - `"5555"` → `"555-5"` - `"5555555555"` → `"555-555-5555"` - **`formatPhoneDisplay(phone: string | null | undefined): string`** — display formatter for read-only contexts (tables, PDFs, previews). - `"5555555555"` → `"555-555-5555"` - `"5551234"` → `"555-1234"` (7-digit fallback) - Handles legacy formatted data (strips parens, spaces, dots). ## Input Pattern (onChange + value) For every phone ``: ```tsx import { formatPhoneInput } from '../lib/phone'; // In the input: value={formatPhoneInput(phoneValue)} onChange={(e) => setPhone(e.target.value.replace(/\D/g, ''))} placeholder="555-555-5555" ``` This stores raw digits (stripped on every keystroke) and displays the mask. ## Display Pattern For every read-only phone render: ```tsx import { formatPhoneDisplay } from '../lib/phone'; // In JSX: {formatPhoneDisplay(customer.phone)} // In template literals: `${formatPhoneDisplay(inv.customerPhone)}` ``` ## Files Using Phone Formatting | File | Applied | |---|---| | `QuoteGenerator.tsx` | CustomerInfoPanel phone field | | `ROForm.tsx` | RO create/edit phone field | | `Appointments.tsx` | 3 inputs + list display | | `Invoices.tsx` | 1 input + printable HTML + preview | | `Customers.tsx` | 1 input + 2 displays (card + detail) | ## Pitfalls - **Stored data may be legacy-formatted** — `formatPhoneDisplay` and `formatPhoneInput` both strip non-digits first, so legacy `(555) 555-5555` data is handled. - **Don't store the formatted value** — the `onChange` handler must strip formatting (`.replace(/\D/g, '')`) so PocketBase only contains raw digits. - **Don't create local formatPhone functions** — always import from `src/lib/phone.ts`. Duplicate implementations exist in legacy code and should be replaced.