181 lines
10 KiB
JavaScript
181 lines
10 KiB
JavaScript
import React, { useState } from 'react';
|
|
import { Head } from '@inertiajs/react';
|
|
import AdminLayout from '../../../Layouts/AdminLayout';
|
|
import { Megaphone, Plus, Trash2, Send, CheckCircle2 } from 'lucide-react';
|
|
|
|
export default function Announcements() {
|
|
const [announcements, setAnnouncements] = useState([
|
|
{
|
|
id: 1,
|
|
title: 'New Visa Regulations Update',
|
|
content: 'The Ministry of Human Resources and Emiratisation has announced updated guidelines for domestic worker sponsorship starting this month.',
|
|
audience: 'Both',
|
|
created_at: 'May 10, 2026',
|
|
},
|
|
{
|
|
id: 2,
|
|
title: 'Enhanced OCR Verification Active',
|
|
content: 'We have deployed upgraded OCR passport verification to ensure 100% legal compliance for all worker profiles on the platform.',
|
|
audience: 'Employers',
|
|
created_at: 'May 1, 2026',
|
|
},
|
|
]);
|
|
|
|
const [isFormOpen, setIsFormOpen] = useState(false);
|
|
const [newAnnouncement, setNewAnnouncement] = useState({ title: '', content: '', audience: 'Both' });
|
|
const [toastMessage, setToastMessage] = useState(null);
|
|
|
|
const showToast = (message) => {
|
|
setToastMessage(message);
|
|
setTimeout(() => setToastMessage(null), 3000);
|
|
};
|
|
|
|
const handleCreate = (e) => {
|
|
e.preventDefault();
|
|
const newEntry = {
|
|
id: announcements.length + 1,
|
|
title: newAnnouncement.title,
|
|
content: newAnnouncement.content,
|
|
audience: newAnnouncement.audience,
|
|
created_at: 'Just now',
|
|
};
|
|
setAnnouncements([newEntry, ...announcements]);
|
|
setNewAnnouncement({ title: '', content: '', audience: 'Both' });
|
|
setIsFormOpen(false);
|
|
showToast('Announcement sent successfully');
|
|
};
|
|
|
|
const handleDelete = (id) => {
|
|
setAnnouncements(announcements.filter(a => a.id !== id));
|
|
showToast('Announcement deleted');
|
|
};
|
|
|
|
return (
|
|
<AdminLayout title="Announcements">
|
|
<Head title="Announcements - Admin Portal" />
|
|
|
|
{/* Toast Notification */}
|
|
{toastMessage && (
|
|
<div className="fixed bottom-4 right-4 bg-slate-900 text-white px-6 py-3 rounded-xl shadow-2xl flex items-center space-x-3 z-50 animate-in slide-in-from-bottom-5">
|
|
<CheckCircle2 className="w-5 h-5 text-emerald-400" />
|
|
<span className="font-medium text-sm">{toastMessage}</span>
|
|
</div>
|
|
)}
|
|
|
|
<div className="space-y-6 select-none max-w-6xl mx-auto">
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<h1 className="text-2xl font-bold text-slate-900">Platform Announcements</h1>
|
|
<p className="text-sm text-slate-500">Broadcast messages to employers and workers.</p>
|
|
</div>
|
|
<button
|
|
onClick={() => setIsFormOpen(true)}
|
|
className="bg-[#185FA5] hover:bg-[#144f8a] text-white px-5 py-2.5 rounded-xl font-bold text-sm flex items-center space-x-2 transition-colors shadow-sm"
|
|
>
|
|
<Plus className="w-4 h-4" />
|
|
<span>New Announcement</span>
|
|
</button>
|
|
</div>
|
|
|
|
{isFormOpen && (
|
|
<div className="bg-white p-6 rounded-2xl border border-slate-200 shadow-sm animate-in fade-in slide-in-from-top-4">
|
|
<div className="flex items-center space-x-2 mb-4 text-[#185FA5] font-bold">
|
|
<Megaphone className="w-5 h-5" />
|
|
<h2>Compose Message</h2>
|
|
</div>
|
|
<form onSubmit={handleCreate} className="space-y-4">
|
|
<div>
|
|
<label className="block text-xs font-semibold text-slate-600 mb-1">Title</label>
|
|
<input
|
|
type="text"
|
|
required
|
|
value={newAnnouncement.title}
|
|
onChange={(e) => setNewAnnouncement({ ...newAnnouncement, title: e.target.value })}
|
|
className="w-full px-4 py-2.5 rounded-xl border border-slate-300 text-sm focus:ring-2 focus:ring-[#185FA5]/20 focus:border-[#185FA5] outline-none transition-all"
|
|
placeholder="Enter announcement title..."
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label className="block text-xs font-semibold text-slate-600 mb-1">Content</label>
|
|
<textarea
|
|
required
|
|
rows="4"
|
|
value={newAnnouncement.content}
|
|
onChange={(e) => setNewAnnouncement({ ...newAnnouncement, content: e.target.value })}
|
|
className="w-full px-4 py-3 rounded-xl border border-slate-300 text-sm focus:ring-2 focus:ring-[#185FA5]/20 focus:border-[#185FA5] outline-none transition-all resize-none"
|
|
placeholder="Type your message here..."
|
|
></textarea>
|
|
</div>
|
|
<div>
|
|
<label className="block text-xs font-semibold text-slate-600 mb-1">Target Audience</label>
|
|
<select
|
|
value={newAnnouncement.audience}
|
|
onChange={(e) => setNewAnnouncement({ ...newAnnouncement, audience: e.target.value })}
|
|
className="w-full sm:w-64 px-4 py-2.5 rounded-xl border border-slate-300 text-sm focus:ring-2 focus:ring-[#185FA5]/20 focus:border-[#185FA5] outline-none transition-all bg-white"
|
|
>
|
|
<option value="Both">Both Employers & Workers</option>
|
|
<option value="Employers">Employers Only</option>
|
|
<option value="Workers">Workers Only</option>
|
|
</select>
|
|
</div>
|
|
<div className="flex items-center justify-end space-x-3 pt-2">
|
|
<button
|
|
type="button"
|
|
onClick={() => setIsFormOpen(false)}
|
|
className="px-5 py-2.5 rounded-xl text-sm font-semibold text-slate-600 hover:bg-slate-100 transition-colors"
|
|
>
|
|
Cancel
|
|
</button>
|
|
<button
|
|
type="submit"
|
|
className="bg-emerald-600 hover:bg-emerald-700 text-white px-6 py-2.5 rounded-xl text-sm font-bold flex items-center space-x-2 transition-colors shadow-sm"
|
|
>
|
|
<Send className="w-4 h-4" />
|
|
<span>Broadcast Message</span>
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
)}
|
|
|
|
<div className="space-y-4">
|
|
{announcements.length === 0 ? (
|
|
<div className="text-center py-16 bg-white rounded-2xl border border-slate-200 shadow-sm text-slate-500">
|
|
<Megaphone className="w-12 h-12 text-slate-300 mx-auto mb-3" />
|
|
<p className="font-medium text-sm">No announcements published yet.</p>
|
|
</div>
|
|
) : (
|
|
announcements.map((ann) => (
|
|
<div key={ann.id} className="bg-white p-6 rounded-2xl border border-slate-200 shadow-sm flex flex-col sm:flex-row sm:items-start justify-between gap-4 group">
|
|
<div className="space-y-2 flex-1">
|
|
<div className="flex items-center space-x-3">
|
|
<h3 className="font-bold text-lg text-slate-900 tracking-tight">{ann.title}</h3>
|
|
<span className={`px-2.5 py-1 rounded-md text-[10px] font-bold uppercase tracking-wider ${
|
|
ann.audience === 'Both' ? 'bg-purple-100 text-purple-700' :
|
|
ann.audience === 'Employers' ? 'bg-blue-100 text-blue-700' :
|
|
'bg-emerald-100 text-emerald-700'
|
|
}`}>
|
|
To: {ann.audience}
|
|
</span>
|
|
</div>
|
|
<p className="text-sm text-slate-600 leading-relaxed">{ann.content}</p>
|
|
<div className="text-[11px] font-medium text-slate-400">
|
|
Published: {ann.created_at}
|
|
</div>
|
|
</div>
|
|
<button
|
|
onClick={() => handleDelete(ann.id)}
|
|
className="p-2 text-slate-400 hover:text-red-600 hover:bg-red-50 rounded-xl transition-colors self-start sm:opacity-0 group-hover:opacity-100 focus:opacity-100"
|
|
title="Delete Announcement"
|
|
>
|
|
<Trash2 className="w-5 h-5" />
|
|
</button>
|
|
</div>
|
|
))
|
|
)}
|
|
</div>
|
|
</div>
|
|
</AdminLayout>
|
|
);
|
|
}
|