Files
baya-monorepo/client/messages/en.json
T
hamid 99ebf5d881 frontend phase 4: catalog browse (Home A5) & nurse service builder (B7)
Light up the two faces of the configurable service catalog over a new cached
services/catalog domain (consumes the b5 contract; unlocks f6 search).

- services/catalog: types/keys/constants/apis(client+mock+seam)/hooks/index +
  names.ts. Categories & option groups are session-cached reference data
  (Infinity staleTime, like geography); variant mutations invalidate
  myVariantsLists() and setQueryData the edited row. Mock-primary
  (USE_CATALOG_MOCK), one-line swap; mock reproduces the 400 missing-required
  and (nurse,category,option-set) 409 duplicate rules.
- Customer Home (A5): greeting+avatar, search bar (navigates toward f6),
  data-driven category grid (loading/empty/error), patient nudge from the
  cached f2 query. Deferred /search placeholder stub.
- Nurse Services & prices (B7) at /nurse/services: offerings list (active vs
  deactivated, edit, soft-deactivate w/ confirm, reactivate, no delete) and a
  3-step variant builder (category -> required/optional options -> price+unit+
  duration). Required-group gate; Toman->IRR digit-string at the field
  boundary (no float); live unit-aware estimated total (never from price
  alone); editable auto display_name; inline 409 duplicate warning; locked
  category edit form.
- Shared, tested components: CategoryTile, PriceDisplay, VariantCard. Money
  util: tomanToRial + multiplyIrr (integer-safe) + tests.
- i18n: catalog/services/search namespaces + home additions + nav.services
  (both locales, in sync). Icons, routes (SEARCH, NURSE_SERVICES), nurse nav.

Gate: npm run check green; npm run test:ci green (147 tests, +18 across 4
suites); npm run build green with NEXT_PUBLIC_API_URL set.

Docs: client/CLAUDE.md (Project Structure, caching note, namespaces), STATUS,
for-backend REQ-010 (pagination param casing), phase report, mocks registry.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 17:33:44 +03:30

348 lines
14 KiB
JSON

{
"nav": {
"home": "Home",
"bookings": "Bookings",
"patients": "Patients",
"wallet": "Wallet",
"profile": "Profile",
"bank": "Bank account",
"coverage": "Coverage",
"services": "Services",
"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_named": "Hi, {name}",
"greeting_plain": "Hi there",
"subtitle": "Manage care for the people you love.",
"search_placeholder": "Search a service or nurse…",
"search_action": "Search",
"categories_title": "Services",
"categories_error": "Couldn't load services.",
"categories_empty": "No services have been set up yet.",
"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": "Manage your services & prices in the Services section; available days come 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"
},
"catalog": {
"unit_per_hour": "hourly",
"unit_per_session": "per session",
"unit_per_half_day": "per half-day",
"unit_per_day": "daily",
"unit_per_24h": "24-hour (live-in)",
"count_per_hour": "hours",
"count_per_session": "sessions",
"count_per_half_day": "half-days",
"count_per_day": "days",
"count_per_24h": "days (24h)",
"estimate_label": "Estimated total",
"estimate_for": "for {count} {unit}"
},
"services": {
"title": "Services & prices",
"subtitle": "The services you offer and what each costs.",
"add": "Add service",
"empty_title": "No services yet",
"empty_body": "Add at least one active, priced service so families can find and book you.",
"active_chip": "Active",
"inactive_chip": "Deactivated",
"inactive_hint": "This service is deactivated and can't be booked.",
"edit": "Edit",
"deactivate": "Deactivate",
"activate": "Reactivate",
"deactivate_title": "Deactivate this service?",
"deactivate_body": "It becomes unbookable and drops out of search. You can reactivate it anytime — it is never deleted.",
"deactivate_confirm": "Deactivate",
"deactivated_toast": "Service deactivated",
"activated_toast": "Service reactivated",
"toggle_error": "That couldn't be done. Please try again.",
"builder_add_title": "Add a new service",
"builder_edit_title": "Edit service",
"step_category": "Category",
"step_options": "Options",
"step_price": "Price",
"category_title": "Choose the service category",
"category_subtitle": "Every service belongs to one category.",
"categories_error": "Couldn't load categories. Please try again.",
"category_locked": "The category can't be changed after a service is created.",
"options_title": "Set the service options",
"options_subtitle": "Pick one option for each required item.",
"options_none": "This category has no options to configure.",
"required_badge": "Required",
"optional_badge": "Optional",
"options_incomplete": "Answer every required item to continue.",
"price_title": "Set the price and unit",
"price_label": "Price (Toman)",
"price_hint": "Enter the price in Toman.",
"price_required": "Enter a valid price greater than zero.",
"unit_label": "Price unit",
"duration_label": "Duration / count",
"duration_hint": "Optional — add a duration to preview the estimated total.",
"rate_note": "This is the base rate per unit, not the full total.",
"display_name_label": "Display name",
"display_name_hint": "Auto-generated from your options — you can edit it.",
"duplicate_warning": "You already have a service with these exact details. Change an option or the category.",
"summary_options": "Options",
"summary_none": "No options",
"next": "Next",
"submit_create": "Add service",
"submit_save": "Save changes",
"create_error": "The service couldn't be saved. Check your inputs and try again.",
"created_toast": "Service added",
"saved_toast": "Changes saved"
},
"search": {
"title": "Search",
"deferred": "Search and results arrive in the next phase.",
"query_echo": "You searched for “{query}”.",
"category_echo": "Filtered to the selected service category."
},
"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"
}
}