import React, { useState, useEffect } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { Get } from '../../../scripts/pocketbase/Get'; import { Authentication } from '../../../scripts/pocketbase/Authentication'; import toast from 'react-hot-toast'; // Define the event request interface interface EventRequest { id: string; name: string; location: string; start_date_time: string; end_date_time: string; event_description: string; flyers_needed: boolean; photography_needed: boolean; as_funding_required: boolean; food_drinks_being_served: boolean; created: string; updated: string; status?: string; // Status might not be in the schema yet flyer_type?: string[]; other_flyer_type?: string; flyer_advertising_start_date?: string; flyer_additional_requests?: string; required_logos?: string[]; advertising_format?: string; will_or_have_room_booking?: boolean; expected_attendance?: number; itemized_invoice?: string; invoice_data?: any; } interface UserEventRequestsProps { eventRequests: EventRequest[]; } const UserEventRequests: React.FC = ({ eventRequests: initialEventRequests }) => { const [eventRequests, setEventRequests] = useState(initialEventRequests); const [selectedRequest, setSelectedRequest] = useState(null); const [isModalOpen, setIsModalOpen] = useState(false); const [isRefreshing, setIsRefreshing] = useState(false); const [viewMode, setViewMode] = useState<'table' | 'cards'>('table'); // Refresh event requests const refreshEventRequests = async () => { setIsRefreshing(true); const refreshToast = toast.loading('Refreshing submissions...'); try { const get = Get.getInstance(); const auth = Authentication.getInstance(); if (!auth.isAuthenticated()) { toast.error('You must be logged in to refresh submissions', { id: refreshToast }); return; } const userId = auth.getUserId(); if (!userId) { toast.error('User ID not found', { id: refreshToast }); return; } const updatedRequests = await get.getAll( 'event_request', `requested_user="${userId}"`, '-created' ); setEventRequests(updatedRequests); toast.success('Submissions refreshed successfully', { id: refreshToast }); } catch (err) { console.error('Failed to refresh event requests:', err); toast.error('Failed to refresh submissions. Please try again.', { id: refreshToast }); } finally { setIsRefreshing(false); } }; // Auto refresh on component mount useEffect(() => { refreshEventRequests(); }, []); // Format date for display const formatDate = (dateString: string) => { if (!dateString) return 'Not specified'; try { const date = new Date(dateString); return date.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }); } catch (e) { return dateString; } }; // Get status badge class based on status const getStatusBadge = (status?: string) => { if (!status) return 'badge-warning'; switch (status.toLowerCase()) { case 'approved': return 'badge-success'; case 'rejected': return 'badge-error'; case 'pending': return 'badge-warning'; case 'in progress': return 'badge-info'; default: return 'badge-warning'; } }; // Open modal with event request details const openDetailModal = (request: EventRequest) => { setSelectedRequest(request); setIsModalOpen(true); }; // Close modal const closeModal = () => { setIsModalOpen(false); setSelectedRequest(null); }; if (eventRequests.length === 0) { return (

No Event Requests Found

