109 lines
3.5 KiB
TypeScript
109 lines
3.5 KiB
TypeScript
|
|
import React from 'react';
|
|||
|
|
import { AlertTriangle, X } from 'lucide-react';
|
|||
|
|
|
|||
|
|
interface Props {
|
|||
|
|
isOpen: boolean;
|
|||
|
|
onClose: () => void;
|
|||
|
|
onConfirm: () => void;
|
|||
|
|
title: string;
|
|||
|
|
message: string;
|
|||
|
|
itemName: string;
|
|||
|
|
isLoading?: boolean;
|
|||
|
|
warningMessage?: string;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export const DeleteConfirmModal: React.FC<Props> = ({
|
|||
|
|
isOpen,
|
|||
|
|
onClose,
|
|||
|
|
onConfirm,
|
|||
|
|
title,
|
|||
|
|
message,
|
|||
|
|
itemName,
|
|||
|
|
isLoading = false,
|
|||
|
|
warningMessage,
|
|||
|
|
}) => {
|
|||
|
|
if (!isOpen) return null;
|
|||
|
|
|
|||
|
|
const handleConfirm = () => {
|
|||
|
|
onConfirm();
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div
|
|||
|
|
className="fixed inset-0 z-[100] flex items-center justify-center p-4 bg-slate-900/80 backdrop-blur-md animate-fade-in"
|
|||
|
|
onClick={onClose}
|
|||
|
|
>
|
|||
|
|
<div
|
|||
|
|
className="bg-white rounded-2xl w-full max-w-md shadow-2xl animate-slide-up"
|
|||
|
|
onClick={(e) => e.stopPropagation()}
|
|||
|
|
>
|
|||
|
|
{/* Header */}
|
|||
|
|
<div className="p-6 border-b border-slate-200">
|
|||
|
|
<div className="flex items-start justify-between">
|
|||
|
|
<div className="flex items-center gap-3">
|
|||
|
|
<div className="p-2 bg-red-50 rounded-lg">
|
|||
|
|
<AlertTriangle className="w-6 h-6 text-red-500" />
|
|||
|
|
</div>
|
|||
|
|
<div>
|
|||
|
|
<h3 className="text-lg font-black text-slate-900">{title}</h3>
|
|||
|
|
<p className="text-sm text-slate-500 mt-1">{message}</p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<button
|
|||
|
|
onClick={onClose}
|
|||
|
|
disabled={isLoading}
|
|||
|
|
className="p-2 hover:bg-slate-100 rounded-full transition-colors disabled:opacity-50"
|
|||
|
|
>
|
|||
|
|
<X className="w-5 h-5 text-slate-400" />
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Content */}
|
|||
|
|
<div className="p-6">
|
|||
|
|
<div className="bg-slate-50 rounded-xl p-4 border border-slate-200">
|
|||
|
|
<p className="text-sm font-bold text-slate-700">
|
|||
|
|
<span className="text-slate-500">Удалить:</span> {itemName}
|
|||
|
|
</p>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{warningMessage && (
|
|||
|
|
<div className="mt-4 bg-amber-50 border border-amber-200 rounded-xl p-4">
|
|||
|
|
<p className="text-sm text-amber-800 font-medium">{warningMessage}</p>
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
|
|||
|
|
<p className="mt-4 text-sm text-slate-600">
|
|||
|
|
Это действие нельзя отменить. Все данные, связанные с этим элементом, будут удалены.
|
|||
|
|
</p>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Footer */}
|
|||
|
|
<div className="p-6 border-t border-slate-200 flex gap-3">
|
|||
|
|
<button
|
|||
|
|
onClick={onClose}
|
|||
|
|
disabled={isLoading}
|
|||
|
|
className="flex-1 px-4 py-3 rounded-xl border border-slate-200 text-slate-700 font-bold hover:bg-slate-50 transition-colors disabled:opacity-50"
|
|||
|
|
>
|
|||
|
|
Отмена
|
|||
|
|
</button>
|
|||
|
|
<button
|
|||
|
|
onClick={handleConfirm}
|
|||
|
|
disabled={isLoading}
|
|||
|
|
className="flex-1 px-4 py-3 rounded-xl bg-red-600 text-white font-bold hover:bg-red-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
|
|||
|
|
>
|
|||
|
|
{isLoading ? (
|
|||
|
|
<>
|
|||
|
|
<div className="w-4 h-4 border-2 border-white/50 border-t-white rounded-full animate-spin" />
|
|||
|
|
<span>Удаление...</span>
|
|||
|
|
</>
|
|||
|
|
) : (
|
|||
|
|
'Удалить'
|
|||
|
|
)}
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
};
|