TorbatYar/frontend/components/ds/Dialog.tsx
Mortezakoohjani 12c8615615 Ship enterprise Accounting FE/API with CRUD parity and production wiring.
Adds accounting-service PATCH/archive, fiscal helpers, COA templates and setup status, plus SuperApp Accounting UI (DS, scoreboard, masters, vouchers, ledger, ops modules) with session refresh and HTTPS public API URLs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-24 15:26:43 +03:30

117 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

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";
import { useEffect } from "react";
import { X } from "lucide-react";
import { cn } from "@/lib/utils";
import { Button } from "./Button";
export function Dialog({
open,
onClose,
title,
description,
children,
className,
size = "md",
}: {
open: boolean;
onClose: () => void;
title: string;
description?: string;
children: React.ReactNode;
className?: string;
size?: "sm" | "md" | "lg" | "xl";
}) {
useEffect(() => {
if (!open) return;
const onKey = (e: KeyboardEvent) => {
if (e.key === "Escape") onClose();
};
window.addEventListener("keydown", onKey);
return () => window.removeEventListener("keydown", onKey);
}, [open, onClose]);
if (!open) return null;
const widths = {
sm: "max-w-md",
md: "max-w-lg",
lg: "max-w-2xl",
xl: "max-w-4xl",
};
return (
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
<button
type="button"
aria-label="بستن"
className="absolute inset-0 bg-black/40 backdrop-blur-[1px]"
onClick={onClose}
/>
<div
role="dialog"
aria-modal="true"
aria-labelledby="dialog-title"
className={cn(
"relative z-10 w-full rounded-2xl border border-[var(--border)] bg-[var(--surface)] shadow-[var(--shadow-lg)]",
widths[size],
className
)}
>
<div className="flex items-start justify-between gap-3 border-b border-[var(--border)] px-5 py-4">
<div>
<h2 id="dialog-title" className="text-base font-semibold text-secondary">
{title}
</h2>
{description ? (
<p className="mt-1 text-sm text-[var(--muted)]">{description}</p>
) : null}
</div>
<Button type="button" variant="ghost" size="icon" onClick={onClose} aria-label="بستن">
<X className="h-4 w-4" />
</Button>
</div>
<div className="px-5 py-4">{children}</div>
</div>
</div>
);
}
export function ConfirmDialog({
open,
onClose,
onConfirm,
title,
description,
confirmLabel = "تأیید",
danger,
loading,
}: {
open: boolean;
onClose: () => void;
onConfirm: () => void;
title: string;
description?: string;
confirmLabel?: string;
danger?: boolean;
loading?: boolean;
}) {
return (
<Dialog open={open} onClose={onClose} title={title} description={description} size="sm">
<div className="flex justify-end gap-2">
<Button type="button" variant="outline" onClick={onClose} disabled={loading}>
انصراف
</Button>
<Button
type="button"
variant={danger ? "danger" : "default"}
onClick={onConfirm}
disabled={loading}
>
{loading ? "در حال انجام…" : confirmLabel}
</Button>
</div>
</Dialog>
);
}