بلاک‌ها · بانکی و پرداخت

پرداخت قبض با نوع قبض، شناسهٔ قبض و پرداخت، و خلاصهٔ مبلغ.

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

این بلاک از ۹ آیتم دیگ استفاده می‌کند: buttoncardcontrol-sizelabelpersianseparatortext-fieldtoasttoggle-group

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

۲. کد صفحه

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

bill-payment.tsx
"use client"

import * as React from "react"

import { Button } from "@/components/ui/button"
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
import { ControlSizeProvider } from "@/components/ui/control-size"
import { Label } from "@/components/ui/label"
import { Separator } from "@/components/ui/separator"
import { TextField } from "@/components/ui/text-field"
import { toast } from "@/components/ui/toast"
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
import { formatCurrency } from "@/lib/persian"

const BILL_TYPES = [
  // لوگوی هر اداره در public/logos/organizations
  { value: "water", label: "آب", logo: "water" },
  { value: "power", label: "برق", logo: "power" },
  { value: "gas", label: "گاز", logo: "gas" },
  { value: "phone", label: "تلفن", logo: "telecom" },
]

export default function BillPaymentBlock() {
  const [type, setType] = React.useState("power")
  const [billId, setBillId] = React.useState("")
  const [paymentId, setPaymentId] = React.useState("")
  const [amount, setAmount] = React.useState<number | null>(null)
  const [loading, setLoading] = React.useState(false)

  async function lookup(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault()
    setLoading(true)
    // مبلغ از شناسهٔ پرداخت درمی‌آید؛ این نمونه یک مبلغِ ثابت برمی‌گرداند.
    await new Promise((resolve) => setTimeout(resolve, 700))
    setLoading(false)
    setAmount(386_000)
  }

  return (
    <ControlSizeProvider size="xl" asChild>
      <main className="flex min-h-svh items-start justify-center bg-muted p-4 sm:items-center">
        <Card className="w-full max-w-md">
          <CardHeader>
            <CardTitle asChild>
              <h1>پرداخت قبض</h1>
            </CardTitle>
            <CardDescription>شناسه‌ها روی قبض کاغذی یا پیامک قبض آمده‌اند.</CardDescription>
          </CardHeader>
          <ControlSizeProvider size="xl">
            <form onSubmit={lookup}>
              <CardContent className="flex flex-col gap-4">
                <div className="flex flex-col gap-2">
                  <Label id="bill-type">نوع قبض</Label>
                  <ToggleGroup
                    type="single"
                    variant="segmented"
                    fullWidth
                    value={type}
                    onValueChange={(value) => value && setType(value as string)}
                    aria-labelledby="bill-type"
                  >
                    {BILL_TYPES.map((item) => (
                      <ToggleGroupItem key={item.value} value={item.value} className="gap-2">
                        {/* eslint-disable-next-line @next/next/no-img-element -- لوگوی کوچکِ ثابت */}
                        <img src={`/logos/organizations/${item.logo}.svg`} alt="" className="size-5" />
                        {item.label}
                      </ToggleGroupItem>
                    ))}
                  </ToggleGroup>
                </div>
                <TextField
                  label="شناسهٔ قبض"
                  name="billId"
                  inputMode="numeric"
                  dir="ltr"
                  maxLength={13}
                  value={billId}
                  onValueChange={(value) => {
                    setBillId(value)
                    setAmount(null)
                  }}
                  required
                />
                <TextField
                  label="شناسهٔ پرداخت"
                  name="paymentId"
                  inputMode="numeric"
                  dir="ltr"
                  maxLength={13}
                  value={paymentId}
                  onValueChange={(value) => {
                    setPaymentId(value)
                    setAmount(null)
                  }}
                  required
                />
                {amount !== null && (
                  <>
                    <Separator />
                    <div className="flex items-center justify-between gap-2">
                      <span className="text-sm text-muted-foreground">مبلغ قابل پرداخت</span>
                      <span className="text-lg font-semibold">{formatCurrency(amount)}</span>
                    </div>
                  </>
                )}
              </CardContent>
              <CardFooter>
                {amount === null ? (
                  <Button type="submit" fullWidth loading={loading} disabled={billId.length < 6 || paymentId.length < 6}>
                    استعلام مبلغ
                  </Button>
                ) : (
                  <Button type="button" fullWidth onClick={() => toast.success("قبض پرداخت شد.")}>
                    پرداخت {formatCurrency(amount)}
                  </Button>
                )}
              </CardFooter>
            </form>
          </ControlSizeProvider>
        </Card>
      </main>
    </ControlSizeProvider>
  )
}