Commit Graph
488 Commits
Author SHA1 Message Date
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 e820cc88ee fix(appointment): client guard for slots that pass while page is open
The backend already returns is_available:false for past slots, but a
slot can lapse after the list is loaded. Disable any slot whose start
(unix seconds) is before now in the time grid, so a just-passed slot
can't be clicked. The grid disabling makes a SendAppo-level guard
redundant — a past slot can no longer be selected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 16:51:30 +03:30
hamedandClaude Opus 4.8 da3f20e07d fix(appointment): stop insurance select crash and use current endpoint
DefaultSelect passed options={undefined} to MUI Autocomplete while the
insurance lists were still loading (or failed), throwing 'Cannot read
properties of undefined (reading length)'. Default options to [].

The old categorys/insurance_type + supplementary_insurance routes were
removed server-side (ERR_MOVED), so the lists never loaded. Point
getInsuranceType/getSupplementaryInsurance at the current
/api/v1/insurances?type=basic|supplementary (authed; the booking detail
step and dashboard are both logged-in), returning a flat data array.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 16:41:17 +03:30
hamedandClaude Opus 4.8 65b3f56530 fix(auth): surface real OTP error on verification step
The booking login step showed only a generic error when /api/auth/token
returned 400, so an invalid or expired OTP looked like a broken page.
The backend returns the reason (ERR_AUTH_002 invalid / ERR_AUTH_003
expired) in errors[].message, forwarded by the route; show it via toast.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 16:37:50 +03:30
hamedandClaude Opus 4.8 232e7eaeb2 feat(appointment): grey out unavailable days on the booking calendar
DatePicker now loads month-availability for the two displayed Jalali
months (mapped to the Gregorian months they span, fetched once and
cached per month) and disables any day in disabled_dates plus past
days. Auto-select skips disabled days. When the doctor has online
booking turned off, show a notice instead of the calendar. doctorUuid
comes from the route params.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 16:31:47 +03:30
hamedandClaude Opus 4.8 96f4126c0b feat(appointment): add getMonthAvailability request wrapper
Public wrapper for GET /api/v1/appointment-settings/month-availability
/{doctor_uuid}?year=&month= so the calendar can learn which days are
bookable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 16:29:31 +03:30
hamedandClaude Opus 4.8 779113bb19 fix(appointment): order calendar months RTL (خرداد right, تیر left)
The two months rendered reversed (current month on the left). Pin the
calendar row to dir=rtl and render the base month first so the current
month sits on the right and the next month on the left, matching the
design. Pin each month header to dir=ltr so the nav arrows stay on the
expected outer edges regardless of the RTL flip.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 16:05:56 +03:30
hamedandClaude Opus 4.8 cf705a894e feat(appointment): inline dual-month Jalali calendar for day selection
The day picker used a Popover-based JalaliDatePicker that only showed two
empty text inputs on the booking page — the calendar was hidden until you
clicked the input, so it never matched the design. Replace it with an
always-visible inline two-month calendar (InlineJalaliMonth) rendered side
by side: current month on the right, next on the left (RTL), weekday
headers, Fridays in red, disabled days greyed, selected day in orange,
shared month navigation on the outer edges. Preserves the existing
contract: setDate(unix timestamp), disabledDates[], auto-select nearest
available day.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 15:58:23 +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 dcfdedd93c fix(appointment): render real slot structure in time picker
The slots API returns data.sessions[].slots[] with start_time (HH:MM),
is_available, and start/end unix timestamps — not the morning/evening +
time/status shape the UI assumed. Add lib/appointmentSlots.js to flatten
sessions into morning/evening by start_time, fetch with doctor.uuid, and
read item.start_time / item.is_available in the slot grid. Derive the
clinic address from the already-loaded doctor.address by location_id
instead of a separate auth-required call.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 15:40:21 +03:30
hamedandClaude Opus 4.8 0e112d2299 fix(appointment): unwrap doctor response and drop dead not-available call
The doctor endpoint is triple-nested, so doctorRes.data left doctor.id
undefined and the booking page received a broken doctor object. Extract
with data?.data?.data and remove the disabledDates fetch to the
nonexistent /appointment/not-available route (404); pass [] so the date
picker enables all dates and lets the slots response gate availability.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 15:37:47 +03:30
hamedandClaude Opus 4.8 811882ea05 fix(appointment): align request layer with real backend contract
- getAppointmentSlots uses doctor_uuid + date (was doctor_id, which the
  backend rejects with دکتر یافت نشد).
- postAppointmentPayment posts to /api/v1/payment/appointment (was the
  nonexistent /api/v1/payment).
- Remove getAppointmentNotAvailable: the not-available route does not
  exist (404); disabled dates come from the slots response.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 15:35:43 +03:30
hamedandClaude Opus 4.8 e13d1c2eeb fix(location): correct directions deep links
The routing modal shipped broken deep links: snapp.ir/route and
tapsi.ir/route paths don't exist (404), and balad used the wrong path
and params. Keep only apps with verified destination deep links and
fix their formats:

