diff --git a/components/dashboard/userAccount/sidebars/turns/Card.js b/components/dashboard/userAccount/sidebars/turns/Card.js index 5f09ddc..c161bdb 100644 --- a/components/dashboard/userAccount/sidebars/turns/Card.js +++ b/components/dashboard/userAccount/sidebars/turns/Card.js @@ -55,6 +55,25 @@ function Card({ data, loading, setIsTurnsDetails }) {

+ + {/* فیلدهای حالت نوبت‌دهی سرویسی. شرط اجباری است: نوبت اسلاتی این‌ها را ندارد و + بدون شرط، کارتِ همهٔ نوبت‌های اسلاتی می‌شکند — یعنی کل پنل کاربر. */} + {data.service_items?.length > 0 && ( +
  • +

    سرویس:

    +

    + {data.service_items.map((s) => s.name).join("، ")} +

    +
  • + )} + {!data.is_reserve && data.service_total_minutes ? ( +
  • +

    مدت نوبت:

    +

    + {data.service_total_minutes} دقیقه +

    +
  • + ) : null}
    diff --git a/components/dashboard/userAccount/sidebars/turns/Card.test.jsx b/components/dashboard/userAccount/sidebars/turns/Card.test.jsx new file mode 100644 index 0000000..dcc8355 --- /dev/null +++ b/components/dashboard/userAccount/sidebars/turns/Card.test.jsx @@ -0,0 +1,85 @@ +import { describe, it, expect, vi } from "vitest"; +import { render, screen } from "@testing-library/react"; +import Card from "./Card"; + +// آیکن و لودینگ‌ها به این تست ربطی ندارند؛ فقط باید کودکشان را رندر کنند. +vi.mock("@/app/component/loading/Text", () => ({ + default: ({ children }) => <>{children}, +})); +vi.mock("@/app/component/loading/Circular", () => ({ + default: ({ children }) => <>{children}, +})); +vi.mock("@/components/icons/ArrowLeftCardD", () => ({ default: () => null })); +vi.mock("next/image", () => ({ default: () => null })); + +const base = { + uuid: "ap1", + status: "confirmed", + slot_start: 1785567600, + doctor: { name: "دکتر تست" }, +}; + +function renderCard(data) { + return render( {}} />); +} + +describe("Card نوبت — فیلدهای حالت سرویسی", () => { + // ── ✅ موفق ────────────────────────────────────────────────────────────── + + it("نام همهٔ سرویس‌ها و مدت نوبت را نشان می‌دهد", () => { + renderCard({ + service_items: [{ uuid: "s1", name: "لیزر صورت" }, { uuid: "s2", name: "لیزر بیکینی" }], + service_total_minutes: 35, + }); + + expect(screen.getByText("سرویس:")).toBeInTheDocument(); + expect(screen.getByText("لیزر صورت، لیزر بیکینی")).toBeInTheDocument(); + expect(screen.getByText("مدت نوبت:")).toBeInTheDocument(); + expect(screen.getByText("35 دقیقه")).toBeInTheDocument(); + }); + + // ── ❌ خط سرخ: نوبت اسلاتی ──────────────────────────────────────────────── + + it("نوبت اسلاتی هیچ‌کدام از دو ردیف را نمی‌گیرد و کرش نمی‌کند", () => { + renderCard({ service_items: [], service_total_minutes: null }); + + expect(screen.queryByText("سرویس:")).not.toBeInTheDocument(); + expect(screen.queryByText("مدت نوبت:")).not.toBeInTheDocument(); + // ردیف‌های موجود سر جایشان‌اند. + expect(screen.getByText("تاریخ نوبت:")).toBeInTheDocument(); + expect(screen.getByText("ساعت نوبت:")).toBeInTheDocument(); + }); + + it("فیلدهای سرویسی کاملاً غایب (بک‌اند قدیمی) هم کرش نمی‌دهد", () => { + renderCard({}); + + expect(screen.queryByText("سرویس:")).not.toBeInTheDocument(); + expect(screen.getByText("تاریخ نوبت:")).toBeInTheDocument(); + }); + + // ── ⚠️ مرزی ────────────────────────────────────────────────────────────── + + it("نوبت رزرو سرویس را نشان می‌دهد ولی مدت را نه (زمان ندارد)", () => { + renderCard({ + is_reserve: true, + service_items: [{ uuid: "s1", name: "لیزر" }], + service_total_minutes: 45, + }); + + expect(screen.getByText("لیزر")).toBeInTheDocument(); + expect(screen.queryByText("مدت نوبت:")).not.toBeInTheDocument(); + }); + + it("سرویس بدون مدت → فقط ردیف سرویس", () => { + renderCard({ service_items: [{ uuid: "s1", name: "مشاوره" }], service_total_minutes: null }); + + expect(screen.getByText("مشاوره")).toBeInTheDocument(); + expect(screen.queryByText("مدت نوبت:")).not.toBeInTheDocument(); + }); + + it("مدت صفر ردیف نمی‌سازد", () => { + renderCard({ service_items: [{ uuid: "s1", name: "مشاوره" }], service_total_minutes: 0 }); + + expect(screen.queryByText("مدت نوبت:")).not.toBeInTheDocument(); + }); +}); diff --git a/components/dashboard/userAccount/sidebars/turns/isTurnsDetails/DetailLg.js b/components/dashboard/userAccount/sidebars/turns/isTurnsDetails/DetailLg.js index 520e848..bf51cf4 100644 --- a/components/dashboard/userAccount/sidebars/turns/isTurnsDetails/DetailLg.js +++ b/components/dashboard/userAccount/sidebars/turns/isTurnsDetails/DetailLg.js @@ -90,6 +90,29 @@ function DetailLg({ appointmentData, loading }) {
    + {/* حالت نوبت‌دهی سرویسی. شرط اجباری: نوبت اسلاتی این فیلدها را ندارد. */} + {appointmentData?.service_items?.length > 0 && ( +
  • + +

    + سرویس:{" "} + + {appointmentData.service_items.map((s) => s.name).join("، ")} + +

    +
    + {!appointmentData.is_reserve && appointmentData.service_total_minutes ? ( + +

    + مدت نوبت:{" "} + + {appointmentData.service_total_minutes} دقیقه + +

    +
    + ) : null} +
  • + )}
  • diff --git a/components/dashboard/userAccount/sidebars/turns/isTurnsDetails/DetailSm.js b/components/dashboard/userAccount/sidebars/turns/isTurnsDetails/DetailSm.js index a346b62..92171fc 100644 --- a/components/dashboard/userAccount/sidebars/turns/isTurnsDetails/DetailSm.js +++ b/components/dashboard/userAccount/sidebars/turns/isTurnsDetails/DetailSm.js @@ -85,6 +85,31 @@ function DetailSm({ appointmentData, loading }) {

  • + {/* حالت نوبت‌دهی سرویسی. شرط اجباری: نوبت اسلاتی این فیلدها را ندارد. */} + {appointmentData?.service_items?.length > 0 && ( +
  • + +

    سرویس:

    +
    + +

    + {appointmentData.service_items.map((s) => s.name).join("، ")} +

    +
    +
  • + )} + {!appointmentData?.is_reserve && appointmentData?.service_total_minutes ? ( +
  • + +

    مدت نوبت:

    +
    + +

    + {appointmentData.service_total_minutes} دقیقه +

    +
    +
  • + ) : null}