diff --git a/src/components/dashboard/Officer_EventRequestForm/ASFundingSection.tsx b/src/components/dashboard/Officer_EventRequestForm/ASFundingSection.tsx index e762149..1ae2641 100644 --- a/src/components/dashboard/Officer_EventRequestForm/ASFundingSection.tsx +++ b/src/components/dashboard/Officer_EventRequestForm/ASFundingSection.tsx @@ -217,26 +217,14 @@ const ASFundingSection: React.FC = ({ formData, onDataCha } }; - // Handle invoice data change + // Handle invoice data change from the invoice builder const handleInvoiceDataChange = (data: InvoiceData) => { - // Create itemized invoice string for Pocketbase - const itemizedInvoice = JSON.stringify({ - vendor: data.vendor, - items: data.items.map((item: InvoiceItem) => ({ - item: item.description, - quantity: item.quantity, - unit_price: item.unitPrice, - amount: item.amount - })), - subtotal: data.subtotal, - tax: data.taxAmount, - tip: data.tipAmount, - total: data.total - }, null, 2); + // Calculate if budget exceeds maximum allowed + const maxBudget = Math.min(formData.expected_attendance * 10, 5000); onDataChange({ invoiceData: data, - itemized_invoice: itemizedInvoice + itemized_invoice: JSON.stringify(data) }); }; @@ -251,18 +239,15 @@ const ASFundingSection: React.FC = ({ formData, onDataCha

AS Funding Details

-

- Please provide the necessary information for your Associated Students funding request. -