- Remove Snapp and Tapsi (no valid web destination route).
- Balad: balad.ir/location?latitude=&longitude= (was /map?lat=&lng=).
- Google Maps and Waze kept (already correct).
- Guard data.map destructuring against null.
- Dashboard turn detail: use maps/dir directions URL instead of a
  plain q= pin to match the مسیریابی label.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 15:26:10 +03:30
hamedandClaude Opus 4.8 365892a0f1 fix(doctor): render location map reliably when accordion expands
The map iframe lived inside a collapsed (max-h-0, overflow-hidden)
accordion with loading=lazy, so it often never loaded after expanding.
Mount the iframe only when the location item is open so it loads fresh,
and raise the open clamp from max-h-screen to max-h-[800px] so the map
isn't clipped on shorter viewports.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 15:21:07 +03:30
hamedandClaude Opus 4.8 ff54daf1ae fix(doctor): unwrap double-nested API response and guard empty sections
The GET /api/v1/doctor/{uuid} response is double-nested
({ success, data: { data: {...} } }), but the page only unwrapped one
level, leaving every field (name, specialties, expertise, address)
undefined — so خدمات / موقعیت مکانی / نظرات rendered empty or broken.

- Extract the doctor object with res.data?.data?.data in both
  generateMetadata and the page.
- Hide the خدمات block when expertise is empty (no fabricated data).
- Render the location map iframe and routing buttons only when the
  address has real latitude/longitude (was building q=null,null).
- Fix the comments list rendering a stray 0 on empty arrays.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 15:18:06 +03:30
hamedandClaude Opus 4.8 0a48c854cb chore(data): remove unused mock json after API wiring
Delete data/information.json, data/userData.json, data/bank.json — the
panel and patient dashboard now read real data from the API, and no
render path references these files anymore. Verified via grep + build.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 13:47:19 +03:30
hamed 4374ed5043 feat(panel): connect representative panel and user dashboard to real API, removing mock data 2026-06-15 09:12:51 +03:30
hamedandClaude Opus 4.8 d9dc976ab3 fix(pagination): read pagination from meta instead of page
backend جدید clinicpro صفحه‌بندی را در پاسخ تحت کلید meta برمی‌گرداند
({totalRecords, totalPages, currentPage})، نه page. به همین دلیل
PaginationContent مقدار totalRecords نمی‌گرفت و count=NaN می‌شد و
صفحه‌بندی مخفی می‌ماند. اصلاح در صفحات /doctors و /clinics.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 00:56:26 +03:30
hamedandClaude Opus 4.8 f9a4a028eb fix(doctor): guard optional chaining on address array
برخی پزشکان address ندارند؛ data?.address[0] روی آن‌ها کرش می‌کرد
(Cannot read properties of undefined). اصلاح به data?.address?.[0]
در Address و Telefon صفحه پروفایل پزشک.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 00:52:32 +03:30
hamedandClaude Opus 4.8 dc60b0a4f2 chore(dev): accept ddev self-signed cert in dev for next/image optimizer
بهینه‌ساز تصویر داخلی Next با fetch بومی خودش تصویر را از ddev می‌گیرد و
گواهی self-signed را رد می‌کرد (UNABLE_TO_VERIFY_LEAF_SIGNATURE روی
/_next/image). افزودن NODE_TLS_REJECT_UNAUTHORIZED=0 فقط به اسکریپت dev.
build و start production دست‌نخورده و امن می‌مانند.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 00:46:43 +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 05cf5fc585 fix(auth): align token/refresh routes with clinicpro 3-step OTP flow
backend جدید clinicpro جریان سه‌مرحله‌ای دارد:
send-code → verify-code (uuid+code) → oauth/token (uuid).
- token route حالا اول /api/v1/user/verify-code را صدا می‌زند سپس
  /oauth/token با بدنه JSON {grant_type, uuid} (به‌جای form-urlencoded
  با client_id/secret/scope که فقط backend پروداکشن قدیم می‌پذیرفت)
- refresh route به مسیر درست /oauth/token/refresh با بدنه JSON
- تست E2E روی ddev محلی: access_token واقعی صادر شد

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 00:39:43 +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 Opus 4.8 ecc212db86 fix(auth): use SSL-tolerant axios for oauth token/refresh routes
route های token و refresh از fetch بومی Node استفاده می‌کردند که گواهی
self-signed ddev محلی را رد می‌کرد و خطای 500 می‌داد. حالا از axiosInstance
استفاده می‌کنند و خطای واقعی backend را با status درست برمی‌گردانند.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 00:30:42 +03:30
hamedandClaude Opus 4.8 1d56972b65 fix: use SSL-tolerant axios instance for server-side API calls
صفحات سرور (doctors, doctor/[slug], appointment/[doctorId]) از axios خام
استفاده می‌کردند که گواهی self-signed ddev محلی را رد می‌کرد
(unable to verify the first certificate). حالا از axiosInstance/fetchReq
در lib/req استفاده می‌کنند که در development آن را می‌پذیرد.
افزودن clinic-pro.ddev.site (http/https) به remotePatterns تصاویر.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 00:21:34 +03:30
hamedandClaude Opus 4.8 f3192945c7 fix(doctors): resolve next/image http host and MUI v5 loading prop
- افزودن الگوی http برای api.clinic-pro.ir به next.config (عکس‌های بیمه
  با http برمی‌گردند و خطای 500 next/image می‌دادند)
