358 lines
23 KiB
JavaScript
358 lines
23 KiB
JavaScript
import React, { useState, useEffect } from 'react';
|
|
import { Head, useForm } from '@inertiajs/react';
|
|
import EmployerLayout from '../../Layouts/EmployerLayout';
|
|
import {
|
|
Megaphone,
|
|
Send,
|
|
CheckCircle2,
|
|
Users,
|
|
Search,
|
|
Calendar,
|
|
Target,
|
|
Filter,
|
|
ChevronRight,
|
|
MessageSquare,
|
|
Info,
|
|
Heart,
|
|
MapPin,
|
|
Clock,
|
|
Sparkles,
|
|
BellRing
|
|
} from 'lucide-react';
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
DialogTrigger,
|
|
DialogFooter
|
|
} from '@/components/ui/dialog';
|
|
|
|
export default function Announcements({ initialAnnouncements }) {
|
|
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
|
const [searchTerm, setSearchTerm] = useState('');
|
|
const [toastMessage, setToastMessage] = useState(null);
|
|
const [toastSub, setToastSub] = useState(null);
|
|
const [announcements, setAnnouncements] = useState(initialAnnouncements || []);
|
|
|
|
useEffect(() => {
|
|
setAnnouncements(initialAnnouncements || []);
|
|
}, [initialAnnouncements]);
|
|
|
|
const { data: newAnnouncement, setData: setNewAnnouncement, post, processing, reset } = useForm({
|
|
title: '',
|
|
content: '',
|
|
audience: 'Charity',
|
|
type: 'Charity',
|
|
provided_items: '',
|
|
event_date: '',
|
|
event_time: '',
|
|
location_details: '',
|
|
location_pin: ''
|
|
});
|
|
|
|
const showToast = (message, subMessage = null) => {
|
|
setToastMessage(message);
|
|
setToastSub(subMessage);
|
|
setTimeout(() => {
|
|
setToastMessage(null);
|
|
setToastSub(null);
|
|
}, 5000);
|
|
};
|
|
|
|
const handleCreate = (e) => {
|
|
e.preventDefault();
|
|
post('/employer/announcements/create', {
|
|
preserveScroll: true,
|
|
onSuccess: () => {
|
|
reset();
|
|
setIsDialogOpen(false);
|
|
showToast(
|
|
'💖 COMMUNITY CHARITY EVENT POSTED!',
|
|
'🔔 Instant Push Notification sent to all workers in Dubai! ⏰ Morning-of reminder notification scheduled successfully.'
|
|
);
|
|
}
|
|
});
|
|
};
|
|
|
|
const filteredAnnouncements = announcements.filter(ann =>
|
|
ann.title.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
ann.content.toLowerCase().includes(searchTerm.toLowerCase())
|
|
);
|
|
|
|
return (
|
|
<EmployerLayout title="Charity Events & Support Drives">
|
|
<Head title="Community Charity Events - Sponsor Hub" />
|
|
|
|
{toastMessage && (
|
|
<div className="fixed bottom-8 right-8 bg-slate-900 text-white px-6 py-5 rounded-[24px] shadow-2xl border border-slate-800 flex items-start space-x-3.5 z-[100] max-w-md animate-in slide-in-from-bottom-5 duration-350">
|
|
<div className="bg-emerald-500 p-2 rounded-xl shrink-0 mt-0.5 shadow-md shadow-emerald-500/20">
|
|
<CheckCircle2 className="w-5 h-5 text-white" />
|
|
</div>
|
|
<div className="space-y-1">
|
|
<div className="font-black text-xs uppercase tracking-widest text-emerald-400">{toastMessage}</div>
|
|
{toastSub && <p className="text-[11px] text-slate-350 leading-relaxed font-semibold">{toastSub}</p>}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<div className="space-y-6 select-none max-w-5xl mx-auto">
|
|
|
|
{/* Community Drive & Charity Banner */}
|
|
<div className="bg-gradient-to-br from-rose-500/10 via-pink-500/5 to-transparent border border-rose-200 rounded-[32px] p-6 sm:p-8 flex flex-col md:flex-row md:items-center justify-between gap-6">
|
|
<div className="space-y-2 max-w-2xl">
|
|
<div className="inline-flex items-center space-x-2 px-3 py-1 bg-rose-50 border border-rose-100 rounded-full text-[10px] font-black uppercase tracking-wider text-rose-700">
|
|
<Heart className="w-3.5 h-3.5 fill-rose-500 text-rose-500 animate-pulse" />
|
|
<span>Dubai Community Support Drives</span>
|
|
</div>
|
|
<h2 className="text-xl font-black text-slate-900 tracking-tight">Free Medical Checks, Food Drives & Support Services</h2>
|
|
<p className="text-xs text-slate-500 font-bold leading-relaxed">
|
|
Organizing a support program? Share community campaigns directly. The platform will automatically push an **instant pop-up notification** to workers, followed by a **morning-of event reminder** to keep attendance strong.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4 bg-white p-6 rounded-[32px] border border-slate-100 shadow-sm">
|
|
<div className="relative flex-1 max-w-md group">
|
|
<Search className="absolute left-4 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400 group-focus-within:text-[#185FA5] transition-colors" />
|
|
<input
|
|
type="text"
|
|
placeholder="Search charity events & drives..."
|
|
value={searchTerm}
|
|
onChange={(e) => setSearchTerm(e.target.value)}
|
|
className="w-full pl-12 pr-4 py-3 bg-slate-50 border-none rounded-2xl text-sm font-bold focus:ring-2 focus:ring-blue-100 transition-all outline-none"
|
|
/>
|
|
</div>
|
|
|
|
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
|
|
<DialogTrigger asChild>
|
|
<button className="bg-rose-600 hover:bg-rose-700 text-white px-8 py-3.5 rounded-2xl font-black text-xs uppercase tracking-widest flex items-center justify-center space-x-2 transition-all shadow-lg shadow-rose-200/50 hover:-translate-y-1 active:translate-y-0">
|
|
<Heart className="w-4 h-4 fill-white" />
|
|
<span>Post Charity Event</span>
|
|
</button>
|
|
</DialogTrigger>
|
|
<DialogContent className="sm:max-w-[550px] rounded-3xl p-0 overflow-hidden border-none shadow-2xl">
|
|
<div className="bg-gradient-to-r from-rose-500 to-pink-600 p-8 text-white relative">
|
|
<div className="absolute top-0 right-0 w-32 h-32 bg-white/10 rounded-full -mr-16 -mt-16 blur-2xl" />
|
|
<DialogTitle className="text-2xl font-black relative z-10">Post Charity Event</DialogTitle>
|
|
<DialogDescription className="text-pink-100 font-semibold mt-2 relative z-10">
|
|
Broadcast a support program, medical camp, or distribution drive to the worker community.
|
|
</DialogDescription>
|
|
</div>
|
|
|
|
<form onSubmit={handleCreate} className="p-8 space-y-5 bg-white max-h-[80vh] overflow-y-auto">
|
|
|
|
<div className="space-y-4 p-4 bg-rose-50/50 rounded-2xl border border-rose-100 animate-in fade-in duration-200">
|
|
<div className="text-[10px] font-black text-rose-800 uppercase tracking-widest flex items-center gap-1.5">
|
|
<Heart className="w-3.5 h-3.5 fill-rose-500 text-rose-500" />
|
|
<span>Charity Drive Metadata (Dubai Support)</span>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-2 gap-3">
|
|
<div className="space-y-1">
|
|
<label className="text-[9px] font-black text-slate-500 uppercase tracking-widest ml-1">Event Date</label>
|
|
<input
|
|
type="date"
|
|
required
|
|
value={newAnnouncement.event_date}
|
|
onChange={(e) => setNewAnnouncement({ ...newAnnouncement, event_date: e.target.value })}
|
|
className="w-full px-3 py-2 bg-white border border-slate-200 rounded-xl text-xs font-bold focus:ring-2 focus:ring-rose-100 outline-none"
|
|
/>
|
|
</div>
|
|
<div className="space-y-1">
|
|
<label className="text-[9px] font-black text-slate-500 uppercase tracking-widest ml-1">Event Time</label>
|
|
<input
|
|
type="text"
|
|
required
|
|
placeholder="e.g. 9:00 AM - 4:00 PM"
|
|
value={newAnnouncement.event_time}
|
|
onChange={(e) => setNewAnnouncement({ ...newAnnouncement, event_time: e.target.value })}
|
|
className="w-full px-3 py-2 bg-white border border-slate-200 rounded-xl text-xs font-bold focus:ring-2 focus:ring-rose-100 outline-none"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-1">
|
|
<label className="text-[9px] font-black text-slate-500 uppercase tracking-widest ml-1">What is Being Provided</label>
|
|
<input
|
|
type="text"
|
|
required
|
|
placeholder="e.g. Free Medical Check, Food Boxes, Supplies"
|
|
value={newAnnouncement.provided_items}
|
|
onChange={(e) => setNewAnnouncement({ ...newAnnouncement, provided_items: e.target.value })}
|
|
className="w-full px-3.5 py-2.5 bg-white border border-slate-200 rounded-xl text-xs font-bold focus:ring-2 focus:ring-rose-100 outline-none"
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-1">
|
|
<label className="text-[9px] font-black text-slate-500 uppercase tracking-widest ml-1">Location Details & Pin URL</label>
|
|
<input
|
|
type="text"
|
|
required
|
|
placeholder="e.g. Al Quoz Community Center, Dubai"
|
|
value={newAnnouncement.location_details}
|
|
onChange={(e) => setNewAnnouncement({ ...newAnnouncement, location_details: e.target.value })}
|
|
className="w-full px-3.5 py-2.5 bg-white border border-slate-200 rounded-xl text-xs font-bold focus:ring-2 focus:ring-rose-100 outline-none mb-2"
|
|
/>
|
|
<input
|
|
type="url"
|
|
required
|
|
placeholder="Google Maps Pin Link (e.g. https://maps.app.goo.gl/xyz)"
|
|
value={newAnnouncement.location_pin}
|
|
onChange={(e) => setNewAnnouncement({ ...newAnnouncement, location_pin: e.target.value })}
|
|
className="w-full px-3.5 py-2.5 bg-white border border-slate-200 rounded-xl text-xs font-bold focus:ring-2 focus:ring-rose-100 outline-none"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<label className="text-[10px] font-black text-slate-500 uppercase tracking-widest ml-1">Title</label>
|
|
<input
|
|
type="text"
|
|
required
|
|
value={newAnnouncement.title}
|
|
onChange={(e) => setNewAnnouncement({ ...newAnnouncement, title: e.target.value })}
|
|
className="w-full px-5 py-3.5 bg-slate-50 border-none rounded-2xl text-sm font-bold focus:ring-2 focus:ring-blue-100 transition-all outline-none"
|
|
placeholder="e.g. Free Dental checkup by Emirates Charity"
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<label className="text-[10px] font-black text-slate-500 uppercase tracking-widest ml-1">Event Description & Instructions</label>
|
|
<textarea
|
|
required
|
|
rows="3"
|
|
value={newAnnouncement.content}
|
|
onChange={(e) => setNewAnnouncement({ ...newAnnouncement, content: e.target.value })}
|
|
className="w-full px-5 py-4 bg-slate-50 border-none rounded-2xl text-sm font-bold focus:ring-2 focus:ring-blue-100 transition-all outline-none resize-none"
|
|
placeholder="Enter details of the charity event here..."
|
|
></textarea>
|
|
</div>
|
|
|
|
<DialogFooter className="pt-2">
|
|
<button
|
|
type="submit"
|
|
disabled={processing}
|
|
className="w-full bg-rose-600 hover:bg-rose-700 text-white py-4 rounded-2xl text-xs font-black uppercase tracking-widest flex items-center justify-center space-x-2 transition-all shadow-lg shadow-rose-200/50"
|
|
>
|
|
<Send className="w-4 h-4" />
|
|
<span>Publish Charity Event</span>
|
|
</button>
|
|
</DialogFooter>
|
|
</form>
|
|
</DialogContent>
|
|
</Dialog>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 gap-5">
|
|
{filteredAnnouncements.length === 0 ? (
|
|
<div className="text-center py-24 bg-white rounded-[40px] border border-slate-200 shadow-sm text-slate-500 border-dashed">
|
|
<div className="w-20 h-20 bg-slate-50 rounded-full flex items-center justify-center mx-auto mb-6">
|
|
<Megaphone className="w-10 h-10 text-slate-200" />
|
|
</div>
|
|
<h3 className="font-black text-slate-900 text-lg uppercase tracking-tight">No announcements</h3>
|
|
<p className="font-bold text-xs text-slate-400 mt-1 uppercase tracking-widest">You haven't posted any announcements yet</p>
|
|
</div>
|
|
) : (
|
|
filteredAnnouncements.map((ann) => {
|
|
const details = ann.charityDetails;
|
|
|
|
return (
|
|
<div
|
|
key={ann.id}
|
|
className="group bg-white rounded-[32px] border border-rose-100 bg-rose-50/10 p-6 shadow-sm hover:shadow-md transition-all duration-300 relative overflow-hidden flex flex-col md:flex-row md:items-start gap-6"
|
|
>
|
|
<div className="absolute right-0 top-0 w-24 h-24 bg-rose-500/5 rounded-full blur-2xl pointer-events-none" />
|
|
|
|
<div className="flex-1 space-y-4">
|
|
<div className="flex flex-wrap items-center gap-3">
|
|
<span className="px-3 py-1.5 rounded-xl text-[9px] font-black uppercase tracking-widest border bg-rose-50 border-rose-100 text-rose-700 flex items-center space-x-1">
|
|
<Heart className="w-3 h-3 fill-rose-500 text-rose-500" />
|
|
<span>COMMUNITY CHARITY DRIVE</span>
|
|
</span>
|
|
|
|
<div className="flex items-center text-slate-400 text-[10px] font-black uppercase tracking-widest">
|
|
<Calendar className="w-3.5 h-3.5 mr-1.5" />
|
|
{ann.created_at}
|
|
</div>
|
|
|
|
<div className="inline-flex items-center space-x-1 px-2.5 py-1 bg-emerald-50 rounded-lg text-[9px] font-bold text-emerald-800 border border-emerald-100">
|
|
<BellRing className="w-3 h-3 text-emerald-600 animate-bounce" />
|
|
<span>Push & Reminder Scheduled</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<h4 className="text-lg font-black text-slate-900 tracking-tight flex items-center gap-2">
|
|
<Sparkles className="w-4 h-4 text-rose-500" />
|
|
{ann.title}
|
|
</h4>
|
|
<p className="text-xs text-slate-600 font-bold leading-relaxed">{ann.content}</p>
|
|
</div>
|
|
|
|
{details && (
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-3 p-4 bg-white/80 rounded-2xl border border-rose-100/60 text-xs font-bold text-slate-600">
|
|
<div className="flex items-center space-x-2.5">
|
|
<div className="w-8 h-8 rounded-lg bg-rose-50 flex items-center justify-center text-rose-600 shrink-0">
|
|
<Heart className="w-4 h-4 fill-rose-500 text-rose-500" />
|
|
</div>
|
|
<div>
|
|
<div className="text-[9px] text-slate-400 uppercase font-black tracking-widest">Provided Packages</div>
|
|
<div className="text-slate-800 text-[11px] font-extrabold mt-0.5">{details.provided_items}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex items-center space-x-2.5">
|
|
<div className="w-8 h-8 rounded-lg bg-amber-50 flex items-center justify-center text-amber-600 shrink-0">
|
|
<Clock className="w-4 h-4" />
|
|
</div>
|
|
<div>
|
|
<div className="text-[9px] text-slate-400 uppercase font-black tracking-widest">Event Timing</div>
|
|
<div className="text-slate-800 text-[11px] font-extrabold mt-0.5">
|
|
{details.event_date} • {details.event_time}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex items-center space-x-2.5 md:col-span-2 pt-2 border-t border-slate-100 mt-1">
|
|
<div className="w-8 h-8 rounded-lg bg-blue-50 flex items-center justify-center text-[#185FA5] shrink-0">
|
|
<MapPin className="w-4 h-4" />
|
|
</div>
|
|
<div className="flex-1 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2">
|
|
<div>
|
|
<div className="text-[9px] text-slate-400 uppercase font-black tracking-widest">Event Location Address</div>
|
|
<div className="text-slate-800 text-[11px] font-extrabold mt-0.5">{details.location_details}</div>
|
|
</div>
|
|
{details.location_pin && (
|
|
<a
|
|
href={details.location_pin}
|
|
target="_blank"
|
|
rel="noreferrer"
|
|
className="px-3.5 py-2 bg-rose-600 hover:bg-rose-700 text-white rounded-xl text-[10px] font-black uppercase tracking-wider flex items-center space-x-1 w-fit transition-colors shrink-0 shadow-sm"
|
|
>
|
|
<MapPin className="w-3.5 h-3.5" />
|
|
<span>View Map Location Pin</span>
|
|
</a>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
<div className="flex items-center space-x-3 md:border-l md:border-slate-50 md:pl-6 shrink-0 h-full self-center">
|
|
<button className="p-3 rounded-2xl bg-slate-50 text-slate-400 hover:text-rose-600 transition-all">
|
|
<ChevronRight className="w-5 h-5" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
})
|
|
)}
|
|
</div>
|
|
</div>
|
|
</EmployerLayout>
|
|
);
|
|
}
|