b8934f531d
Three domain services (mirroring the patients/nurse template): services/geography (cached province→city→district lookups; Infinity staleTime + shared geographyKeys), services/addresses (address book CRUD + set-primary; single-primary invariant), and services/serviceAreas (coverage add/remove; areaExists dup-guard, districtId=null = whole city). Four tested composites in src/components/geography: CascadingRegionSelect (drives the cascade queries), AddressMapPicker (map-pin stand-in emitting real lat/lng), AddressForm, AddressCard. Screens: customer address book (/addresses, reached from the profile hub) and nurse coverage editor (/nurse/coverage, new sidebar tab, inline duplicate block + 409). Adds geo/address/coverage i18n namespaces (both locales), location/delete/coverage icons, ADDRESSES/NURSE_COVERAGE routes. Consumes the b4 geography-addresses contract; filed REQ-008 (accept the map pin on create/update) and REQ-009 (provinceId on CustomerAddressDto) for gaps. Gate: npm run check + npm run test:ci (129, +17) + npm run build all green. A 5-dimension adversarial review fixed 3 findings (map-marker RTL transform, page_size→pageSize pagination casing, coverage districts-scope dead-end on district-less cities). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
268 lines
10 KiB
JSON
268 lines
10 KiB
JSON
{
|
|
"nav": {
|
|
"home": "Home",
|
|
"bookings": "Bookings",
|
|
"patients": "Patients",
|
|
"wallet": "Wallet",
|
|
"profile": "Profile",
|
|
"bank": "Bank account",
|
|
"coverage": "Coverage",
|
|
"dashboard": "Dashboard",
|
|
"verification": "Verification",
|
|
"visits": "Visits",
|
|
"admin": "Admin",
|
|
"overview": "Overview",
|
|
"users": "Users",
|
|
"notifications": "Notifications",
|
|
"login": "Login",
|
|
"logout": "Logout"
|
|
},
|
|
"common": {
|
|
"dark_mode": "Dark mode",
|
|
"light_mode": "Light mode",
|
|
"direction_ltr": "Switch to LTR",
|
|
"direction_rtl": "Switch to RTL",
|
|
"coming_soon": "Coming soon",
|
|
"loading": "Loading…",
|
|
"retry": "Retry",
|
|
"add": "Add",
|
|
"cancel": "Cancel",
|
|
"save": "Save",
|
|
"saving": "Saving…",
|
|
"back": "Back",
|
|
"close": "Close",
|
|
"optional": "Optional",
|
|
"currency_toman": "Toman",
|
|
"brand": "Balinyaar",
|
|
"brand_tagline": "Home care you can trust"
|
|
},
|
|
"shell": {
|
|
"customer_app": "Family app",
|
|
"nurse_app": "Nurse view",
|
|
"admin_console": "Admin console",
|
|
"placeholder_body": "This area will be built in a later phase."
|
|
},
|
|
"home": {
|
|
"greeting": "Welcome to Balinyaar",
|
|
"subtitle": "Manage care for the people you love.",
|
|
"nudge_patient_title": "Complete the patient record",
|
|
"nudge_patient_body": "Add conditions, medications and routine so nurses arrive prepared.",
|
|
"nudge_patient_cta": "Open patients",
|
|
"nudge_profile_title": "Complete your profile",
|
|
"nudge_profile_body": "Add an emergency contact to speed up bookings.",
|
|
"nudge_profile_cta": "Go to profile"
|
|
},
|
|
"onboarding": {
|
|
"step_relation": "Who for",
|
|
"step_patient": "Patient",
|
|
"relation_title": "Who are you arranging care for?",
|
|
"relation_subtitle": "This helps us tailor the right care. You can add more people later.",
|
|
"relation_parent": "Parent",
|
|
"relation_spouse": "Spouse",
|
|
"relation_child": "Child",
|
|
"relation_self": "Myself",
|
|
"patient_title": "Register the patient",
|
|
"patient_subtitle": "The person receiving care — not necessarily the account holder.",
|
|
"name_label": "Full name",
|
|
"name_required": "Enter the patient's name",
|
|
"age_label": "Age",
|
|
"age_invalid": "Enter a valid age",
|
|
"gender_label": "Gender",
|
|
"gender_male": "Male",
|
|
"gender_female": "Female",
|
|
"gender_required": "Patient gender is required",
|
|
"conditions_label": "Conditions",
|
|
"conditions_hint": "Optional — select any that apply.",
|
|
"condition_elderly": "Elderly",
|
|
"condition_post_surgery": "Post-surgery",
|
|
"condition_diabetes": "Diabetes",
|
|
"condition_mobility": "Limited mobility",
|
|
"condition_dementia": "Dementia",
|
|
"continue": "Continue",
|
|
"save_continue": "Save and continue",
|
|
"saved": "Patient saved"
|
|
},
|
|
"patients": {
|
|
"title": "Patients",
|
|
"subtitle": "The people you arrange care for.",
|
|
"add": "Add patient",
|
|
"add_title": "Add patient",
|
|
"edit_title": "Edit patient",
|
|
"edit": "Edit",
|
|
"archive": "Archive",
|
|
"empty_title": "No patients yet",
|
|
"empty_body": "Add your first patient to get started.",
|
|
"archive_title": "Archive patient?",
|
|
"archive_body": "This patient is removed from your list, but past booking records are kept.",
|
|
"archive_confirm": "Archive",
|
|
"archived": "Patient archived",
|
|
"age_years": "{age} yrs",
|
|
"conditions_none": "No recorded conditions",
|
|
"unavailable": "This patient isn't available to you."
|
|
},
|
|
"profile": {
|
|
"title": "Profile",
|
|
"subtitle": "Your details and emergency contact.",
|
|
"first_name": "First name",
|
|
"last_name": "Last name",
|
|
"language": "Preferred language",
|
|
"language_fa": "Persian",
|
|
"language_en": "English",
|
|
"emergency_section": "Emergency contact",
|
|
"emergency_hint": "Who we call in an emergency.",
|
|
"emergency_name": "Emergency contact name",
|
|
"emergency_phone": "Emergency contact phone",
|
|
"emergency_phone_invalid": "Enter a valid mobile number",
|
|
"save": "Save",
|
|
"saved": "Profile saved",
|
|
"completion_done": "Your profile is complete.",
|
|
"completion_todo": "Complete your profile to speed up bookings."
|
|
},
|
|
"nurseProfile": {
|
|
"title": "Nurse profile",
|
|
"subtitle": "What families see when they find you.",
|
|
"photo": "Profile photo",
|
|
"photo_hint": "A clear photo of your face.",
|
|
"upload": "Upload photo",
|
|
"uploading": "Uploading…",
|
|
"bio": "About me",
|
|
"bio_hint": "A short intro — experience, focus, approach.",
|
|
"years": "Years of experience",
|
|
"years_invalid": "Enter a number between 0 and 80",
|
|
"save": "Save profile",
|
|
"saved": "Profile saved",
|
|
"unverified_title": "Your profile isn't active yet",
|
|
"unverified_body": "Complete identity verification to appear to families and receive bookings.",
|
|
"unverified_cta": "Complete verification",
|
|
"deferred_services": "You'll add your services & prices and available days in a later step."
|
|
},
|
|
"bank": {
|
|
"title": "Bank account",
|
|
"subtitle": "Where your earnings are paid out.",
|
|
"iban_label": "IBAN (Sheba)",
|
|
"iban_hint": "Starts with IR followed by 24 digits.",
|
|
"iban_invalid": "Enter a valid IBAN (IR + 24 digits)",
|
|
"holder_label": "Account holder name",
|
|
"holder_hint": "Must be exactly your own name.",
|
|
"holder_required": "Enter the account holder name",
|
|
"submit": "Submit account",
|
|
"submitting": "Submitting…",
|
|
"added": "Account submitted — ownership inquiry started",
|
|
"add_error": "This account couldn't be added. Check the IBAN and try again.",
|
|
"status_pending_chip": "Checking",
|
|
"status_pending_title": "Verifying account ownership",
|
|
"status_pending_body": "The Sheba ownership inquiry is running; this can take a moment.",
|
|
"status_verified_chip": "Verified",
|
|
"status_verified_title": "Account verified",
|
|
"status_verified_body": "This account is ready to receive your payouts.",
|
|
"status_mismatch_chip": "Ownership mismatch",
|
|
"status_mismatch_title": "The account must be in your own name",
|
|
"status_mismatch_body": "This account's holder doesn't match your identity. Please enter the IBAN of an account in your own name.",
|
|
"reenter": "Enter another account",
|
|
"make_primary": "Make primary",
|
|
"primary_set": "Primary account updated",
|
|
"iban_masked_label": "IBAN",
|
|
"primary": "Primary",
|
|
"empty_title": "No bank account yet",
|
|
"empty_body": "Add a bank account in your own name to receive payouts."
|
|
},
|
|
"geo": {
|
|
"province": "Province",
|
|
"city": "City",
|
|
"district": "District",
|
|
"whole_city": "Whole city",
|
|
"city_needs_province": "Choose a province first",
|
|
"district_needs_city": "Choose a city first",
|
|
"district_optional": "Optional",
|
|
"no_districts": "This city has no districts — whole city"
|
|
},
|
|
"address": {
|
|
"title": "Addresses",
|
|
"subtitle": "Where nurses will visit.",
|
|
"add": "Add address",
|
|
"add_title": "Add address",
|
|
"edit_title": "Edit address",
|
|
"edit": "Edit",
|
|
"delete": "Delete",
|
|
"empty_title": "No addresses yet",
|
|
"empty_body": "Add your first address so nurses know where to go.",
|
|
"primary": "Primary",
|
|
"set_primary": "Set as primary",
|
|
"primary_set": "Primary address updated",
|
|
"delete_title": "Delete address?",
|
|
"delete_body": "This address is removed from your list.",
|
|
"delete_confirm": "Delete",
|
|
"deleted": "Address deleted",
|
|
"saved": "Address saved",
|
|
"save_error": "This address couldn't be saved. Please try again.",
|
|
"unavailable": "This address isn't available to you.",
|
|
"title_label": "Address label",
|
|
"title_placeholder": "e.g. Home, Work",
|
|
"title_required": "Enter a label for this address",
|
|
"line_label": "Street address",
|
|
"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",
|
|
"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",
|
|
"map_lat": "Lat",
|
|
"map_lng": "Lng",
|
|
"manage_title": "Your addresses",
|
|
"manage_body": "Manage the places nurses visit.",
|
|
"manage_cta": "Manage addresses"
|
|
},
|
|
"coverage": {
|
|
"title": "Coverage areas",
|
|
"subtitle": "The cities and districts you'll travel to.",
|
|
"areas_heading": "Your areas",
|
|
"add_title": "Add a coverage area",
|
|
"scope_label": "Coverage",
|
|
"scope_whole_city": "Whole city",
|
|
"scope_districts": "Specific districts",
|
|
"add": "Add area",
|
|
"adding": "Adding…",
|
|
"whole_city_chip": "Whole city",
|
|
"empty_title": "No coverage areas yet",
|
|
"empty_warning": "You won't appear in search until you add at least one coverage area.",
|
|
"duplicate": "You already cover this area.",
|
|
"city_required": "Select a city",
|
|
"district_required": "Select a district, or switch to whole city.",
|
|
"added": "Coverage area added",
|
|
"add_error": "This area couldn't be added. Please try again.",
|
|
"remove_title": "Remove coverage area?",
|
|
"remove_body": "You'll no longer be matched for visits in this area.",
|
|
"remove_confirm": "Remove",
|
|
"removed": "Coverage area removed"
|
|
},
|
|
"auth": {
|
|
"customer_title": "Sign in to Balinyaar",
|
|
"customer_subtitle": "Sign in with your mobile number",
|
|
"nurse_title": "Nurse sign in",
|
|
"nurse_subtitle": "For nurses with a Nursing Council licence",
|
|
"phone_label": "Mobile number",
|
|
"phone_invalid": "Enter a valid Iranian mobile number",
|
|
"request_code": "Get verification code",
|
|
"nurse_switch": "Are you a nurse? Nurse sign in →",
|
|
"customer_switch": "Are you a family? Family sign in →",
|
|
"rate_limited": "Too many attempts — please try again shortly",
|
|
"otp_title": "Enter the verification code",
|
|
"otp_sent_to": "Code sent to {phone}",
|
|
"otp_verify_customer": "Verify and continue",
|
|
"otp_verify_nurse": "Verify and sign in",
|
|
"otp_invalid": "The code is incorrect or has expired",
|
|
"otp_locked": "Too many attempts. Request a new code to continue.",
|
|
"resend_in": "Resend code in {time}",
|
|
"resend": "Resend code",
|
|
"change_number": "Change number",
|
|
"routing_title": "Signing you in…",
|
|
"select_role_title": "Welcome to Balinyaar",
|
|
"select_role_subtitle": "Choose how you'll use Balinyaar to get started",
|
|
"role_customer": "Family",
|
|
"role_customer_desc": "Book nurses and home care",
|
|
"role_nurse": "Nurse",
|
|
"role_nurse_desc": "Offer nursing services",
|
|
"continue": "Continue"
|
|
}
|
|
}
|