70 lines
2.7 KiB
TypeScript
70 lines
2.7 KiB
TypeScript
|
|
import React from 'react';
|
||
|
|
|
||
|
|
interface ConfirmModalProps {
|
||
|
|
isOpen: boolean;
|
||
|
|
title?: string;
|
||
|
|
message: React.ReactNode;
|
||
|
|
confirmText?: string;
|
||
|
|
cancelText?: string;
|
||
|
|
confirmButtonClass?: string;
|
||
|
|
onConfirm: () => void;
|
||
|
|
onCancel: () => void;
|
||
|
|
isLoading?: boolean;
|
||
|
|
}
|
||
|
|
|
||
|
|
const ConfirmModal: React.FC<ConfirmModalProps> = ({
|
||
|
|
isOpen,
|
||
|
|
title = 'Xác nhận',
|
||
|
|
message,
|
||
|
|
confirmText = 'Xác nhận',
|
||
|
|
cancelText = 'Huỷ',
|
||
|
|
confirmButtonClass = 'bg-rose-600 hover:bg-rose-700',
|
||
|
|
onConfirm,
|
||
|
|
onCancel,
|
||
|
|
isLoading = false,
|
||
|
|
}) => {
|
||
|
|
if (!isOpen) return null;
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center p-4 z-[60]">
|
||
|
|
<div className="bg-slate-800 rounded-xl shadow-2xl border border-slate-700 max-w-md w-full">
|
||
|
|
{/* Header */}
|
||
|
|
<div className="p-6 border-b border-slate-700">
|
||
|
|
<h3 className="text-lg font-semibold text-white">{title}</h3>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Content */}
|
||
|
|
<div className="p-6">
|
||
|
|
<div className="text-slate-300">{message}</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Footer */}
|
||
|
|
<div className="flex justify-end gap-3 p-6 border-t border-slate-700">
|
||
|
|
<button
|
||
|
|
onClick={onCancel}
|
||
|
|
disabled={isLoading}
|
||
|
|
className="px-4 py-2 bg-slate-700 hover:bg-slate-600 text-white rounded-lg font-medium transition-colors disabled:opacity-50"
|
||
|
|
>
|
||
|
|
{cancelText}
|
||
|
|
</button>
|
||
|
|
<button
|
||
|
|
onClick={onConfirm}
|
||
|
|
disabled={isLoading}
|
||
|
|
className={`px-4 py-2 text-white rounded-lg font-medium transition-colors disabled:opacity-50 flex items-center gap-2 ${confirmButtonClass}`}
|
||
|
|
>
|
||
|
|
{isLoading && (
|
||
|
|
<svg className="w-4 h-4 animate-spin" fill="none" viewBox="0 0 24 24">
|
||
|
|
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
|
||
|
|
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||
|
|
</svg>
|
||
|
|
)}
|
||
|
|
{confirmText}
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
};
|
||
|
|
|
||
|
|
export default ConfirmModal;
|