Files
Event-Management-System/RIT-EVENT-MANAGEMENT--main/components/CreateSpecialEventsView.tsx

285 lines
13 KiB
TypeScript

import React, { useState, useEffect, useCallback } from 'react';
import { supabase } from '../supabase';
import { SpecialEvent } from '../types';
interface CreateSpecialEventsViewProps {
onShowToast: (msg: string, type: 'success' | 'delete') => void;
}
const CreateSpecialEventsView: React.FC<CreateSpecialEventsViewProps> = ({ onShowToast }) => {
const [specialEvents, setSpecialEvents] = useState<SpecialEvent[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [isSubmitting, setIsSubmitting] = useState(false);
const [editingEvent, setEditingEvent] = useState<SpecialEvent | null>(null);
const [formData, setFormData] = useState({
title: '',
description: '',
link: ''
});
const fetchSpecialEvents = useCallback(async () => {
setIsLoading(true);
const { data, error } = await supabase
.from('special_events')
.select('*')
.order('created_at', { ascending: false });
if (!error && data) {
setSpecialEvents(data);
}
setIsLoading(false);
}, []);
useEffect(() => {
fetchSpecialEvents();
}, [fetchSpecialEvents]);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setIsSubmitting(true);
try {
const { data: { user } } = await supabase.auth.getUser();
if (!user) throw new Error("User not authenticated");
if (editingEvent) {
const { error } = await supabase
.from('special_events')
.update({
title: formData.title,
description: formData.description,
link: formData.link
})
.eq('id', editingEvent.id);
if (error) throw error;
onShowToast("Session updated! Awaiting Review.", "success");
} else {
const { error } = await supabase
.from('special_events')
.insert({
title: formData.title,
description: formData.description,
link: formData.link,
created_by: user.id,
verification_status: 'PENDING'
});
if (error) throw error;
onShowToast("Session Broadcasted! Security check initiated.", "success");
}
setFormData({ title: '', description: '', link: '' });
setEditingEvent(null);
fetchSpecialEvents();
} catch (err: any) {
console.error("Error saving special event:", err);
alert(`Error: ${err.message}`);
} finally {
setIsSubmitting(false);
}
};
const handleEdit = (event: SpecialEvent) => {
setEditingEvent(event);
setFormData({
title: event.title,
description: event.description || '',
link: event.link
});
// Scroll to form
window.scrollTo({ top: 0, behavior: 'smooth' });
};
const handleDelete = async (id: string) => {
if (!confirm("Are you sure you want to delete this special event?")) return;
try {
const { error } = await supabase
.from('special_events')
.delete()
.eq('id', id);
if (error) throw error;
onShowToast("Special event deleted successfully!", "delete");
fetchSpecialEvents();
} catch (err: any) {
console.error("Error deleting special event:", err);
alert(`Error: ${err.message}`);
}
};
return (
<div className="max-w-7xl mx-auto px-4 md:px-10 py-10 animate-in fade-in duration-700">
<div className="grid grid-cols-1 lg:grid-cols-3 gap-12">
{/* Creation Form */}
<div className="lg:col-span-1">
<div className="bg-white border border-slate-200 rounded-[2.5rem] p-10 shadow-xl sticky top-32">
<h2 className="text-3xl font-black text-slate-900 tracking-tighter uppercase mb-2">
{editingEvent ? 'Edit Portal' : 'Create Portal'}
</h2>
<p className="text-[#004a99] font-bold text-[8px] tracking-[0.4em] uppercase mb-10">
External Link Broadcaster
</p>
<form onSubmit={handleSubmit} className="space-y-6">
<div>
<label className="block text-[9px] font-black text-slate-500 uppercase tracking-[0.2em] mb-3">Event Title</label>
<input
required
type="text"
placeholder="e.g. Google Cloud Workshop"
className="w-full bg-slate-50 border border-slate-200 rounded-xl px-6 py-4 text-slate-900 focus:ring-1 focus:ring-[#004a99] outline-none font-bold placeholder:text-slate-400 transition-all"
value={formData.title}
onChange={e => setFormData({ ...formData, title: e.target.value })}
/>
</div>
<div>
<label className="block text-[9px] font-black text-slate-500 uppercase tracking-[0.2em] mb-3">External Link</label>
<input
required
type="url"
placeholder="https://..."
className="w-full bg-slate-50 border border-slate-200 rounded-xl px-6 py-4 text-slate-900 focus:ring-1 focus:ring-[#004a99] outline-none font-bold placeholder:text-slate-400 transition-all"
value={formData.link}
onChange={e => setFormData({ ...formData, link: e.target.value })}
/>
</div>
<div>
<label className="block text-[9px] font-black text-slate-500 uppercase tracking-[0.2em] mb-3">Description</label>
<textarea
required
placeholder="What is this event about?"
className="w-full bg-slate-50 border border-slate-200 rounded-2xl px-6 py-4 text-slate-900 focus:ring-1 focus:ring-[#004a99] outline-none font-bold placeholder:text-slate-400 transition-all min-h-[120px] resize-none"
value={formData.description}
onChange={e => setFormData({ ...formData, description: e.target.value })}
/>
</div>
<div className="flex gap-4 pt-4">
{editingEvent && (
<button
type="button"
onClick={() => {
setEditingEvent(null);
setFormData({ title: '', description: '', link: '' });
}}
className="flex-1 py-4 bg-slate-100 text-slate-600 font-black uppercase tracking-widest text-[10px] rounded-2xl hover:bg-slate-200 transition-all"
>
Cancel
</button>
)}
<button
type="submit"
disabled={isSubmitting}
className="flex-[2] py-4 bg-[#004a99] text-white font-black uppercase tracking-widest text-[10px] rounded-2xl hover:bg-blue-800 transition-all shadow-lg active:scale-95 disabled:opacity-50"
>
{isSubmitting ? 'Syncing...' : editingEvent ? 'Update Link' : 'Generate Link'}
</button>
</div>
</form>
</div>
</div>
{/* List of Special Events */}
<div className="lg:col-span-2">
<div className="flex items-end justify-between mb-12 border-b border-slate-200 pb-8">
<div>
<h2 className="text-5xl font-black text-slate-900 tracking-tighter uppercase mb-2">Active Portals</h2>
<p className="text-[#004a99] font-bold text-xs tracking-[0.4em] uppercase flex items-center gap-3">
<span className="w-1.5 h-1.5 bg-[#004a99] rounded-full"></span>
External Event Hub
</p>
</div>
<div className="text-right">
<span className="text-[32px] font-black text-slate-900">{specialEvents.length}</span>
<p className="text-[9px] font-black text-slate-400 uppercase tracking-widest">Global Links</p>
</div>
</div>
<div className="space-y-6">
{isLoading ? (
<div className="py-20 flex flex-col items-center justify-center">
<div className="w-10 h-10 border-4 border-slate-200 border-t-[#004a99] rounded-full animate-spin"></div>
</div>
) : specialEvents.length > 0 ? (
specialEvents.map((event) => (
<div key={event.id} className="bg-white border border-slate-100 rounded-[2.5rem] p-10 shadow-sm hover:shadow-2xl hover:shadow-slate-200 transition-all group flex flex-col md:flex-row md:items-center gap-10 border-l-8 border-l-[#004a99] relative overflow-hidden">
<div className="absolute -top-10 -right-10 w-40 h-40 bg-[#004a99]/5 rounded-full blur-3xl group-hover:bg-[#004a99]/10 transition-colors duration-1000"></div>
<div className="flex-1 relative z-10">
<div className="flex flex-wrap items-center gap-4 mb-6">
<div className="flex items-center gap-3">
{event.verification_status === 'APPROVED' ? (
<div className="flex items-center gap-2">
<span className="w-2 h-2 rounded-full bg-emerald-500 shadow-[0_0_8px_rgba(16,185,129,0.5)]"></span>
<span className="text-[9px] font-black text-slate-400 uppercase tracking-widest leading-none">Broadcast Active</span>
</div>
) : event.verification_status === 'REJECTED' ? (
<div className="flex items-center gap-2">
<span className="w-2 h-2 rounded-full bg-rose-500"></span>
<span className="text-[9px] font-black text-rose-400 uppercase tracking-widest leading-none">Rejected</span>
</div>
) : (
<div className="flex items-center gap-2">
<span className="w-2 h-2 rounded-full bg-amber-500 animate-pulse"></span>
<span className="text-[9px] font-black text-amber-500 uppercase tracking-widest leading-none">Security Review Queue</span>
</div>
)}
</div>
<span className="w-1 h-1 bg-slate-200 rounded-full"></span>
<span className="text-[8px] font-black text-slate-300 uppercase tracking-[0.3em] font-inter">Global ID: {event.id.slice(0, 8)}</span>
</div>
<h3 className="text-3xl font-black text-slate-900 mb-3 group-hover:text-[#004a99] transition-colors tracking-tight uppercase leading-none">{event.title}</h3>
<p className="text-blue-500 font-bold text-[10px] mb-4 truncate max-w-md">{event.link}</p>
<p className="text-slate-500 text-sm font-medium line-clamp-2 italic">{event.description}</p>
</div>
<div className="flex gap-3">
<button
onClick={() => handleEdit(event)}
className="w-12 h-12 bg-blue-50 text-[#004a99] rounded-2xl flex items-center justify-center hover:bg-[#004a99] hover:text-white transition-all active:scale-90 shadow-sm"
title="Edit Portal"
>
<i className="fas fa-edit text-sm"></i>
</button>
<button
onClick={() => handleDelete(event.id)}
className="w-12 h-12 bg-rose-50 text-rose-500 rounded-2xl flex items-center justify-center hover:bg-rose-500 hover:text-white transition-all active:scale-90 shadow-sm"
title="Delete Portal"
>
<i className="fas fa-trash-alt text-sm"></i>
</button>
<a
href={event.link}
target="_blank"
rel="noopener noreferrer"
className="w-12 h-12 bg-slate-900 text-white rounded-2xl flex items-center justify-center hover:bg-black transition-all active:scale-90 shadow-lg shadow-slate-900/20"
title="Visit Link"
>
<i className="fas fa-external-link-alt text-sm"></i>
</a>
</div>
</div>
))
) : (
<div className="py-20 text-center bg-slate-50 border border-dashed border-slate-300 rounded-[2rem]">
<i className="fas fa-link text-4xl text-slate-300 mb-6"></i>
<p className="text-slate-400 font-black uppercase tracking-widest text-xs">No special events found</p>
<p className="text-slate-300 font-bold text-[9px] uppercase tracking-widest mt-2">Start by creating your first global portal</p>
</div>
)}
</div>
</div>
</div>
</div>
);
};
export default CreateSpecialEventsView;