58 Commits
Author SHA1 Message Date
hamed 54bebbd41a feat: Implement resource-based appointment booking flow
- Updated DoctorPage component to accept bookingResources prop for appointment list.
- Added serviceQuery function to serialize service item UUIDs for API requests.
- Introduced new API endpoints for fetching booking resources and resource slots.
- Enhanced tests for new resource-based booking functionality, including resource selection and service availability.
- Created ResourceSelect component for selecting appointment types, including doctor and resource options.
- Updated appointment submission logic to include resource_uuid in payload when applicable.
- Ensured UI reflects changes in booking flow without disrupting existing doctor-centric experience.
2026-08-09 10:45:52 +03:30
hamedandClaude Opus 4.8 b37096048c feat(booking): show only locations that can actually be booked that day
The site offered a "personal practice" for a doctor who has no personal address
at all — the schedule existed but its shifts pointed at the clinic's address, so
there was nowhere to go. The backend now filters those out; this consumes the
filtered contract and adds the per-day dimension.

- getBookingLocations takes an optional date and the appointment page refetches
  on it, merging available_on_date into the existing list rather than replacing
  it, so browsing the calendar never resets the user's choice.
- The browsed day had to be lifted out of the Date step: selectedDate is only
  set once a slot is confirmed, far too late to drive availability.
- A location closed on the chosen day renders disabled with «در این روز نوبت
  ندارد», and when every location is closed the step says so instead of showing
  an empty slot list. If the already-selected location closes, a notice appears
  with a link back to the picker — silently showing nothing was the failure mode
  worth avoiding.
- Doctor profile: workLocation in the Physician JSON-LD is limited to addresses
  that appear in booking_locations, since schema.org presents them as places a
  patient can attend. The address card still lists the others — they are real
  practice details — tagged «بدون نوبت‌دهی آنلاین».

Verified end-to-end with a temporary unused address on the test doctor: the
visible card listed both and tagged the unused one, while workLocation carried
only the bookable one. The row was removed afterwards.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 14:44:49 +03:30
hamedandClaude Opus 4.8 eba0c6a5ba feat(booking): let patients choose the booking location
A doctor now has one booking schedule per context — the personal practice plus
one per clinic — and every booking endpoint takes an optional clinic_uuid where
omitting it means the personal practice, not a wildcard. This site sent none, so
a clinic-only doctor showed no availability at all and a doctor working in both
places silently booked into the wrong one.

- services/response.js: getBookingLocations + clinic_uuid on slots,
  service-slots, booking-services and month-availability. The manual query
  building is kept so the service_item_uuids[] serialisation does not change.
- AppointmentPage owns the selected location; booking_mode and services are
  derived from it instead of a separate getBookingServices call, which drops a
  request. Changing location clears the selected service, slot and date, since
  a service from one location cannot be booked into another.
- New LocationSelect step, shown only when there is more than one location.
  The list arrives sorted by earliest free slot, so the first item is the
  default and is not re-sorted here.
- DatePicker drops its month cache when the location changes; otherwise the
  previous location's disabled days stayed on the calendar.
- The slot address now comes from the selected location rather than
  doctor.address, which does not contain clinic addresses.
- clinic_uuid rides through to the appointment payload, and
  /appointment/[doctorId]?clinic_uuid=… preselects a location.
- Doctor page JSON-LD gains availableService from the bookable services.
  openingHoursSpecification still needs a public weekly-hours endpoint.

