Files
nobat724_front/components/appointment/resource/index.js
T
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

85 lines
3.4 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
const MAX_PREVIEW_SERVICES = 3;
/**
* زیرنویس کارت: نام سرویس‌ها تا سه‌تا و بعد «+n».
*
* شمارِ خالی («۳ سرویس») به بیمار نمی‌گوید این دستگاه به کارش می‌آید یا نه، و او را
* مجبور می‌کند کورکورانه کلیک کند.
*/
function servicesLabel(services = []) {
if (services.length === 0) return null;
const shown = services.slice(0, MAX_PREVIEW_SERVICES).map((s) => s.name);
const rest = services.length - shown.length;
return rest > 0 ? `${shown.join("، ")} +${rest}` : shown.join("، ");
}
/**
* انتخاب نوع نوبت — پیش از انتخاب سرویس و روز، و فقط وقتی این پزشک در این محل
* دست‌کم یک منبعِ قابل رزرو دارد.
*
* «منبع» واژهٔ داخلی است و به بیمار نشان داده نمی‌شود؛ کارت‌ها نام واقعی دستگاه/اتاق
* و نوعشان را نشان می‌دهند. کارت اول همیشه جریان همیشگی است: نوبت با خودِ پزشک.
*/
function ResourceSelect({ resources = [], selected = null, onSelect, allowDoctorOption = true }) {
const cardClass = (active) =>
`w-full text-right p-[16px] rounded-[8px] border border-solid transition-colors ${
active
? "border-[#5559CE] bg-[rgba(85,89,206,0.06)]"
: "border-[#EFEFEF] bg-[#FFF] hover:border-[#C7C9EC]"
}`;
return (
<div className="w-full max-w-[520px] mx-auto">
<h2 className="text-[16px] font-bold text-[#3B3B3B] mb-4">۱. انتخاب نوع نوبت</h2>
<div className="flex flex-col gap-2">
{/* پزشکی که برنامهٔ هفتگی ندارد، ویزیتِ مستقیم هم ندارد؛ نشان‌دادن این کارت
کاربر را به فهرست ساعتِ همیشه‌خالی می‌برد. */}
{allowDoctorOption && (
<button type="button" onClick={() => onSelect(null)} className={cardClass(selected === null)}>
<p className="text-[14px] md:text-[16px] font-bold text-[#3B3B3B]">نوبت با پزشک</p>
<p className="mt-[6px] text-[13px] text-[#616161] font-normal">
ویزیت معمول در ساعتهای کاری پزشک
</p>
</button>
)}
{resources.map((resource) => {
const active = selected?.uuid === resource.uuid;
const label = servicesLabel(resource.services);
return (
<button
key={resource.uuid}
type="button"
onClick={() => onSelect(resource)}
className={cardClass(active)}
>
<div className="flex items-center justify-between gap-[8px]">
<p className="text-[14px] md:text-[16px] font-bold text-[#3B3B3B]">
{resource.name}
</p>
{resource.type?.name && (
<span className="text-[11px] text-[#5559CE] bg-[rgba(85,89,206,0.10)] rounded-[4px] px-[6px] py-[2px] shrink-0">
{resource.type.name}
</span>
)}
</div>
{label && (
<p className="mt-[6px] text-[13px] text-[#616161] font-normal">{label}</p>
)}
</button>
);
})}
</div>
</div>
);
}
export default ResourceSelect;