oauth/userinfo returns { success, data: {...} }, so after the interceptor
unwraps once the user lives at res.data, not res. getInfo checked
res.uuid (undefined), so it never set the userInfo cookie or redirected —
the /login page just sat there after entering the OTP. Read res.data,
store the user object (with a username alias for mobile_number so the
appointment flow keeps working), redirect via location.href, and show a
toast instead of silently staying when userinfo fails.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
backend جدید clinicpro صفحهبندی را در پاسخ تحت کلید meta برمیگرداند
({totalRecords, totalPages, currentPage})، نه page. به همین دلیل
PaginationContent مقدار totalRecords نمیگرفت و count=NaN میشد و
صفحهبندی مخفی میماند. اصلاح در صفحات /doctors و /clinics.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
برخی پزشکان address ندارند؛ data?.address[0] روی آنها کرش میکرد
(Cannot read properties of undefined). اصلاح به data?.address?.[0]
در Address و Telefon صفحه پروفایل پزشک.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
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>
- افزودن الگوی 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>
- 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>
- انتقال 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>
افزودن adaptRepresentationInfo که خروجی API نماینده را به propهای
کامپوننتهای نمایشی map میکند و حذف import داده mock از Content پنل.
فیلدهای آماری بدون معادل API خالی میمانند (بدون داده ساختگی).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
- 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>
- Updated MUI packages to version 5.x and x-charts/x-date-pickers to 7.x
- Downgraded React and React-DOM to version 18.3.1
- Added .dockerignore to exclude unnecessary files from Docker context
- Bumped versions for several packages including:
- @emotion/styled from ^11.14.0 to ^11.14.1
- @maptiler/sdk from ^2.4.0 to ^2.5.1
- @mui/icons-material from ^7.1.0 to ^7.3.6
- @mui/material from ^7.1.0 to ^7.3.6
- @mui/styled-engine-sc from ^6.0.0-alpha.18 to ^6.4.9
- @mui/x-charts from ^7.16.0 to ^7.29.1
- @mui/x-date-pickers from ^7.17.0 to ^7.29.4
- @next/third-parties from ^15.1.0 to ^15.5.7
- axios from ^1.7.7 to ^1.13.2
- dayjs from ^1.11.13 to ^1.11.19
- jspdf from ^3.0.1 to ^3.0.4
- next from ^14.2.20 to ^15.5.7
- next-themes from ^0.3.0 to ^0.4.6
- npm from ^10.8.2 to ^10.9.4
- react from ^18.0.0 to ^18.3.1
- react-dom from ^18 to ^18.3.1
- react-easy-crop from ^5.1.0 to ^5.5.6
- react-toastify from ^10.0.6 to ^11.0.5
- sharp from ^0.34.1 to ^0.34.5
- styled-components from ^6.1.11 to ^6.1.19
- stylis from ^4.3.4 to ^4.3.6
- swiper from ^11.1.9 to ^11.2.10
- postcss from ^8 to ^8.5.6
- prettier from ^3.5.3 to ^3.7.4
- tailwindcss from ^3.4.1 to ^3.4.18