Files
approagency-admin-panel/components/admin/ConfirmDialog.tsx
T

101 lines
4.1 KiB
TypeScript

'use client';
import { useEffect } from 'react';
import { ExclamationTriangleIcon } from '@heroicons/react/24/outline';
interface ConfirmDialogProps {
open: boolean;
title: string;
message: string;
confirmLabel?: string;
cancelLabel?: string;
tone?: 'danger' | 'primary';
isLoading?: boolean;
onConfirm: () => void;
onCancel: () => void;
}
// Styled replacement for the native confirm() dialog so destructive actions
// match the rest of the panel.
export default function ConfirmDialog({
open,
title,
message,
confirmLabel = 'تأیید',
cancelLabel = 'انصراف',
tone = 'danger',
isLoading = false,
onConfirm,
onCancel,
}: ConfirmDialogProps) {
useEffect(() => {
if (!open) return;
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === 'Escape' && !isLoading) onCancel();
};
document.addEventListener('keydown', handleKeyDown);
return () => document.removeEventListener('keydown', handleKeyDown);
}, [open, isLoading, onCancel]);
if (!open) return null;
const confirmClass =
tone === 'danger'
? 'bg-red-600 hover:bg-red-700 focus:ring-red-500/30 shadow-red-500/20'
: 'bg-indigo-600 hover:bg-indigo-700 focus:ring-indigo-500/30 shadow-indigo-500/20';
const iconWrapClass =
tone === 'danger'
? 'bg-red-50 text-red-600 dark:bg-red-500/10 dark:text-red-400'
: 'bg-indigo-50 text-indigo-600 dark:bg-indigo-500/10 dark:text-indigo-400';
return (
<div
className="fixed inset-0 z-50 flex items-center justify-center bg-black/40 dark:bg-black/60 p-4"
onClick={() => {
if (!isLoading) onCancel();
}}
>
<div
className="bg-white dark:bg-gray-900 rounded-2xl shadow-xl ring-1 ring-gray-200 dark:ring-gray-800 w-full max-w-md"
dir="rtl"
onClick={(event) => event.stopPropagation()}
role="alertdialog"
aria-modal="true"
aria-label={title}
>
<div className="px-6 py-5 flex items-start gap-4">
<div className={`flex-shrink-0 h-11 w-11 rounded-xl flex items-center justify-center ${iconWrapClass}`}>
<ExclamationTriangleIcon className="h-6 w-6" />
</div>
<div className="min-w-0">
<h3 className="text-base font-semibold text-gray-900 dark:text-gray-100">{title}</h3>
<p className="mt-1.5 text-sm text-gray-500 dark:text-gray-400 leading-6">{message}</p>
</div>
</div>
<div className="flex justify-end gap-3 px-6 py-4 border-t border-gray-100 dark:border-gray-800">
<button
type="button"
onClick={onCancel}
disabled={isLoading}
className="px-5 py-2.5 rounded-xl border border-gray-200 dark:border-gray-700 text-sm font-medium text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 disabled:opacity-50 transition-colors"
>
{cancelLabel}
</button>
<button
type="button"
onClick={onConfirm}
disabled={isLoading}
className={`inline-flex items-center gap-2 px-5 py-2.5 rounded-xl text-white text-sm font-medium focus:outline-none focus:ring-2 focus:ring-offset-2 dark:focus:ring-offset-gray-900 disabled:opacity-50 transition-colors shadow-sm ${confirmClass}`}
>
{isLoading && (
<span className="h-4 w-4 border-2 border-white/40 border-t-white rounded-full animate-spin" />
)}
{isLoading ? 'در حال انجام...' : confirmLabel}
</button>
</div>
</div>
</div>
);
}