feat(frontend): create reusable components for Phase 1 refactoring
- Add Alert component with 4 variants (success/error/warning/info) - Add LoadingSpinner and LoadingButton components - Add FormInput and FormSelect components with icon support - Add Modal and ConfirmationModal components - Add ChatMessage, ChatMessageList, and ChatInput components - Add EventCard component These components will eliminate ~450 lines of duplicated code across pages. Part of Phase 1 (Quick Wins) frontend refactoring.
This commit is contained in:
93
frontend/src/components/modals/ConfirmationModal.jsx
Normal file
93
frontend/src/components/modals/ConfirmationModal.jsx
Normal file
@@ -0,0 +1,93 @@
|
||||
import { AlertTriangle, Loader2 } from 'lucide-react';
|
||||
|
||||
/**
|
||||
* Reusable Confirmation Modal for actions that need user confirmation
|
||||
*
|
||||
* @param {boolean} isOpen - Controls modal visibility
|
||||
* @param {function} onClose - Close/Cancel handler
|
||||
* @param {function} onConfirm - Confirm action handler
|
||||
* @param {string} title - Modal title
|
||||
* @param {string} description - Optional description text
|
||||
* @param {string} message - Main message/question to display
|
||||
* @param {string} confirmText - Confirm button text (default: 'Confirm')
|
||||
* @param {string} cancelText - Cancel button text (default: 'Cancel')
|
||||
* @param {string} confirmButtonClass - Custom classes for confirm button (default: red/danger style)
|
||||
* @param {React.Component} icon - Icon component (default: AlertTriangle)
|
||||
* @param {string} iconBgClass - Icon background class (default: bg-red-100)
|
||||
* @param {string} iconColorClass - Icon color class (default: text-red-600)
|
||||
* @param {boolean} isLoading - Shows loading state on confirm button
|
||||
* @param {string} loadingText - Text to show when loading (default: 'Loading...')
|
||||
*/
|
||||
const ConfirmationModal = ({
|
||||
isOpen,
|
||||
onClose,
|
||||
onConfirm,
|
||||
title,
|
||||
description,
|
||||
message,
|
||||
confirmText = 'Confirm',
|
||||
cancelText = 'Cancel',
|
||||
confirmButtonClass = 'bg-red-600 hover:bg-red-700',
|
||||
icon: Icon = AlertTriangle,
|
||||
iconBgClass = 'bg-red-100',
|
||||
iconColorClass = 'text-red-600',
|
||||
isLoading = false,
|
||||
loadingText = 'Loading...'
|
||||
}) => {
|
||||
if (!isOpen) return null;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50"
|
||||
onClick={onClose}
|
||||
>
|
||||
<div
|
||||
className="bg-white rounded-lg shadow-xl max-w-md w-full p-6"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{/* Header with Icon */}
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<div className={`w-12 h-12 rounded-full ${iconBgClass} flex items-center justify-center flex-shrink-0`}>
|
||||
<Icon className={iconColorClass} size={24} />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h3 className="text-lg font-semibold text-gray-900">{title}</h3>
|
||||
{description && <p className="text-sm text-gray-600">{description}</p>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Message */}
|
||||
{message && (
|
||||
<p className="text-gray-700 mb-6">{message}</p>
|
||||
)}
|
||||
|
||||
{/* Actions */}
|
||||
<div className="flex gap-3">
|
||||
<button
|
||||
onClick={onClose}
|
||||
disabled={isLoading}
|
||||
className="flex-1 px-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors font-medium disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{cancelText}
|
||||
</button>
|
||||
<button
|
||||
onClick={onConfirm}
|
||||
disabled={isLoading}
|
||||
className={`flex-1 px-4 py-2 ${confirmButtonClass} text-white rounded-lg transition-colors font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2`}
|
||||
>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<Loader2 className="animate-spin" size={16} />
|
||||
{loadingText}
|
||||
</>
|
||||
) : (
|
||||
confirmText
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ConfirmationModal;
|
||||
Reference in New Issue
Block a user