Files
Hotel-Booking/Frontend/src/features/notifications/components/NotificationTemplatesModal.tsx
Iliyan Angelov 39fcfff811 update
2025-11-30 22:43:09 +02:00

211 lines
8.8 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import { X, Plus } from 'lucide-react';
import { toast } from 'react-toastify';
import notificationService, { NotificationTemplate } from '../services/notificationService';
interface NotificationTemplatesModalProps {
onClose: () => void;
}
const NotificationTemplatesModal: React.FC<NotificationTemplatesModalProps> = ({ onClose }) => {
const [templates, setTemplates] = useState<NotificationTemplate[]>([]);
const [loading, setLoading] = useState(true);
const [showCreate, setShowCreate] = useState(false);
const [formData, setFormData] = useState({
name: '',
notification_type: 'booking_confirmation',
channel: 'email',
subject: '',
content: '',
});
useEffect(() => {
loadTemplates();
}, []);
const loadTemplates = async () => {
try {
setLoading(true);
const response = await notificationService.getTemplates();
setTemplates(response.data.data || []);
} catch (error: any) {
toast.error(error.message || 'Failed to load templates');
} finally {
setLoading(false);
}
};
const handleCreate = async (e: React.FormEvent) => {
e.preventDefault();
if (!formData.name.trim() || !formData.content.trim()) {
toast.error('Name and content are required');
return;
}
try {
await notificationService.createTemplate(formData);
toast.success('Template created successfully');
setShowCreate(false);
setFormData({
name: '',
notification_type: 'booking_confirmation',
channel: 'email',
subject: '',
content: '',
});
loadTemplates();
} catch (error: any) {
toast.error(error.message || 'Failed to create template');
}
};
return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
<div className="bg-white rounded-xl shadow-2xl max-w-4xl w-full max-h-[90vh] overflow-y-auto">
<div className="sticky top-0 bg-white border-b border-gray-200 p-6 flex items-center justify-between">
<h2 className="text-2xl font-bold text-gray-900">Notification Templates</h2>
<div className="flex items-center gap-2">
<button
onClick={() => setShowCreate(true)}
className="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors flex items-center gap-2"
>
<Plus className="w-4 h-4" />
Create Template
</button>
<button
onClick={onClose}
className="p-2 hover:bg-gray-100 rounded-lg transition-colors"
>
<X className="w-5 h-5" />
</button>
</div>
</div>
<div className="p-6">
{showCreate ? (
<form onSubmit={handleCreate} className="space-y-4">
<div>
<label className="block text-sm font-semibold text-gray-700 mb-2">Name *</label>
<input
type="text"
value={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
required
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-semibold text-gray-700 mb-2">Type</label>
<select
value={formData.notification_type}
onChange={(e) => setFormData({ ...formData, notification_type: e.target.value })}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
>
<option value="booking_confirmation">Booking Confirmation</option>
<option value="payment_receipt">Payment Receipt</option>
<option value="pre_arrival_reminder">Pre-Arrival Reminder</option>
<option value="check_in_reminder">Check-In Reminder</option>
<option value="check_out_reminder">Check-Out Reminder</option>
<option value="marketing_campaign">Marketing Campaign</option>
<option value="loyalty_update">Loyalty Update</option>
<option value="system_alert">System Alert</option>
</select>
</div>
<div>
<label className="block text-sm font-semibold text-gray-700 mb-2">Channel</label>
<select
value={formData.channel}
onChange={(e) => setFormData({ ...formData, channel: e.target.value })}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
>
<option value="email">Email</option>
<option value="sms">SMS</option>
<option value="push">Push</option>
<option value="whatsapp">WhatsApp</option>
<option value="in_app">In-App</option>
</select>
</div>
</div>
{(formData.channel === 'email' || formData.channel === 'push') && (
<div>
<label className="block text-sm font-semibold text-gray-700 mb-2">Subject</label>
<input
type="text"
value={formData.subject}
onChange={(e) => setFormData({ ...formData, subject: e.target.value })}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
placeholder="Use {{variable_name}} for variables"
/>
</div>
)}
<div>
<label className="block text-sm font-semibold text-gray-700 mb-2">Content *</label>
<textarea
value={formData.content}
onChange={(e) => setFormData({ ...formData, content: e.target.value })}
rows={8}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
placeholder="Use {{variable_name}} for variables (e.g., {{booking_number}}, {{guest_name}})"
required
/>
<p className="text-xs text-gray-500 mt-1">
Available variables: booking_number, guest_name, check_in, check_out, total_price, payment_amount, etc.
</p>
</div>
<div className="flex items-center justify-end gap-3">
<button
type="button"
onClick={() => setShowCreate(false)}
className="px-4 py-2 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300"
>
Cancel
</button>
<button
type="submit"
className="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700"
>
Create Template
</button>
</div>
</form>
) : (
<>
{loading ? (
<div className="text-center py-8">Loading templates...</div>
) : templates.length === 0 ? (
<div className="text-center py-8 text-gray-500">
No templates found. Create your first template.
</div>
) : (
<div className="space-y-4">
{templates.map((template) => (
<div key={template.id} className="border border-gray-200 rounded-lg p-4">
<div className="flex items-start justify-between mb-2">
<div>
<h3 className="font-semibold text-gray-900">{template.name}</h3>
<p className="text-sm text-gray-500">
{template.notification_type.replace('_', ' ')} {template.channel}
</p>
</div>
</div>
{template.subject && (
<p className="text-sm font-medium text-gray-700 mb-2">Subject: {template.subject}</p>
)}
<p className="text-sm text-gray-600 line-clamp-3">{template.content}</p>
</div>
))}
</div>
)}
</>
)}
</div>
</div>
</div>
);
};
export default NotificationTemplatesModal;