@@ -407,18 +392,15 @@ const ASFundingSection: React.FC = ({ formData, onDataCha ) : ( = ({ formData, onD {/* Date and Time Section */} {/* Event Start Date */} = ({ formData, onD whileHover={{ y: -2 }} > = ({ formData, onD whileHover="hover" variants={inputHoverVariants} /> +

+ Note: For multi-day events, please submit a separate request for each day. +

+

+ The event time should not include setup time. +

- {/* Event End Date */} + {/* Event End Time */} - onDataChange({ end_date_time: e.target.value })} - required - whileHover="hover" - variants={inputHoverVariants} - /> +
+ { + if (formData.start_date_time) { + // Create a new date object from start_date_time + const startDate = new Date(formData.start_date_time); + // Parse the time value + const [hours, minutes] = e.target.value.split(':').map(Number); + // Set the hours and minutes on the date + startDate.setHours(hours, minutes); + // Update end_date_time with the new time but same date as start + onDataChange({ end_date_time: startDate.toISOString() }); + } + }} + required + whileHover="hover" + variants={inputHoverVariants} + /> +

+ The end time will use the same date as the start date. +

+
@@ -202,7 +224,7 @@ const EventDetailsSection: React.FC = ({ formData, onD onChange={() => onDataChange({ will_or_have_room_booking: true })} required /> - Yes, I have/will have a booking + Yes, I have a room booking = ({ formData, onD type="radio" className="radio radio-primary" checked={formData.will_or_have_room_booking === false} - onChange={() => onDataChange({ will_or_have_room_booking: false })} + onChange={() => { + onDataChange({ will_or_have_room_booking: false }); + }} required /> No, I don't need a booking + + {formData.will_or_have_room_booking === false && ( + + + + )}
); diff --git a/src/components/dashboard/Officer_EventRequestForm/EventRequestForm.tsx b/src/components/dashboard/Officer_EventRequestForm/EventRequestForm.tsx index 9aaaf42..c74cb80 100644 --- a/src/components/dashboard/Officer_EventRequestForm/EventRequestForm.tsx +++ b/src/components/dashboard/Officer_EventRequestForm/EventRequestForm.tsx @@ -13,7 +13,7 @@ import PRSection from './PRSection'; import EventDetailsSection from './EventDetailsSection'; import TAPFormSection from './TAPFormSection'; import ASFundingSection from './ASFundingSection'; -import EventRequestFormPreview from './EventRequestFormPreview'; +import { EventRequestFormPreview } from './EventRequestFormPreview'; import type { InvoiceData, InvoiceItem } from './InvoiceBuilder'; // Animation variants @@ -119,9 +119,7 @@ const EventRequestForm: React.FC = () => { invoiceData: { items: [], subtotal: 0, - taxRate: 7.75, // Default tax rate for San Diego taxAmount: 0, - tipPercentage: 15, // Default tip percentage tipAmount: 0, total: 0, vendor: '' @@ -204,7 +202,7 @@ const EventRequestForm: React.FC = () => { advertising_format: '', will_or_have_room_booking: false, expected_attendance: 0, - room_booking: null, + room_booking: null, // No room booking by default as_funding_required: false, food_drinks_being_served: false, itemized_invoice: '', @@ -215,9 +213,7 @@ const EventRequestForm: React.FC = () => { invoiceData: { items: [], subtotal: 0, - taxRate: 7.75, // Default tax rate for San Diego taxAmount: 0, - tipPercentage: 15, // Default tip percentage tipAmount: 0, total: 0, vendor: '' @@ -272,13 +268,12 @@ const EventRequestForm: React.FC = () => { name: formData.name, location: formData.location, start_date_time: new Date(formData.start_date_time).toISOString(), - end_date_time: new Date(formData.end_date_time).toISOString(), + end_date_time: formData.end_date_time ? new Date(formData.end_date_time).toISOString() : new Date(formData.start_date_time).toISOString(), event_description: formData.event_description, flyers_needed: formData.flyers_needed, photography_needed: formData.photography_needed, as_funding_required: formData.needs_as_funding, food_drinks_being_served: formData.food_drinks_being_served, - // Store the itemized_invoice as a string for backward compatibility itemized_invoice: formData.itemized_invoice, flyer_type: formData.flyer_type, other_flyer_type: formData.other_flyer_type, @@ -288,23 +283,19 @@ const EventRequestForm: React.FC = () => { advertising_format: formData.advertising_format, will_or_have_room_booking: formData.will_or_have_room_booking, expected_attendance: formData.expected_attendance, - // Add these fields explicitly to match the schema needs_graphics: formData.needs_graphics, needs_as_funding: formData.needs_as_funding, - // Store the invoice data as a properly formatted JSON object invoice_data: { items: formData.invoiceData.items.map(item => ({ item: item.description, quantity: item.quantity, unit_price: item.unitPrice })), - tax: formData.invoiceData.taxAmount, - tip: formData.invoiceData.tipAmount, + taxAmount: formData.invoiceData.taxAmount, + tipAmount: formData.invoiceData.tipAmount, total: formData.invoiceData.total, vendor: formData.invoiceData.vendor }, - // Set the initial status to "submitted" - status: EventRequestStatus.SUBMITTED, }; // Create the record using the Update service @@ -400,37 +391,45 @@ const EventRequestForm: React.FC = () => { // Validate Event Details Section const validateEventDetailsSection = () => { - if (!formData.name) { - toast.error('Please enter an event name'); - return false; + let valid = true; + const errors: string[] = []; + + if (!formData.name || formData.name.trim() === '') { + errors.push('Event name is required'); + valid = false; } - if (!formData.event_description) { - toast.error('Please enter an event description'); - return false; + if (!formData.event_description || formData.event_description.trim() === '') { + errors.push('Event description is required'); + valid = false; } - if (!formData.start_date_time) { - toast.error('Please enter a start date and time'); - return false; + if (!formData.start_date_time || formData.start_date_time.trim() === '') { + errors.push('Event start date and time is required'); + valid = false; } if (!formData.end_date_time) { - toast.error('Please enter an end date and time'); + errors.push('Event end time is required'); + valid = false; + } + + if (!formData.location || formData.location.trim() === '') { + errors.push('Event location is required'); + valid = false; + } + + if (formData.will_or_have_room_booking === undefined) { + errors.push('Room booking status is required'); + valid = false; + } + + if (errors.length > 0) { + setError(errors[0]); return false; } - if (!formData.location) { - toast.error('Please enter an event location'); - return false; - } - - if (formData.will_or_have_room_booking === null || formData.will_or_have_room_booking === undefined) { - toast.error('Please specify if you have a room booking'); - return false; - } - - return true; + return valid; }; // Validate TAP Form Section @@ -446,6 +445,7 @@ const EventRequestForm: React.FC = () => { return false; } + // Only require room booking file if will_or_have_room_booking is true if (formData.will_or_have_room_booking && !formData.room_booking) { toast.error('Please upload your room booking confirmation'); return false; @@ -467,17 +467,22 @@ const EventRequestForm: React.FC = () => { // Validate AS Funding Section const validateASFundingSection = () => { - if (formData.needs_as_funding) { - // Check if vendor is provided - if (!formData.invoiceData.vendor) { - toast.error('Please enter the vendor/restaurant name'); + if (formData.as_funding_required) { + // Check if invoice data is present and has items + if (!formData.invoiceData || !formData.invoiceData.items || formData.invoiceData.items.length === 0) { + setError('Please add at least one item to your invoice'); return false; } - // No longer require items in the invoice - // Check if at least one invoice file is uploaded - if (!formData.invoice && (!formData.invoice_files || formData.invoice_files.length === 0)) { - toast.error('Please upload at least one invoice file'); + // Calculate the total budget from invoice items + const totalBudget = formData.invoiceData.items.reduce( + (sum, item) => sum + (item.unitPrice * item.quantity), 0 + ); + + // Check if the budget exceeds the maximum allowed ($5000 cap regardless of attendance) + const maxBudget = Math.min(formData.expected_attendance * 10, 5000); + if (totalBudget > maxBudget) { + setError(`Your budget (${totalBudget.toFixed(2)} dollars) exceeds the maximum allowed (${maxBudget} dollars). The absolute maximum is $5,000.`); return false; } } @@ -487,8 +492,11 @@ const EventRequestForm: React.FC = () => { // Validate all sections before submission const validateAllSections = () => { - // Validate Event Details + // We no longer forcibly set end_date_time to match start_date_time + // The end time is now configured separately with the same date + if (!validateEventDetailsSection()) { + setCurrentStep(1); return false; } @@ -579,6 +587,14 @@ const EventRequestForm: React.FC = () => { variants={containerVariants} className="space-y-6" > + +

Event Request Form

diff --git a/src/components/dashboard/Officer_EventRequestForm/EventRequestFormPreview.tsx b/src/components/dashboard/Officer_EventRequestForm/EventRequestFormPreview.tsx index f65ca15..70a5861 100644 --- a/src/components/dashboard/Officer_EventRequestForm/EventRequestFormPreview.tsx +++ b/src/components/dashboard/Officer_EventRequestForm/EventRequestFormPreview.tsx @@ -65,6 +65,20 @@ const modalVariants = { } }; +// Extended version of InvoiceItem to handle multiple property names +interface ExtendedInvoiceItem { + id?: string; + description?: string; + item?: string; + name?: string; + quantity: number; + unitPrice?: number; + unit_price?: number; + price?: number; + amount?: number; + [key: string]: any; // Allow any additional properties +} + // Helper function to normalize EventRequest to match EventRequestFormData structure const normalizeFormData = (data: EventRequestFormData | (EventRequest & { invoiceData?: any; @@ -108,7 +122,26 @@ const normalizeFormData = (data: EventRequestFormData | (EventRequest & { ...invoiceData, ...(parsed as any), items: Array.isArray((parsed as any).items) ? (parsed as any).items : [], + // Normalize tax/tip fields + taxAmount: parseFloat(parsed.taxAmount || parsed.tax || 0), + tipAmount: parseFloat(parsed.tipAmount || parsed.tip || 0) }; + + // Normalize item property names + invoiceData.items = invoiceData.items.map(item => { + // Create a normalized item with all possible property names + return { + id: item.id || `item-${Math.random().toString(36).substr(2, 9)}`, + description: item.description || item.item || item.name || 'Item', + quantity: parseFloat(item.quantity) || 1, + unitPrice: parseFloat(item.unitPrice || item.unit_price || item.price || 0), + unit_price: parseFloat(item.unitPrice || item.unit_price || item.price || 0), + price: parseFloat(item.unitPrice || item.unit_price || item.price || 0), + amount: parseFloat(item.amount) || + (parseFloat(item.quantity) || 1) * + parseFloat(item.unitPrice || item.unit_price || item.price || 0) + }; + }); } } catch (e) { console.error('Error parsing itemized_invoice:', e); @@ -119,7 +152,25 @@ const normalizeFormData = (data: EventRequestFormData | (EventRequest & { ...invoiceData, ...parsed, items: Array.isArray(parsed.items) ? parsed.items : [], + // Normalize tax/tip fields + taxAmount: parseFloat(parsed.taxAmount || parsed.tax || 0), + tipAmount: parseFloat(parsed.tipAmount || parsed.tip || 0) }; + + // Normalize item property names + invoiceData.items = invoiceData.items.map(item => { + return { + id: item.id || `item-${Math.random().toString(36).substr(2, 9)}`, + description: item.description || item.item || item.name || 'Item', + quantity: parseFloat(item.quantity) || 1, + unitPrice: parseFloat(item.unitPrice || item.unit_price || item.price || 0), + unit_price: parseFloat(item.unitPrice || item.unit_price || item.price || 0), + price: parseFloat(item.unitPrice || item.unit_price || item.price || 0), + amount: parseFloat(item.amount) || + (parseFloat(item.quantity) || 1) * + parseFloat(item.unitPrice || item.unit_price || item.price || 0) + }; + }); } } else if (eventRequest.invoiceData) { const parsed = eventRequest.invoiceData as any; @@ -128,7 +179,25 @@ const normalizeFormData = (data: EventRequestFormData | (EventRequest & { ...invoiceData, ...parsed, items: Array.isArray(parsed.items) ? parsed.items : [], + // Normalize tax/tip fields + taxAmount: parseFloat(parsed.taxAmount || parsed.tax || 0), + tipAmount: parseFloat(parsed.tipAmount || parsed.tip || 0) }; + + // Normalize item property names + invoiceData.items = invoiceData.items.map(item => { + return { + id: item.id || `item-${Math.random().toString(36).substr(2, 9)}`, + description: item.description || item.item || item.name || 'Item', + quantity: parseFloat(item.quantity) || 1, + unitPrice: parseFloat(item.unitPrice || item.unit_price || item.price || 0), + unit_price: parseFloat(item.unitPrice || item.unit_price || item.price || 0), + price: parseFloat(item.unitPrice || item.unit_price || item.price || 0), + amount: parseFloat(item.amount) || + (parseFloat(item.quantity) || 1) * + parseFloat(item.unitPrice || item.unit_price || item.price || 0) + }; + }); } } @@ -288,7 +357,7 @@ interface EventRequestFormPreviewProps { }); // Accept both form data and event request types isOpen?: boolean; // Control whether the modal is open onClose?: () => void; // Callback when modal is closed - isModal?: boolean; // Whether to render as a modal or inline component + isModal: boolean; // Whether to render as a modal or inline component } // Define the main EventRequestFormPreview component @@ -495,22 +564,22 @@ const EventRequestFormPreview: React.FC = ({ Expected Attendance

{formData.expected_attendance || 'Not specified'}

+ {formData.expected_attendance > 0 && ( +

+ Budget limit: ${Math.min(formData.expected_attendance * 10, 5000)} (max $5,000) +

+ )}
- Start Date & Time + Date & Time

{formatDateTime(formData.start_date_time)}

-
- -
-
- - End Date & Time -
-

{formatDateTime(formData.end_date_time)}

+

+ Note: Multi-day events require separate submissions for each day. +

@@ -637,7 +706,7 @@ const EventRequestFormPreview: React.FC = ({
- {formData.will_or_have_room_booking ? 'Has/Will Have Booking' : 'No Booking Needed'} + {formData.will_or_have_room_booking ? 'Room Booking Confirmed' : 'No Booking Needed'} {formData.will_or_have_room_booking && formData.room_booking && ( @@ -690,12 +759,12 @@ const EventRequestFormPreview: React.FC = ({ - {formData.invoiceData.items.map((item: InvoiceItem, index: number) => ( + {formData.invoiceData.items.map((item: ExtendedInvoiceItem, index: number) => ( - {item.description || 'Item'} + {item.description || item.item || item.name || 'Item'} {item.quantity || 1} - ${(item.unitPrice || 0).toFixed(2)} - ${(item.amount || 0).toFixed(2)} + ${(item.unitPrice || item.unit_price || item.price || 0).toFixed(2)} + ${(item.amount || (item.quantity * (item.unitPrice || item.unit_price || item.price || 0)) || 0).toFixed(2)} ))} @@ -704,18 +773,14 @@ const EventRequestFormPreview: React.FC = ({ Subtotal: ${(formData.invoiceData.subtotal || 0).toFixed(2)} - {formData.invoiceData.taxAmount && formData.invoiceData.taxAmount > 0 && ( - - Tax: - ${(formData.invoiceData.taxAmount || 0).toFixed(2)} - - )} - {formData.invoiceData.tipAmount && formData.invoiceData.tipAmount > 0 && ( - - Tip: - ${(formData.invoiceData.tipAmount || 0).toFixed(2)} - - )} + + Tax: + ${(typeof formData.invoiceData.taxAmount === 'number' ? formData.invoiceData.taxAmount : 0).toFixed(2)} + + + Tip: + ${(typeof formData.invoiceData.tipAmount === 'number' ? formData.invoiceData.tipAmount : 0).toFixed(2)} + Total: ${(formData.invoiceData.total || 0).toFixed(2)} @@ -730,28 +795,7 @@ const EventRequestFormPreview: React.FC = ({ )} - {/* Submission Information */} - -
-

- - Ready to Submit -

- {formData.formReviewed && ( - Reviewed - )} -
- -
-

- Once submitted, you'll need to notify PR and/or Coordinators in the #-events Slack channel. -

-
-
); }; diff --git a/src/components/dashboard/Officer_EventRequestForm/InvoiceBuilder.tsx b/src/components/dashboard/Officer_EventRequestForm/InvoiceBuilder.tsx index bc88ae4..6e8c004 100644 --- a/src/components/dashboard/Officer_EventRequestForm/InvoiceBuilder.tsx +++ b/src/components/dashboard/Officer_EventRequestForm/InvoiceBuilder.tsx @@ -713,6 +713,17 @@ const InvoiceBuilder: React.FC = ({ invoiceData, onChange }
+ {/* Budget Warning */} + {total > 0 && ( + + )} + {/* Validation notice */} {invoiceData.items.length === 0 && ( = ({ invoiceData, onChange } className="mt-4" icon="heroicons:exclamation-triangle" /> + + {/* Summary Section */} + +
+ + + {/* Right Column: Summary */} +
+

Invoice Summary

+
+
+ Subtotal: + ${invoiceData.subtotal.toFixed(2)} +
+
+ Tax: + ${invoiceData.taxAmount.toFixed(2)} +
+
+ Tip: + ${invoiceData.tipAmount.toFixed(2)} +
+
+
+ Total: + ${invoiceData.total.toFixed(2)} +
+
+ + +
+
+
); }; diff --git a/src/components/dashboard/Officer_EventRequestForm/TAPFormSection.tsx b/src/components/dashboard/Officer_EventRequestForm/TAPFormSection.tsx index 7d89501..040e418 100644 --- a/src/components/dashboard/Officer_EventRequestForm/TAPFormSection.tsx +++ b/src/components/dashboard/Officer_EventRequestForm/TAPFormSection.tsx @@ -1,8 +1,9 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { motion } from 'framer-motion'; import type { EventRequestFormData } from './EventRequestForm'; import type { EventRequest } from '../../../schemas/pocketbase'; import CustomAlert from '../universal/CustomAlert'; +import FilePreview from '../universal/FilePreview'; // Enhanced animation variants const containerVariants = { @@ -38,6 +39,19 @@ const inputHoverVariants = { } }; +// Add a new CSS class to hide the number input arrows +const hiddenNumberInputArrows = ` + /* Hide number input spinners */ + input[type=number]::-webkit-inner-spin-button, + input[type=number]::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; + } + input[type=number] { + -moz-appearance: textfield; + } +`; + // File upload animation const fileUploadVariants = { initial: { scale: 1 }, @@ -57,13 +71,42 @@ interface TAPFormSectionProps { const TAPFormSection: React.FC = ({ formData, onDataChange }) => { const [roomBookingFile, setRoomBookingFile] = useState(formData.room_booking); const [isDragging, setIsDragging] = useState(false); + const [fileError, setFileError] = useState(null); + const [showFilePreview, setShowFilePreview] = useState(false); + const [filePreviewUrl, setFilePreviewUrl] = useState(null); - // Handle room booking file upload + // Add style tag for hidden arrows + useEffect(() => { + const style = document.createElement('style'); + style.textContent = hiddenNumberInputArrows; + document.head.appendChild(style); + + return () => { + document.head.removeChild(style); + }; + }, []); + + // Handle room booking file upload with size limit const handleRoomBookingFileChange = (e: React.ChangeEvent) => { if (e.target.files && e.target.files.length > 0) { const file = e.target.files[0]; + + // Check file size - 1MB limit + if (file.size > 1024 * 1024) { + setFileError("Room booking file size must be under 1MB"); + return; + } + + setFileError(null); setRoomBookingFile(file); onDataChange({ room_booking: file }); + + // Create preview URL + if (filePreviewUrl) { + URL.revokeObjectURL(filePreviewUrl); + } + const url = URL.createObjectURL(file); + setFilePreviewUrl(url); } }; @@ -84,11 +127,40 @@ const TAPFormSection: React.FC = ({ formData, onDataChange if (e.dataTransfer.files && e.dataTransfer.files.length > 0) { const file = e.dataTransfer.files[0]; + + // Check file size - 1MB limit + if (file.size > 1024 * 1024) { + setFileError("Room booking file size must be under 1MB"); + return; + } + + setFileError(null); setRoomBookingFile(file); onDataChange({ room_booking: file }); + + // Create preview URL + if (filePreviewUrl) { + URL.revokeObjectURL(filePreviewUrl); + } + const url = URL.createObjectURL(file); + setFilePreviewUrl(url); } }; + // Function to toggle file preview + const toggleFilePreview = () => { + setShowFilePreview(!showFilePreview); + }; + + // Clean up object URL when component unmounts + useEffect(() => { + return () => { + if (filePreviewUrl) { + URL.revokeObjectURL(filePreviewUrl); + } + }; + }, [filePreviewUrl]); + return ( = ({ formData, onDataChange @@ -127,7 +199,11 @@ const TAPFormSection: React.FC = ({ formData, onDataChange type="number" className="input input-bordered focus:input-primary transition-all duration-300 w-full pr-20" value={formData.expected_attendance || ''} - onChange={(e) => onDataChange({ expected_attendance: parseInt(e.target.value) || 0 })} + onChange={(e) => { + // Allow any attendance number, no longer limiting to 500 + const attendance = parseInt(e.target.value) || 0; + onDataChange({ expected_attendance: attendance }); + }} min="0" placeholder="Enter expected attendance" required @@ -138,6 +214,30 @@ const TAPFormSection: React.FC = ({ formData, onDataChange people
+ {formData.expected_attendance > 0 && ( + +

+ Budget Calculator: $10 per person × {formData.expected_attendance} people +

+

+ {formData.expected_attendance * 10 <= 5000 ? ( + `You cannot exceed spending past $${formData.expected_attendance * 10} dollars.` + ) : ( + `You cannot exceed spending past $5,000 dollars.` + )} +

+ {formData.expected_attendance * 10 > 5000 && ( +

+ Budget cap reached. Maximum budget is $5,000 regardless of attendance. +

+ )} +
+ )} = ({ formData, onDataChange - {/* Room booking confirmation */} + {/* Room booking confirmation - Show file error if present */} = ({ formData, onDataChange > - document.getElementById('room-booking-file')?.click()} - > - - -
- - - - - - - {roomBookingFile ? ( - <> -

File selected:

-

{roomBookingFile.name}

-

Click or drag to replace

- - ) : ( - <> -

Drop your file here or click to browse

-

Accepted formats: PDF, PNG, JPG

- - )} + {fileError && ( +
+
- + )} + + {formData.will_or_have_room_booking ? ( + document.getElementById('room-booking-file')?.click()} + > + + +
+ + + + + + + {roomBookingFile ? ( + <> +

File selected:

+

{roomBookingFile.name}

+

Click or drag to replace (Max size: 1MB)

+ + ) : ( + <> +

Drop your file here or click to browse

+

Accepted formats: PDF, PNG, JPG (Max size: 1MB)

+ + )} +
+
+ ) : ( + +

Room booking upload not required when no booking is needed.

+
+ )} + + {/* Preview File Button - Outside the upload area */} + {formData.will_or_have_room_booking && roomBookingFile && ( +
+ +
+ )} + + {/* File Preview Component */} + {showFilePreview && filePreviewUrl && roomBookingFile && ( + +
+

File Preview

+ +
+ +
+ )} {/* Food/Drinks */} diff --git a/src/components/dashboard/Officer_EventRequestManagement.astro b/src/components/dashboard/Officer_EventRequestManagement.astro index d16bde6..8476134 100644 --- a/src/components/dashboard/Officer_EventRequestManagement.astro +++ b/src/components/dashboard/Officer_EventRequestManagement.astro @@ -256,7 +256,7 @@ try {
-