- جایگزینی prop loading نامعتبر روی Button با disabled در SendReq/ButtonApply
  (loading فقط در MUI v6+ پشتیبانی می‌شود؛ این پروژه v5 است و lab نصب نیست)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 00:15:10 +03:30
hamedandClaude Opus 4.8 dc1c6d25be feat(dashboard): connect patient dashboard to real user profile
- buildPatientUser: ساخت آبجکت user از user-profile واقعی با کلیدهای
  مورد انتظار کامپوننت‌ها؛ comments/messages خالی و اعداد هدر صفر
  (بدون داده ساختگی، چون endpoint ندارند)
- app/dashboard/page.js پروفایل را server-side از user-profile/{uuid} می‌گیرد
- حذف import userData.json mock از Content داشبورد
- نوبت/تراکنش/تب اطلاعات از قبل به API واقعی وصل بودند (بدون تغییر)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 00:10:40 +03:30
hamedandClaude Opus 4.8 5067824f28 feat(panel): connect turns/user-account/add-doctor to real data
- انتقال adapterهای نماینده به lib/representationAdapters (server-safe،
  بدون وابستگی client مثل js-cookie/react-toastify)
- turns: لیست از daily[] داشبورد ماهانه (ستون نام/تخصص خالی، بدون داده ساختگی)
- user-account: حساب بانکی واقعی از bank_account نماینده (map به آرایه تک‌کارته)
- add-doctor: حذف import mock مرده (کامپوننت data مصرف نمی‌کرد)
- رفع dead import اشتباه از turns/page در clinic/doctors که build را می‌شکست

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 00:06:01 +03:30
hamedandClaude Opus 4.8 1599098b6d feat(panel): connect dashboard page to representation monthly stats
تبدیل صفحه dashboard پنل به Server Component که آمار ماهانه نماینده را
از API می‌گیرد (year/month میلادی جاری) و با adaptRepresentationDashboard
به propهای کامپوننت map می‌کند. حذف داده mock.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 00:00:16 +03:30
hamedandClaude Opus 4.8 bef36f86ca feat(panel): wire panel header/userDetail to real representation info
افزودن adaptRepresentationInfo که خروجی API نماینده را به propهای
کامپوننت‌های نمایشی map می‌کند و حذف import داده mock از Content پنل.
فیلدهای آماری بدون معادل API خالی می‌مانند (بدون داده ساختگی).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 23:57:48 +03:30
hamedandClaude Opus 4.8 d513d2dd30 feat(panel): add representation dashboard API helpers
افزودن getRepresentationDashboardMonthly و getRepresentationDashboardYearly
به لایه request برای مصرف endpointهای داشبورد نماینده.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 23:54:58 +03:30
hamed 52f6bf6d0f Refactor code structure for improved readability and maintainability 2026-06-14 23:37:53 +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
hamedandClaude Sonnet 4.6 ec536bfc32 fix: resolve sitemap build error caused by invalid Date values
- Replace new Date(b.created) with toSafeDate() helper to guard against
  invalid date strings from blog API responses
- Use a single NOW constant instead of new Date() per entry to avoid
  serialization issues during static generation
- Remove unused imports (cityData, DOMAIN_CONFIG, etc.)
- Add CLAUDE.md with project architecture and development guidance

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 21:47:42 +03:30
hamed 35408b059a seo check 2026-06-05 21:28:12 +03:30
hamed 3c9013ff0c check lighthous 2026-06-05 21:05:07 +03:30
hamed cf703f131a fix: update environment variables in docker-compose.yml to use default values 2025-12-23 11:27:59 +03:30
hamed 5d8c7cef1d fix: update NEXT_PUBLIC_API_URL to use default value if not set 2025-12-23 10:09:57 +03:30
hamed 54ae8c3a68 chore: update package.json to add tailwindcss and postcss dependencies 2025-12-17 17:59:20 +03:30
hamed db2f9aef60 Replace jalaali-react-date-picker with custom MUI-based Jalali date picker - fixes all 10 security vulnerabilities 2025-12-17 10:09:37 +03:30
hamed e5e6f33ae4 Update packages: Next.js 15.5.9, Tailwind 3.4.19 2025-12-17 09:58:14 +03:30
hamed a844ac20e7 Remove pull_policy - not supported in build section 2025-12-10 15:24:53 +03:30
hamed defaae05fe refactor: simplify Dockerfile for Next.js 14 and optimize build stages 2025-12-10 15:19:06 +03:30