feat(admin): normalize Persian/Arabic digits in every numeric field
Users typing on a Persian keyboard produced two distinct failures. Fields with type="number" silently returned an empty string — the browser rejects Persian digits, so the value was lost and saved as empty or zero. Text fields passed the Persian characters straight through to the database, where a mobile stored as ۰۹۱۲… never matches 09… again. The secretary form hit the second case with no validation at all. Frontend: - Adds digitsOnly() and the national-code schemas to lib/utils, plus lib/forms with numericField()/latinDigitsField() wrappers for React Hook Form fields. - Converts every type="number" input to type="text" inputMode="numeric" with digit normalization; none remain. Fields that legitimately carry non-digits (sheba, landline) only get the digits translated, keeping IR and separators. - Points the patient national-code and mobile schemas at the shared normalizing schemas, which accept Persian input instead of rejecting it. - Drops two duplicate local digit converters in favour of the shared helper. Backend: - Adds NumericFieldNormalizerSubscriber, translating digits in whitelisted numeric keys of JSON request bodies under /api/v1/ before controllers run, so nobat724_front and clinic-pro-tauri are covered too. Translation only — no characters are stripped, non-string values and other keys are untouched. Three component tests asserted on role="spinbutton" and numeric input values; both are properties of type="number", so they were updated to match the new text inputs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -39,6 +39,39 @@ Authorization: Bearer <JWT_TOKEN>
|
||||
|
||||
---
|
||||
|
||||
## Persian digit normalization (global)
|
||||
|
||||
Persian (`۰-۹`) and Arabic (`٠-٩`) digits sent in numeric request fields are translated to Latin **server-side, before the controller runs** — `src/Shared/EventSubscriber/NumericFieldNormalizerSubscriber.php`. Every client benefits: the React admin panel, `nobat724_front`, and `clinic-pro-tauri`.
|
||||
|
||||
Applies to `POST` / `PUT` / `PATCH` requests under `/api/v1/` with a JSON body, recursively through nested arrays.
|
||||
|
||||
**Normalized keys:**
|
||||
|
||||
```
|
||||
mobile, mobile_number, telephone, phone, notification_mobile,
|
||||
national_code, postal_code,
|
||||
card_number, account_number, sheba, shaba, iban,
|
||||
price_rials, amount_rials, amount, free_visit_price_rials,
|
||||
insurance_price_rials, patient_share_rials, visit_price_rials,
|
||||
duration_minutes, duration, commission_percent, coverage,
|
||||
coverage_percent, franchise, ceiling, tax_percent,
|
||||
base_insurance_discount_percent, supplementary_discount_percent
|
||||
```
|
||||
|
||||
Only **digits** are translated — no characters are stripped, so `IR` in a sheba and `-` in a landline survive. Non-string values (`int`, `bool`, `null`) and keys outside the list are untouched, so a name like `منشی شماره ۲` keeps its Persian digit.
|
||||
|
||||
```jsonc
|
||||
// request
|
||||
{ "mobile_number": "۰۹۱۲۳۴۵۶۷۸۹", "national_code": "۰۰۱۲۳۴۵۶۷۸", "name": "منشی شماره ۲" }
|
||||
|
||||
// what the controller sees
|
||||
{ "mobile_number": "09123456789", "national_code": "0012345678", "name": "منشی شماره ۲" }
|
||||
```
|
||||
|
||||
> Adding a new numeric field to any endpoint? Add its key to `NUMERIC_KEYS` in the subscriber, otherwise Persian digits reach the database.
|
||||
|
||||
---
|
||||
|
||||
## Modules
|
||||
|
||||
| File | Domain | Endpoints |
|
||||
|
||||
@@ -79,9 +79,9 @@ Create a secretary for a doctor.
|
||||
| --------------- | ------------- | -------- | -------------------------------------------- |
|
||||
| `doctor_uuid` | string (UUID) | ✅\* | Single doctor to assign (legacy/doctor flow) |
|
||||
| `doctor_uuids` | string[] (UUID) | ✅\* | **Clinic only** — assign one secretary to several clinic doctors at once. When present (non-empty) and caller is `ROLE_CLINIC`, this multi-doctor path is used instead of `doctor_uuid` |
|
||||
| `mobile_number` | string | ✅ | Secretary's login mobile |
|
||||
| `mobile_number` | string | ✅ | Secretary's login mobile. Persian/Arabic digits are accepted and normalized server-side — see [README → Persian digit normalization](README.md#persian-digit-normalization-global) |
|
||||
| `name` | string | ❌ | Full name (نام + نام خانوادگی) → `user_name` |
|
||||
| `national_code` | string | ❌ | کد ملی منشی (nullable) |
|
||||
| `national_code` | string | ❌ | کد ملی منشی (nullable). Persian/Arabic digits accepted and normalized |
|
||||
| `address` | string | ❌ | آدرس منشی (nullable) |
|
||||
| `password` | string | ❌ | Initial password (auto-generated if omitted) |
|
||||
| `permissions` | object | ❌ | Permission set (see structure below) |
|
||||
|
||||
Reference in New Issue
Block a user