Removed the dead locateVisit state, which was initialised true and never unset.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 13:48:31 +03:30
hamed 6f9640cea6 fix(payment): adjust date formatting to use UTC offset for consistency 2026-07-16 00:30:20 +03:30
hamed 165a0a2240 feat(appointment): implement service-based booking flow with service selection and slot adaptation 2026-07-15 23:48:40 +03:30
hamed ee47b535d8 Add empty AST cache file for version 0.8.44 with non-object root data 2026-07-08 17:38:32 +03:30
hamed 5bec4848a2 feat: unify currency display to toman across the application 2026-07-03 10:31:16 +03:30
hamed e6b55c6bad feat: refactor payment handling to use direct backend redirect instead of API call 2026-07-02 17:08:52 +03:30
hamed e83a666adb feat: enhance payment flow with dynamic URL handling and improved error messaging 2026-07-02 15:36:09 +03:30
hamed 9e67ce4872 feat: update payment gateway selection to use active gateways from backend config 2026-07-02 12:19:44 +03:30
hamed 537f3e47d5 fix(payment): update currency display from تومان to ریال and adjust amount formatting 2026-06-24 20:39:34 +03:30
hamed cc6b42c1a5 feat(appointment): add city_id to appointment payload and update ProvinceProvider for city context 2026-06-24 19:56:04 +03:30
hamed ce07b4d1b1 fix(appointment): ensure national code and gender are mandatory for both self and others in SubmitData component 2026-06-24 12:33:00 +03:30
hamed 57e341b7b3 fix(appointment): improve error handling and validation for national code in SubmitData component 2026-06-24 12:16:22 +03:30
hamed 6ec2f5a069 feat(avatar): create DoctorAvatar component for improved doctor image handling 2026-06-21 11:17:34 +03:30
hamed 194ffd889c feat: enhance security by implementing HttpOnly refresh tokens and in-memory access token management
- Added isomorphic-dompurify for improved XSS protection
- Refactored token storage to use in-memory management for access tokens
- Implemented server-side route handlers for OAuth token management
- Introduced security headers in next.config.js
- Removed client-side exposure of client_secret and sensitive tokens
- Updated API interceptors to handle token refresh logic
- Cleaned up cookie management for refresh tokens
2026-06-20 13:10:17 +03:30
hamedandClaude Opus 4.8 7949da9ba9 fix(appointment): real status filter + required account fields
- My-appointments tabs sent invalid status values (reserved/waiting_for_payment/
  ...) that don't exist in the backend, so every tab but "all" returned empty.
  Map tabs to real statuses (pending/confirmed/completed/cancelled_by_user/
  expired) so booked appointments show up.
- Booking form now validates required account fields before proceeding to
  payment (national_code 10 digits, name, family, gender, basic_insurance),
  in both self and other-person modes, surfacing per-field errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 10:45:41 +03:30
hamedandClaude Opus 4.8 59d29cd7c7 fix(appointment): correct payment flow and account-info prefill
- Booking response is double-nested: read appointment uuid/expires_at from
  res.data.data so the payment countdown and gateway redirect actually fire.
- Payment result page (/payment/[uuid]): unwrap res.data.data, use real
  backend fields (amount_rials, gateway, created_at, type) and statuses
  (pending/success/failed/canceled/refunded); the "pay" button now re-initiates
  via postAppointmentPayment instead of building a URL on the API origin.
- Add /payment/result interstitial that reads payment_uuid from the gateway
  callback and forwards to /payment/[uuid].
- Prefill account info correctly in the booking form: name from profile.label,
  insurances from *_id, gender as string, national_code editable unless approved.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 10:06:56 +03:30
hamedandClaude Opus 4.8 fbb2279b49 fix(user-profile): consume profile from double-nested 200 response
With the backend now returning 200 (lazy-created profile) instead of
404, align the consumers: the profile lives at res.data.data (the
endpoint double-nests), so the booking detail and dashboard read that
instead of res.data / the raw envelope. Drop the obsolete 404 special
handling (empty editable form now comes from the 200 payload), seed the
dashboard empty state when the profile has no real data yet, and make
the profile POST fall back to PATCH on 409 (already lazy-created).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 19:06:38 +03:30
hamedandClaude Opus 4.8 d114730768 feat(appointment): redesign payment step with test-mode and real amount
Rebuild the payment screen as a clear confirm-and-pay card: appointment
summary (doctor, patient, Jalali date/time), a prominent amount row
(15,000 تومان from the backend's 150,000 rials), and a countdown with a
progress bar tied to the booking's real expires_at. Fetch
/api/v1/payment/config: in test mode show a 'درگاه آزمایشی' notice and a
'پرداخت آزمایشی' button (gateway select hidden, since the backend forces
MockGateway); otherwise show the bank gateway select. Expired state
offers re-selecting a time.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 18:36:55 +03:30
hamedandClaude Opus 4.8 9912ae06ca feat(api): surface backend error messages globally via toast
Show the backend's Persian error (errors[0].message, e.g. rate-limit
'درخواست‌های زیاد') as a toast for any failed request.* call, from the
axios response interceptor — so failures are no longer silent. 401 still
logs out/redirects without a toast; callers can opt out with
config.skipErrorToast. Drop now-redundant per-caller alerts/toasts in
the booking submit, payment, and OTP userinfo paths.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 18:25:11 +03:30
hamedandClaude Opus 4.8 eb3cb6ca10 feat(appointment): payment timer from real lock + status-driven payment UX
Drive the payment countdown from the booking's expires_at (15-min lock)
instead of a fake local 10-min timer; when it hits zero, show an expiry
notice and an 'choose time again' button back to slot selection. Show the
booked time (Jalali) and doctor on the payment step, and replace the
fabricated success amount with a confirmation/SMS note.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 18:09:33 +03:30
hamedandClaude Opus 4.8 08107d6ef2 feat(appointment): real for-another-patient form and booking payload
Replace the mock for-another button with a real toggle: switching keeps
the user's own data, clears the form to editable patient fields (phone
becomes an input, adds علت مراجعه), and can switch back. SubmitData now
sends for_self plus patient_* only when booking for someone else, skips
the self-profile PATCH/POST in that case, stores the booking expires_at,
and surfaces a clearer 409 message. Thread appointmentExpiresAt through
the wizard to the payment step.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 18:07:10 +03:30
hamedandClaude Opus 4.8 969e915815 fix(appointment): extract insurance list from double-nested response
GET /api/v1/insurances returns success(['data' => items]) → the body is
{ data: { data: [...] } }, so after the interceptor unwraps once the
array lives at res.data.data, not res.data. The callers set the list to
the wrapper object, so insurance.find threw 'not a function'. Read
res.data.data and guard with Array.isArray in both the booking detail
form and the dashboard insurance loader.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 16:54:11 +03:30
hamedandClaude Opus 4.8 1196aa64c6 fix(appointment): use existing doctor image as fallback
The appointment info/location headers fell back to /default-doctor.jpg,
which does not exist in public/, so the Next image optimizer returned
400 for doctors without a photo. Point the fallback at the existing
/assets/images/doctor.png (same default used on the doctor page).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 15:49:45 +03:30
hamedandClaude Opus 4.8 81121ad7d7 fix(appointment): convert picker timestamp to date and fix summary panel
Follow-ups found while sweeping for stale shapes:
- The date picker emits a unix timestamp, but appointment-slots needs
  Y-m-d; convert with moment before calling (slots never loaded before).
