بلاک‌ها · فروشگاهی

پیگیری بدونِ ورود

پیش‌نمایش تمام‌صفحه

پیگیریِ مهمان با کدِ سفارش و موبایلِ خرید، خطای روشن اگر پیدا نشد و نتیجه در همان صفحه با نوارِ چهارمرحله‌ای و جملهٔ وضعیت.

۱. نصب کامپوننت‌ها

این بلاک از ۵ آیتم دیگ استفاده می‌کند: buttoncontrol-sizeiconspersiantext-field

پکیج‌منیجر پیش‌فرض Node.jsنصب سریع با لینک سخت و دیسک مشترکYarn نسخهٔ ۲ به بالا (Berry)رانتایم و پکیج‌منیجر Bun
npx digdesign@latest add https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/icons.json https://docs.digdesign.ir/r/persian.json https://docs.digdesign.ir/r/text-field.json
pnpm dlx digdesign@latest add https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/icons.json https://docs.digdesign.ir/r/persian.json https://docs.digdesign.ir/r/text-field.json
yarn dlx digdesign@latest add https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/icons.json https://docs.digdesign.ir/r/persian.json https://docs.digdesign.ir/r/text-field.json
bunx --bun digdesign@latest add https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/icons.json https://docs.digdesign.ir/r/persian.json https://docs.digdesign.ir/r/text-field.json

۲. کد صفحه

کد را در app/<route>/page.tsx بگذارید و متن‌ها، داده و هندلرها را با محصول خودتان عوض کنید.

order-tracking-lookup.tsx
"use client";

import * as React from "react";

import { CheckIcon, TruckIcon } from "@/components/icons";
import { Button } from "@/components/ui/button";
import { ControlSizeProvider } from "@/components/ui/control-size";
import { TextField } from "@/components/ui/text-field";
import { isValidMobile, toFaDigits } from "@/lib/persian";

const STEPS = ["ثبت", "آماده‌سازی", "ارسال", "تحویل"];

/**
 * پیگیری سفارش بدونِ ورود (برای مهمان): کدِ سفارش و موبایلِ خرید، خطای روشن اگر نخواند، و
 * نتیجه در همان صفحه با نوارِ چهارمرحله‌ای افقی و جملهٔ وضعیت؛ «پیگیری سفارشِ دیگر» برمی‌گرداند.
 */