You haven't submitted any event requests yet. Use the form above to submit a new event request.

); } return (

Your Submissions

{viewMode === 'table' ? (
{eventRequests.map((request) => ( ))}
Event Name Date Location PR Materials AS Funding Submitted Status Actions
{request.name} {formatDate(request.start_date_time)} {request.location} {request.flyers_needed ? ( Yes ) : ( No )} {request.as_funding_required ? ( Yes ) : ( No )} {formatDate(request.created)} {request.status || 'Pending'}
) : (
{eventRequests.map((request) => (

{request.name}

{request.status || 'Pending'}
{formatDate(request.start_date_time)}
{request.location}
{request.flyers_needed && ( PR Materials )} {request.as_funding_required && ( AS Funding )} {request.photography_needed && ( Photography )}
))}
)}

About Your Submissions

  • Event requests are typically reviewed within 1-2 business days.
  • You'll receive email notifications when your request status changes.
  • For urgent inquiries, please contact the PR team or coordinators in the #-events Slack channel.
{/* Event Request Detail Modal */} {isModalOpen && selectedRequest && ( e.stopPropagation()} >

{selectedRequest.name}

Event Details

Event Name

{selectedRequest.name}

Location

{selectedRequest.location}

Start Date & Time

{formatDate(selectedRequest.start_date_time)}

End Date & Time

{formatDate(selectedRequest.end_date_time)}

Room Booking

{selectedRequest.will_or_have_room_booking ? 'Yes' : 'No'}

Expected Attendance

{selectedRequest.expected_attendance || 'Not specified'}

Event Description

{selectedRequest.event_description}

{selectedRequest.flyers_needed && (

PR Materials

Flyer Types

{selectedRequest.flyer_type?.join(', ') || 'Not specified'} {selectedRequest.other_flyer_type && ` (${selectedRequest.other_flyer_type})`}

Advertising Start Date

{selectedRequest.flyer_advertising_start_date ? formatDate(selectedRequest.flyer_advertising_start_date) : 'Not specified'}

Required Logos

{selectedRequest.required_logos?.join(', ') || 'None'}

Advertising Format

{selectedRequest.advertising_format || 'Not specified'}

Additional Requests

{selectedRequest.flyer_additional_requests || 'None'}

)} {selectedRequest.as_funding_required && (

AS Funding Details

Food/Drinks Being Served

{selectedRequest.food_drinks_being_served ? 'Yes' : 'No'}

{selectedRequest.invoice_data && (

Vendor

{selectedRequest.invoice_data.vendor || 'Not specified'}

)}

Itemized Invoice

{(() => { try { let invoiceData: any = null; // Parse the invoice data if it's a string, or use it directly if it's an object if (typeof selectedRequest.itemized_invoice === 'string') { try { invoiceData = JSON.parse(selectedRequest.itemized_invoice); } catch (e) { console.error('Failed to parse invoice JSON:', e); return (
                                                                        {selectedRequest.itemized_invoice || 'Not provided'}
                                                                    
); } } else if (typeof selectedRequest.itemized_invoice === 'object') { invoiceData = selectedRequest.itemized_invoice; } // If we have valid invoice data with items if (invoiceData && Array.isArray(invoiceData.items) && invoiceData.items.length > 0) { // Calculate total from items if not provided or if NaN let calculatedTotal = 0; // Try to use the provided total first if (invoiceData.total !== undefined) { const parsedTotal = typeof invoiceData.total === 'string' ? parseFloat(invoiceData.total) : invoiceData.total; if (!isNaN(parsedTotal)) { calculatedTotal = parsedTotal; } } // If total is NaN or not provided, calculate from items if (calculatedTotal === 0 || isNaN(calculatedTotal)) { calculatedTotal = invoiceData.items.reduce((sum: number, item: any) => { const quantity = typeof item.quantity === 'string' ? parseFloat(item.quantity) : (item.quantity || 1); const unitPrice = typeof item.unit_price === 'string' ? parseFloat(item.unit_price) : (item.unit_price || 0); const itemTotal = !isNaN(quantity) && !isNaN(unitPrice) ? quantity * unitPrice : 0; return sum + itemTotal; }, 0); // Add tax and tip if available if (invoiceData.tax && !isNaN(parseFloat(invoiceData.tax))) { calculatedTotal += parseFloat(invoiceData.tax); } if (invoiceData.tip && !isNaN(parseFloat(invoiceData.tip))) { calculatedTotal += parseFloat(invoiceData.tip); } } return (
{invoiceData.items.map((item: any, index: number) => { const quantity = typeof item.quantity === 'string' ? parseFloat(item.quantity) : (item.quantity || 1); const unitPrice = typeof item.unit_price === 'string' ? parseFloat(item.unit_price) : (item.unit_price || 0); const itemTotal = !isNaN(quantity) && !isNaN(unitPrice) ? quantity * unitPrice : 0; return ( ); })} {invoiceData.tax !== undefined && ( )} {invoiceData.tip !== undefined && ( )}
Item Qty Price Total
{item.item || 'Unnamed item'} {!isNaN(quantity) ? quantity : 1} ${!isNaN(unitPrice) ? unitPrice.toFixed(2) : '0.00'} ${!isNaN(itemTotal) ? itemTotal.toFixed(2) : '0.00'}
Tax: ${typeof invoiceData.tax === 'string' ? (parseFloat(invoiceData.tax) || 0).toFixed(2) : (invoiceData.tax || 0).toFixed(2)}
Tip: ${typeof invoiceData.tip === 'string' ? (parseFloat(invoiceData.tip) || 0).toFixed(2) : (invoiceData.tip || 0).toFixed(2)}
Total: ${!isNaN(calculatedTotal) ? calculatedTotal.toFixed(2) : '0.00'}
{invoiceData.vendor && (
Vendor: {invoiceData.vendor}
)}
); } else if (invoiceData && typeof invoiceData.total !== 'undefined') { // If we have a total but no items, show a simplified view const total = typeof invoiceData.total === 'string' ? parseFloat(invoiceData.total) : invoiceData.total; return (
Total Amount: ${!isNaN(total) ? total.toFixed(2) : '0.00'}
{invoiceData.vendor && (
Vendor: {invoiceData.vendor}
)}
); } else { // Fallback to display the JSON in a readable format return (
                                                                    {typeof selectedRequest.itemized_invoice === 'object'
                                                                        ? JSON.stringify(selectedRequest.itemized_invoice, null, 2)
                                                                        : (selectedRequest.itemized_invoice || 'Not provided')}
                                                                
); } } catch (error) { console.error('Error rendering invoice:', error); return (
                                                                Error displaying invoice. Please check the console for details.
                                                            
); } })()}
)}

Submission Date

{formatDate(selectedRequest.created)}

Status:

{selectedRequest.status || 'Pending'}
)}
); }; export default UserEventRequests;