- Deleted Date.js and FilterDate.js components as they are no longer needed.
- Removed SearchDoctor.js component which was responsible for searching doctors.
- Cleaned up the Head component by removing references to the deleted Date and SearchDoctor components.
- Removed TurnsPage component and its associated List component, which were not utilized.
- Deleted Cards and Table components from the list directory as they were not in use.
- Removed user account related components including Tab, Head, and Form components.
- Cleaned up bank account components including List, Item, and modal components.
- Removed representation adapters and related functions that were not in use.
fix(progress): enhance accessibility by adding aria-label to LinearProgress component
fix(share): add aria-label for better accessibility in Share button
fix(title): change h3 to h2 for semantic correctness and add aria-labels for links
fix(qrimg): add alt text for QR code image for improved accessibility
fix(buttonmenu): add aria-label for mobile menu button to enhance accessibility
feat(robots): update disallow rules to include '/panel'
feat(sitemap): implement separate sitemaps for doctors, clinics, and blogs
feat(icons): add social media icons for doctor profiles
- 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
Fetch active specialties with number_of_doctors from
GET /api/v1/specialties/doctor-counts (scoped to the current city via
matchedCity.id) instead of the static specialties.json, so each specialty
card shows the real doctor count.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Appointment detail (DetailLg/DetailSm) read the real response shape:
date/time from slot_start, specialty from doctor.specialties[0].name,
phone from address.telephone.
- Sidebar Head reads userInfo (cookie) after mount to avoid an SSR/client
hydration mismatch on the user's name.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- JalaliDatePicker gains an opt-in `stepwise` mode (year → month → day): the
year step is a scrollable list from the current Jalali year down to 1332,
used by the birthday field. Default-off so appointment/panel pickers keep
the month-grid behavior. Parse incoming Jalali string values safely
(fixes NaN keys).
- Birthday create path now converts Jalali→Unix on send (changeDateType true),
matching the update path and the Unix-based backend contract.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 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>
- 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>
Connect the existing doctor-page review UI to the rebuilt backend contract
(see clinicpro feat/rating-multidimensional).
- page.js fetches the rating aggregate alongside comments and passes
rateAggregate down to the chart (point / satisfaction / 5 dimensions).
- Submit form sends the five dimensions with doctor_uuid; comment/reply
send {doctor_uuid, comment, parent}; 401/403 ERR_RATING_NOT_ELIGIBLE
surface friendly guidance.
- Like/dislike call POST /like/{uuid} with value and update from the
response; replies render nested.
- ModalAnswer gates the submit button on GET /rate/{uuid}/eligibility.
- services/response.js: getRateEligibility, postCommentsLike(uuid, value),
drop unused patchDoctorRate. Fix hardcoded modal title; empty-state for
no comments. Remove orphaned AnswerField.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The disease status Switch used defaultChecked, but row.status loads
async and changes via changeData, triggering MUI's uncontrolled→
controlled warning. Drive it with checked from row.status instead.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The ثبت اطلاعات button gave no feedback. Show a spinner while saving
(both POST and PATCH) and a 'اطلاعات با موفقیت ثبت شد' toast on success,
for the info tab and the medical-history sub-tabs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The backend stores the first name in the profile's label field, but the
account form binds the نام input to information.name, so a saved name
never displayed on reload. Map label→name when loading the profile (and
drop the raw label) so the field populates; saving still sends name,
which the backend hydrates back into label.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
DefaultSelect's onChange passes the whole option object {label,id}, but
the gender/blood_type/marital/education/job handlers compared it as a
string (education/blood via find(g=>g.label===value), others via ===),
so the value never stored — education in particular always saved empty.
Read option?.id uniformly across all five selects.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Clearing the blood type / education / insurance selects made
.find(...).id (and val.id) read .id on undefined, crashing the account
form. Use optional chaining with empty-string/empty-array fallbacks.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
These tabs have no backend endpoint yet (only per-doctor comments and
admin exist; user messages don't), so they read the always-empty
user.comments/user.messages. Guard against null and show a clear empty
state instead of a blank list.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The transactions list/card read mock fields (appointment_details,
row.amount, status 'received') and iterated user.turns.done. Pass the
real payments array and read order_id/type/created_at/amount_rials/status
from Payment.toArray(); map status to Persian labels, show rials→toman,
and render an empty state when there are no transactions.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The turns list/card read start_time, slot.time and doctor.specialty,
none of which exist on Appointment.toArray() (slot_start, doctor.name,
status). Use slot_start for the Jalali date/time, replace the specialty
column with a Persian status label, and show an empty state when there
are no appointments.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The account tab read basic_insurance.id (object) but the profile returns
basic_insurance_id (number), yielding [NaN], and never loaded the medical
history (other). Map basic_insurance_id/supplementary_insurance_id and
merge profile.other on load, and keep the profile uuid even for an empty
profile so PATCH saves work. Verified round-trip (name→label, insurance,
other) against the live API.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Login now overwrites the uuid cookie with the real user uuid (was the
OTP uuid), so server-side profile/dashboard fetches resolve.
- getMyAppointments → /api/v1/appointments/user (patient's own bookings;
/my/appointments is role-scoped and empty for plain users), read from
the double-nested data.data.
- getMyPayments → /api/v1/my/payments (new endpoint), read paginated
data + meta.totalPages.
- Drop the userId path param (both endpoints derive the user from token).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
getParsedUserInfo() can return null (cookie missing/unparseable), so
reading userInfo.realName crashed the dashboard with a 500. Default to
an empty object and fall back to the user prop's name or 'کاربر'.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>