- Appointment summary (information/Detail.js) used the auth-required
  getDoctorAddress and selectedSlot.time; derive the address from the
  loaded doctor.address by location_id and use selectedSlot.start_time.
- SendAppo: drop the dead postAppointment block, unused useParams/loading,
  and a duplicate disabled prop on the button.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 15:47:21 +03:30
hamedandClaude Opus 4.8 61c21136d2 fix(appointment): read user profile from response envelope
getUserProfile returns { success, data } (interceptor unwraps once), so
the profile fields live under res.data, not res directly — the form was
always populated empty. Extract a buildProfileData helper and use it in
both the mount and step-3 effects, removing the duplicated mapping.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 15:44:12 +03:30
hamedandClaude Opus 4.8 ba32cd4192 fix(appointment): initiate payment against real gateway endpoint
POST /api/v1/payment/appointment expects { appointment_uuid, gateway,
frontend_address } and returns data.redirect_url. Send that body, redirect
to the gateway URL the backend returns (instead of hand-building one),
align the bank options with the real mellat/sep gateways, and remove the
hard-coded 10,000 toman amount (no real price available at this step).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 15:42:35 +03:30
hamedandClaude Opus 4.8 7a8700b09b fix(appointment): book with real payload and handle slot conflict
POST /api/v1/appointment expects { doctor_uuid, slot_start, slot_end,
note } with unix timestamps, and returns the appointment uuid at
data.uuid (not data.id). Send the right body, read the uuid, and on a
409 (slot already booked) alert the user and return to slot selection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 15:41:22 +03:30
hamedandClaude Opus 4.8 e6570e06f6 fix(images): resolve relative backend image URLs to absolute
API مسیرهای تصویر را نسبی برمی‌گرداند (/uploads/...) که next/image روی
دامنه localhost می‌جست و 404 می‌داد. helper جدید imageUrl مسیرهای نسبی
uploads را با NEXT_PUBLIC_API_URL کامل می‌کند (absolute و asset محلی
دست‌نخورده). اعمال روی لیست/جزئیات پزشک، نوبت، گالری کلینیک، آواتارها.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 00:44:27 +03:30
hamedandClaude Opus 4.8 8255283ec0 fix(ui): remove invalid MUI v5 Button loading prop project-wide
prop loading روی Button فقط در MUI v6+ پشتیبانی می‌شود؛ این پروژه v5 است
و هشدار "Received false for a non-boolean attribute loading" می‌داد.
- دکمه‌های login/verify: disabled + CircularProgress شرطی (بازخورد بصری حفظ شد)
- بقیه دکمه‌ها: loading → disabled (ادغام با disabled موجود در صورت وجود)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 00:30:55 +03:30
hamedandClaude Sonnet 4.6 59e0a0fe4f fix: resolve critical bugs and security issues across the project
Security:
- Disable SSL verification only in development (lib/req.js)
- Wrap all JSON.parse(cookie) calls in try-catch via safeJsonParse utility
- Sanitize dangerouslySetInnerHTML in blog/clinic with sanitizeHtml utility
- Fix open redirect in payment page — validate URL origin before redirect
- Fix cookie cleanup on 401 — use js-cookie with correct domain scope