export default function OrderTrackingLookupBlock() {
  const [code, setCode] = React.useState("");
  const [mobile, setMobile] = React.useState("");
  const [state, setState] = React.useState<
    "idle" | "loading" | "found" | "missing"
  >("idle");
  const current = 2;

  return (
    <ControlSizeProvider size="xl" asChild>
      <main className="flex min-h-svh items-start justify-center bg-subtle p-4 sm:items-center">
        <div className="flex w-full max-w-lg flex-col">
          {/* بنر: گرادیانِ برند با مسیرِ خط‌چین و بستهٔ تزئینی؛ کارتِ فرم روی لبه‌اش می‌نشیند. */}
          <header className="relative isolate flex flex-col gap-2 overflow-hidden rounded-xl bg-[linear-gradient(135deg,var(--dig-violet-700),var(--dig-indigo-800))] px-6 pt-8 pb-24 text-[var(--dig-white)] sm:px-8">
            <span
              aria-hidden
              className="pointer-events-none absolute inset-0 -z-10 bg-[radial-gradient(circle_at_90%_0%,var(--dig-violet-400),transparent_50%)]"
            />
            <svg
              aria-hidden
              viewBox="0 0 200 90"
              className="pointer-events-none absolute end-4 top-4 -z-10 hidden w-36 sm:block text-[color-mix(in_oklab,var(--dig-white)_45%,transparent)]"
              fill="none"
            >
              <path
                d="M6 70 C 50 70, 70 20, 120 30 S 170 60, 190 40"
                stroke="currentColor"
                strokeWidth="2"
                strokeDasharray="2 7"
                strokeLinecap="round"
              />
              <circle cx="6" cy="70" r="5" fill="currentColor" />
              <g transform="translate(166 18)">
                <rect width="30" height="26" rx="4" fill="var(--dig-white)" />
                <path
                  d="M0 9h30M15 0v9"
                  stroke="var(--dig-violet-500)"
                  strokeWidth="2"
                />
              </g>
            </svg>
            <h1 className="text-2xl leading-snug font-black">سفارشت کجاست؟</h1>
            <p className="max-w-[15rem] text-sm text-[var(--dig-violet-100)]">
              کدِ سفارش در پیامکِ خرید آمده؛ بدونِ ورود هم پیگیری کن.
            </p>
          </header>
          <section
            aria-label="پیگیری"
            className="relative mx-3 -mt-12 flex flex-col gap-8 rounded-xl border border-border bg-card p-6 shadow-card sm:mx-5 sm:p-8"
          >
            {state === "found" ? (
              <div className="flex flex-col gap-8" aria-live="polite">
                <div className="flex items-center gap-4 rounded-xl bg-subtle p-4">
                  <span
                    aria-hidden
                    className="flex size-12 items-center justify-center rounded-xl bg-card text-brand-secondary [&>svg]:size-6"
                  >
                    <TruckIcon />
                  </span>
                  <span className="flex flex-col">
                    <span className="font-bold">در راه است</span>
                    <span className="text-sm text-muted-foreground">
                      سفارشِ {toFaDigits(code)} · تحویل تا فردا ساعتِ ۱۸
                    </span>
                  </span>
                </div>
                <ol className="grid grid-cols-4 gap-2">
                  {STEPS.map((step, index) => (
                    <li
                      key={step}
                      aria-current={index === current ? "step" : undefined}
                      className="flex flex-col gap-2"
                    >
                      <span
                        className={`h-1.5 rounded-full ${index <= current ? "bg-success" : "bg-muted"}`}
                      />
                      <span
                        className={`flex items-center gap-1 text-xs ${index <= current ? "font-semibold" : "text-muted-foreground"}`}
                      >
                        {index < current && (
                          <CheckIcon
                            aria-hidden
                            className="size-3.5 text-success"
                          />
                        )}
                        {step}
                      </span>
                    </li>
                  ))}
                </ol>
                <Button variant="outline" onClick={() => setState("idle")}>
                  پیگیری سفارشِ دیگر
                </Button>
              </div>
            ) : (
              <form
                className="flex flex-col gap-5"
                onSubmit={(event) => {
                  event.preventDefault();
                  setState("loading");
                  window.setTimeout(
                    () => setState(code.length >= 6 ? "found" : "missing"),
                    700,
                  );
                }}
              >
                <TextField
                  label="کدِ سفارش"
                  inputMode="numeric"
                  dir="ltr"
                  value={code}
                  onValueChange={setCode}
                  required
                  invalid={state === "missing"}
                  errorMessage="سفارشی با این کد و موبایل پیدا نشد؛ کد را از پیامکِ خرید دوباره نگاه کن."
                />
                <TextField
                  label="موبایلِ خرید"
                  type="tel"
                  dir="ltr"
                  maxLength={11}
                  value={mobile}
                  onValueChange={setMobile}
                  required
                  validate={(value) =>
                    isValidMobile(value)
                      ? undefined
                      : "شماره موبایل باید با ۰۹ شروع شود و ۱۱ رقم باشد."
                  }
                />
                <Button
                  type="submit"
                  loading={state === "loading"}
                  className="mt-3"
                >
                  پیگیری
                </Button>
              </form>
            )}
          </section>
          <p className="mt-5 text-center text-sm text-muted-foreground">
            کد را پیدا نمی‌کنی؟{" "}
            <a
              href="#"
              className="font-medium text-foreground underline underline-offset-4"
            >
              با پشتیبانی تماس بگیر
            </a>
          </p>
        </div>
      </main>
    </ControlSizeProvider>
  );
}