diff --git a/src/components/dashboard/Officer_EventRequestForm/UserEventRequests.tsx b/src/components/dashboard/Officer_EventRequestForm/UserEventRequests.tsx index 1ff40c4..9509d73 100644 --- a/src/components/dashboard/Officer_EventRequestForm/UserEventRequests.tsx +++ b/src/components/dashboard/Officer_EventRequestForm/UserEventRequests.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from 'react'; -import { motion } from 'framer-motion'; +import { motion, AnimatePresence } from 'framer-motion'; import { Get } from '../../../scripts/pocketbase/Get'; import { Authentication } from '../../../scripts/pocketbase/Authentication'; import toast from 'react-hot-toast'; @@ -40,6 +40,7 @@ const UserEventRequests: React.FC = ({ eventRequests: in 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 () => { @@ -131,25 +132,39 @@ const UserEventRequests: React.FC = ({ eventRequests: in 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.

- -
+ +
+ + + +

No Event Requests Found

+

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

+ +
+
); } @@ -159,103 +174,212 @@ const UserEventRequests: React.FC = ({ eventRequests: in animate={{ opacity: 1 }} className="space-y-6" > -
+

Your Submissions

- + + +
+ +
-
- - - - - - - - - - - - - - - {eventRequests.map((request) => ( - - - - - - - - - - - ))} - -
Event NameDateLocationPR MaterialsAS FundingSubmittedStatusActions
{request.name}{formatDate(request.start_date_time)}{request.location} - {request.flyers_needed ? ( - Yes - ) : ( - No - )} - - {request.as_funding_required ? ( - Yes - ) : ( - No - )} - {formatDate(request.created)} - + {viewMode === 'table' ? ( +
+ + + + + + + + + + + + + + + {eventRequests.map((request) => ( + + + + + + + + + + + ))} + +
Event NameDateLocationPR MaterialsAS FundingSubmittedStatusActions
{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.
  • +
    +

    + + + + 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 && ( -
    + + {isModalOpen && selectedRequest && ( -
    -
    -

    {selectedRequest.name}

    + 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 && ( +
    +
    +
    +

    + + + + Event Details +

    +
    -

    Vendor

    +

    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.invoice_data.vendor || 'Not specified'} + {selectedRequest.flyer_type?.join(', ') || 'Not specified'} + {selectedRequest.other_flyer_type && ` (${selectedRequest.other_flyer_type})`}

    - )} -
    -

    Itemized Invoice

    - {(() => { - try { - let invoiceData: any = null; +
    +

    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'} +

    +
    +
    +
    + )} - // 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'}
    -                                                                
    - ); + {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; } - } 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; + // 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' + // 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 && ( + + + + + )} + + + + + +
    ItemQtyPriceTotal
    {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; - 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 && ( - - - - - )} - - - - - -
    ItemQtyPriceTotal
    {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} + return ( +
    +
    + Total Amount: + ${!isNaN(total) ? total.toFixed(2) : '0.00'}
    - )} -
    - ); - } 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} +
    + )}
    - {invoiceData.vendor && ( -
    - Vendor: {invoiceData.vendor} -
    - )} -
    - ); - } else { - // Fallback to display the JSON in a readable format + ); + } 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 (
    -                                                                {typeof selectedRequest.itemized_invoice === 'object'
    -                                                                    ? JSON.stringify(selectedRequest.itemized_invoice, null, 2)
    -                                                                    : (selectedRequest.itemized_invoice || 'Not provided')}
    +                                                                Error displaying invoice. Please check the console for details.
                                                                 
    ); } - } 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'} +
    - )} - -
    -
    -
    -

    Submission Date

    -

    {formatDate(selectedRequest.created)}

    -
    -
    -

    Status

    - - {selectedRequest.status || 'Pending'} - -
    -
    -
    + -
    - )} + )} + ); };