initial commit

This commit is contained in:
ray
2026-07-12 10:17:17 -04:00
commit dab5a4ebc6
1424 changed files with 330463 additions and 0 deletions
@@ -0,0 +1,62 @@
# 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 `<input>`:
```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.