style(registration): compact identifier display

This commit is contained in:
2026-10-01 15:20:39 +03:30
parent e45f647c1d
commit 9b53a8c646
4 changed files with 15 additions and 8 deletions

View File

@@ -18,6 +18,7 @@ import {
} from "lucide-react"; } from "lucide-react";
import { Link } from "@/lib/router"; import { Link } from "@/lib/router";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { displayIdentifier } from "@/lib/utils";
export type OutcomeTone = "success" | "pending" | "failed" | "canceled" | "unknown" | "checking"; export type OutcomeTone = "success" | "pending" | "failed" | "canceled" | "unknown" | "checking";
@@ -239,7 +240,7 @@ export default function OutcomePage({
<section data-receipt-reference className="mt-4 flex flex-wrap items-center justify-between gap-3 rounded-xl border border-border px-4 py-3"> <section data-receipt-reference className="mt-4 flex flex-wrap items-center justify-between gap-3 rounded-xl border border-border px-4 py-3">
<div className="min-w-0"> <div className="min-w-0">
<p className="text-xs text-muted-foreground">{referenceLabel}</p> <p className="text-xs text-muted-foreground">{referenceLabel}</p>
<code dir="ltr" className="mt-1 block break-all text-left font-mono text-sm font-semibold text-foreground">{reference}</code> <code dir="ltr" className="mt-1 block break-all text-left font-mono text-sm font-semibold text-foreground">{displayIdentifier(reference)}</code>
</div> </div>
<Button type="button" variant="outline" size="sm" onClick={copyReference} className="registration-copy-reference gap-2" aria-label={`${referenceLabel} را کپی کنید`}> <Button type="button" variant="outline" size="sm" onClick={copyReference} className="registration-copy-reference gap-2" aria-label={`${referenceLabel} را کپی کنید`}>
{copied ? <BadgeCheck className="size-4" /> : <Copy className="size-4" />} {copied ? <BadgeCheck className="size-4" /> : <Copy className="size-4" />}

View File

@@ -6,6 +6,12 @@ export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs)); return twMerge(clsx(inputs));
} }
const UUID_PATTERN = /^[\da-f]{8}(?:-[\da-f]{4}){3}-[\da-f]{12}$/i;
export function displayIdentifier(value: string): string {
return UUID_PATTERN.test(value) ? value.slice(0, 8) : value;
}
export function formatJalali(iso?: string, withTime: boolean = true): string { export function formatJalali(iso?: string, withTime: boolean = true): string {
if (!iso) return '—'; if (!iso) return '—';
try { try {

View File

@@ -16,7 +16,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@
import { Link, Navigate, useParams } from "@/lib/router"; import { Link, Navigate, useParams } from "@/lib/router";
import type { RegistrationAdminSchema } from "@/lib/types"; import type { RegistrationAdminSchema } from "@/lib/types";
import { api } from "@/lib/api"; import { api } from "@/lib/api";
import { formatJalali, formatToman, getEventCardImageUrl, resolveErrorMessage, toPersianDigits } from "@/lib/utils"; import { displayIdentifier, formatJalali, formatToman, getEventCardImageUrl, resolveErrorMessage, toPersianDigits } from "@/lib/utils";
import { useAuth } from "@/contexts/AuthContext"; import { useAuth } from "@/contexts/AuthContext";
import { useToast } from "@/hooks/use-toast"; import { useToast } from "@/hooks/use-toast";
@@ -75,7 +75,7 @@ function RegistrationDialog({
<Info label="دانشگاه" value={registration.user.university} /> <Info label="دانشگاه" value={registration.user.university} />
<Info label="رشته" value={registration.user.major} /> <Info label="رشته" value={registration.user.major} />
<Info label="شماره دانشجویی" value={registration.user.student_id} /> <Info label="شماره دانشجویی" value={registration.user.student_id} />
<Info label="کد بلیت" value={registration.ticket_id} /> <Info label="کد بلیت" value={<code dir="ltr" className="font-mono">{displayIdentifier(registration.ticket_id)}</code>} />
<Info label="تاریخ ثبت‌نام" value={formatJalali(registration.registered_at)} /> <Info label="تاریخ ثبت‌نام" value={formatJalali(registration.registered_at)} />
<Info label="مبلغ نهایی" value={formatToman(registration.final_price ?? 0)} /> <Info label="مبلغ نهایی" value={formatToman(registration.final_price ?? 0)} />
<Info label="تخفیف" value={formatToman(registration.discount_amount ?? 0)} /> <Info label="تخفیف" value={formatToman(registration.discount_amount ?? 0)} />
@@ -87,8 +87,8 @@ function RegistrationDialog({
<div className="grid gap-2 md:grid-cols-2"> <div className="grid gap-2 md:grid-cols-2">
<Info label="وضعیت" value={payment.status_label} /> <Info label="وضعیت" value={payment.status_label} />
<Info label="مبلغ" value={formatToman(payment.amount)} /> <Info label="مبلغ" value={formatToman(payment.amount)} />
<Info label="کد رهگیری" value={payment.ref_id} /> <Info label="کد رهگیری" value={payment.ref_id ? <code dir="ltr" className="font-mono">{payment.ref_id}</code> : undefined} />
<Info label="Authority" value={payment.authority} /> <Info label="Authority" value={payment.authority ? <code dir="ltr" className="font-mono">{payment.authority}</code> : undefined} />
<Info label="کارت" value={payment.card_pan} /> <Info label="کارت" value={payment.card_pan} />
<Info label="کد تخفیف" value={payment.discount_code} /> <Info label="کد تخفیف" value={payment.discount_code} />
</div> </div>

View File

@@ -20,7 +20,7 @@ import {
normalizeCouponAmounts, normalizeCouponAmounts,
} from "@/lib/registration-hub-display"; } from "@/lib/registration-hub-display";
import type { RegistrationHubSchema, RegistrationHubState } from "@/lib/types"; import type { RegistrationHubSchema, RegistrationHubState } from "@/lib/types";
import { formatJalali, formatNumberPersian, formatToman, resolveErrorMessage } from "@/lib/utils"; import { displayIdentifier, formatJalali, formatNumberPersian, formatToman, resolveErrorMessage } from "@/lib/utils";
import { siteUrl } from "@/lib/site"; import { siteUrl } from "@/lib/site";
type Props = { type Props = {
@@ -443,9 +443,9 @@ export default function EventRegistrationHub({ slug, registrationId, paymentId }
...(data.payment ? [ ...(data.payment ? [
{ label: "وضعیت پرداخت", value: data.payment.status === "paid" ? "پرداخت تأییدشده" : data.payment.status === "failed" ? "ناموفق" : data.payment.status === "canceled" ? "لغوشده" : "در انتظار تأیید" }, { label: "وضعیت پرداخت", value: data.payment.status === "paid" ? "پرداخت تأییدشده" : data.payment.status === "failed" ? "ناموفق" : data.payment.status === "canceled" ? "لغوشده" : "در انتظار تأیید" },
{ label: "مبلغ پرداخت", value: money(data.payment.amount) }, { label: "مبلغ پرداخت", value: money(data.payment.amount) },
...(data.payment.ref_id ? [{ label: "کد پیگیری درگاه", value: data.payment.ref_id }] : []), ...(data.payment.ref_id ? [{ label: "کد پیگیری درگاه", value: <code dir="ltr" className="font-mono">{data.payment.ref_id}</code> }] : []),
] : []), ] : []),
...(data.registration ? [{ label: "کد ثبت‌نام", value: data.registration.ticket_id }] : []), ...(data.registration ? [{ label: "کد ثبت‌نام", value: <code dir="ltr" className="font-mono">{displayIdentifier(data.registration.ticket_id)}</code> }] : []),
...(data.registration?.registered_at ? [{ label: "تاریخ درخواست", value: formatJalali(data.registration.registered_at) }] : []), ...(data.registration?.registered_at ? [{ label: "تاریخ درخواست", value: formatJalali(data.registration.registered_at) }] : []),
] ]
: []; : [];