diff --git a/client/messages/en.json b/client/messages/en.json index 137a460..96fce49 100644 --- a/client/messages/en.json +++ b/client/messages/en.json @@ -309,6 +309,10 @@ "line_hint": "Building, street, unit — the detail a nurse needs to find the door.", "line_required": "Enter the street address", "city_required": "Select a city", + "recipient_name_label": "Recipient name", + "recipient_name_required": "Enter who the nurse should ask for", + "recipient_phone_label": "Recipient phone", + "recipient_phone_invalid": "Enter a valid Iranian mobile number", "set_primary_toggle": "Set as primary address", "map_hint": "Tap or drag the marker to the patient's exact location.", "map_required": "Drop a pin on the map", diff --git a/client/messages/fa.json b/client/messages/fa.json index bec5600..b383c03 100644 --- a/client/messages/fa.json +++ b/client/messages/fa.json @@ -309,6 +309,10 @@ "line_hint": "پلاک، خیابان، واحد — جزئیاتی که پرستار برای یافتن درِ منزل نیاز دارد.", "line_required": "نشانی کامل را وارد کنید", "city_required": "شهر را انتخاب کنید", + "recipient_name_label": "نام تحویل‌گیرنده", + "recipient_name_required": "نام فردی که پرستار باید بپرسد را وارد کنید", + "recipient_phone_label": "شماره تماس تحویل‌گیرنده", + "recipient_phone_invalid": "یک شماره موبایل معتبر ایرانی وارد کنید", "set_primary_toggle": "به‌عنوان آدرس اصلی تنظیم شود", "map_hint": "برای تعیین محل دقیق بیمار، نشانگر را بکشید یا روی نقشه بزنید.", "map_required": "روی نقشه یک پین بگذارید", diff --git a/client/src/app/[locale]/(private-routes)/(customer)/addresses/page.tsx b/client/src/app/[locale]/(private-routes)/(customer)/addresses/page.tsx index a161c6a..3f28f7a 100644 --- a/client/src/app/[locale]/(private-routes)/(customer)/addresses/page.tsx +++ b/client/src/app/[locale]/(private-routes)/(customer)/addresses/page.tsx @@ -172,6 +172,8 @@ export default function AddressesPage() { latitude: editing.latitude, longitude: editing.longitude, isPrimary: editing.isPrimary, + recipientName: editing.recipientName, + recipientPhone: editing.recipientPhone, } : undefined } diff --git a/client/src/components/geography/AddressForm.test.tsx b/client/src/components/geography/AddressForm.test.tsx index d753638..7a5d9bb 100644 --- a/client/src/components/geography/AddressForm.test.tsx +++ b/client/src/components/geography/AddressForm.test.tsx @@ -51,6 +51,8 @@ describe(' component', () => { latitude: 35.7, longitude: 51.4, isPrimary: false, + recipientName: 'Sara', + recipientPhone: '09120001234', }} onSubmit={onSubmit} /> @@ -67,6 +69,8 @@ describe(' component', () => { latitude: 35.7, longitude: 51.4, isPrimary: false, + recipientName: 'Sara', + recipientPhone: '09120001234', }); }); }); diff --git a/client/src/components/geography/AddressForm.tsx b/client/src/components/geography/AddressForm.tsx index 326a452..e42009c 100644 --- a/client/src/components/geography/AddressForm.tsx +++ b/client/src/components/geography/AddressForm.tsx @@ -7,6 +7,7 @@ import Stack from '@mui/material/Stack'; import Switch from '@mui/material/Switch'; import { AppButton } from '@/components/common'; import { RhfControlGroup, RhfTextField } from '@/components/common/form'; +import PhoneNumberField, { isIranianMobile } from '@/components/PhoneNumberField'; import { cityCentroid } from '@/services/geography/constants'; import type { CreateAddressInput, LatLng } from '@/services/addresses/types'; import CascadingRegionSelect, { type CascadingRegionValue } from './CascadingRegionSelect'; @@ -22,6 +23,8 @@ export interface AddressFormInitial { latitude?: number | null; longitude?: number | null; isPrimary?: boolean; + recipientName?: string | null; + recipientPhone?: string | null; } export interface AddressFormProps { @@ -39,6 +42,8 @@ interface AddressFormValues { pin: LatLng | null; addressLine: string; isPrimary: boolean; + recipientName: string; + recipientPhone: string; } // Only prefill the region when we have the province — a city id without its province can't drive @@ -78,6 +83,8 @@ const AddressForm: FunctionComponent = ({ initial, submitting pin: initialPin(initial), addressLine: initial?.addressLine ?? '', isPrimary: initial?.isPrimary ?? false, + recipientName: initial?.recipientName ?? '', + recipientPhone: initial?.recipientPhone ?? '', }, }); const { control, handleSubmit, formState } = form; @@ -98,6 +105,8 @@ const AddressForm: FunctionComponent = ({ initial, submitting latitude: (values.pin as LatLng).latitude, longitude: (values.pin as LatLng).longitude, isPrimary: values.isPrimary, + recipientName: values.recipientName.trim(), + recipientPhone: values.recipientPhone, }); }; @@ -153,6 +162,29 @@ const AddressForm: FunctionComponent = ({ initial, submitting fullWidth /> + + name="recipientName" + label={t('recipient_name_label')} + rules={{ validate: (value) => String(value ?? '').trim().length > 0 || t('recipient_name_required') }} + fullWidth + /> + + + name="recipientPhone" + rules={{ validate: (value) => isIranianMobile(String(value ?? '')) }} + > + {({ field, hasError }) => ( + + )} + + name="isPrimary"> {({ field }) => (