Performance:
- Wrap ItemDoctor with React.memo to prevent unnecessary re-renders
- Replace <img> with Next.js <Image> in blog Caption component

Functionality:
- Fix memory leak in Recode.js — store intervals in refs, cleanup on unmount
- Add null guard on retryIcon.current before classList manipulation
- Fix getParsedUserInfo in helper to handle malformed cookie gracefully

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 09:19:20 +03:30
hamedandClaude Sonnet 4.6 1aa9f82d2a fix: resolve critical bugs and security issues across the project
- Fix GPS map links always sending literal "latitude"/"longitude" strings
  instead of actual coordinates in openLocation/Content.js
- Add api.clinic-pro.ir to next.config.js remotePatterns so production
  images load correctly
- Fix appointment page: await params and getStateInfo (Next.js 15 pattern)
- Enable 401 handling in api.js: clear cookies and redirect to /login
- Move OAuth client_secret to server-side API routes (/api/auth/token,
  /api/auth/refresh) so it is never bundled into client-side JavaScript
- Update SendReq, SubmitData, ButtonSendData to call API routes instead
  of directly sending client_secret from the browser
- Update docker-compose.yml to use server-only CLIENT_SECRET env var
- Remove debug console.log from clinic doctors list component

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 22:18:11 +03:30
hamed e6cb27a714 refactor: remove unused frontend_address from payment payload in Paying component 2025-12-02 15:03:27 +03:30
hamed 430e0b3b11 refactor: enhance payment handling by adding frontend_address to payment payload and implement PaymentDetailsPage component 2025-11-18 21:37:05 +03:30
hamed df54983fa3 refactor: enhance appointment handling by adding appointmentId state and updating payment process 2025-11-18 17:09:37 +03:30
hamed 53ac0fea83 refactor: add doctor, selectedSlot, and selectedDate props to SubmitData component and enhance appointment handling 2025-11-18 16:36:08 +03:30
hamed 6d6d27bcc9 refactor: pass doctor, selectedSlot, and selectedDate props to SubmitData and Detail components 2025-11-18 16:03:46 +03:30
hamed 0d547b91bc refactor: update terminology from 'expertise' to 'specialties' in Head components and improve phone number display in Form component 2025-11-18 15:47:24 +03:30
hamed 2894da3c69 refactor: remove console logs for token refresh and user profile requests in SubmitData and AppointmentPage components 2025-11-18 15:39:45 +03:30
hamed 5c98b4de3e refactor: enhance handling of supplementary insurance in Form and AppointmentPage components 2025-11-18 10:35:35 +03:30
hamed 3268b3c51e refactor: enhance form validation and error handling in EditField, DefaultSelect, and Form components 2025-11-18 09:16:01 +03:30
hamed ebc6c246b9 refactor: add gender selection to Form component and update DefaultSelect for improved option handling 2025-11-18 08:32:41 +03:30
hamed a3fd984894 refactor: update user data handling in AppointmentPage to improve loading state and editability of fields 2025-11-17 16:17:50 +03:30
hamed 3db4c7e851 refactor: improve loading state management and enhance user profile data handling in AppointmentPage component 2025-11-17 16:10:14 +03:30
hamed 8c03717cb7 refactor: add supplementary insurance handling in Form component and update Detail component to fetch insurance data 2025-11-17 15:48:33 +03:30
hamed b46a017773 refactor: enhance appointment flow by adding selected slot and date management across components 2025-11-17 15:33:47 +03:30
hamed 5a58c13a4e refactor: implement login state management and navigation flow in appointment components 2025-11-17 15:00:40 +03:30
hamed 63d968be1e refactor: update appointment components to fetch and handle doctor data and disabled dates 2025-11-12 21:28:15 +03:30
Ehsan 9f53daa398 save state selected in modal filter, filter list with location selected, save data sort, filter list with sort point, real all url from .env file, change name of value category and specialties to persian and change functional find data with field 2025-09-08 08:08:35 +03:30