From 0c2fd1a8c23ec65dd20a8b9eb0b34b957a5e4fdd Mon Sep 17 00:00:00 2001 From: chark1es Date: Wed, 28 May 2025 01:42:24 -0700 Subject: [PATCH] fix events time issue --- .../dashboard/Officer_EmailManagement.astro | 89 +++++++++++++++ .../EventDetailsSection.tsx | 78 +++++++++++-- .../EventRequestForm.tsx | 104 ++++++++++++++++-- .../EventRequestDetails.tsx | 5 + .../EventRequestManagementTable.tsx | 65 +++++++++-- 5 files changed, 314 insertions(+), 27 deletions(-) create mode 100644 src/components/dashboard/Officer_EmailManagement.astro diff --git a/src/components/dashboard/Officer_EmailManagement.astro b/src/components/dashboard/Officer_EmailManagement.astro new file mode 100644 index 0000000..8dcf48b --- /dev/null +++ b/src/components/dashboard/Officer_EmailManagement.astro @@ -0,0 +1,89 @@ +--- +import { Icon } from "astro-icon/components"; +import EmailRequestSettings from "./SettingsSection/EmailRequestSettings"; + +// Import environment variables for debugging if needed +const logtoApiEndpoint = import.meta.env.LOGTO_API_ENDPOINT || ""; +--- +
+
+

IEEE Email Management

+

Manage your official IEEE UCSD email address

+
+ + +
+
+

+
+ +
+ IEEE Email Address +

+

+ Request and manage your official IEEE UCSD email address. This email can be used for official IEEE communications and professional purposes. +

+
+ +
+
+ + +
+
+

+
+ +
+ Email Usage Guidelines +

+
+
+ +
+

Officer Email Access

+

IEEE email addresses are only available to active IEEE UCSD officers. Your officer status is automatically verified when you request an email.

+
+
+ +
+

Acceptable Use:

+
    +
  • Official IEEE UCSD communications
  • +
  • Professional networking related to IEEE activities
  • +
  • Event coordination and planning
  • +
  • Communications with sponsors and external partners
  • +
+
+ +
+

Email Features:

+
    +
  • Webmail access at https://mail.ieeeucsd.org
  • +
  • IMAP/SMTP support for email clients
  • +
  • 5GB storage space
  • +
  • Professional @ieeeucsd.org domain
  • +
+
+ +
+

Important Notes:

+
    +
  • Your email username is based on your personal email address
  • +
  • Passwords can be reset through this interface
  • +
  • Email access may be revoked when officer status changes
  • +
  • Contact the webmaster for any technical issues
  • +
+
+
+
+
+
\ No newline at end of file diff --git a/src/components/dashboard/Officer_EventRequestForm/EventDetailsSection.tsx b/src/components/dashboard/Officer_EventRequestForm/EventDetailsSection.tsx index 73f889a..a71ecb2 100644 --- a/src/components/dashboard/Officer_EventRequestForm/EventDetailsSection.tsx +++ b/src/components/dashboard/Officer_EventRequestForm/EventDetailsSection.tsx @@ -129,7 +129,27 @@ const EventDetailsSection: React.FC = ({ formData, onD type="datetime-local" className="input input-bordered focus:input-primary transition-all duration-300 mt-2" value={formData.start_date_time} - onChange={(e) => onDataChange({ start_date_time: e.target.value })} + onChange={(e) => { + const newStartDateTime = e.target.value; + onDataChange({ start_date_time: newStartDateTime }); + + // If there's already an end time set, update it to use the new start date + if (formData.end_date_time && newStartDateTime) { + try { + const existingEndDate = new Date(formData.end_date_time); + const newStartDate = new Date(newStartDateTime); + + if (!isNaN(existingEndDate.getTime()) && !isNaN(newStartDate.getTime())) { + // Keep the same time but update to the new date + const updatedEndDate = new Date(newStartDate); + updatedEndDate.setHours(existingEndDate.getHours(), existingEndDate.getMinutes(), 0, 0); + onDataChange({ end_date_time: updatedEndDate.toISOString() }); + } + } catch (error) { + console.error('Error updating end date when start date changed:', error); + } + } + }} required whileHover="hover" variants={inputHoverVariants} @@ -155,25 +175,59 @@ const EventDetailsSection: React.FC = ({ formData, onD { + try { + const endDate = new Date(formData.end_date_time); + if (isNaN(endDate.getTime())) return ''; + return endDate.toTimeString().substring(0, 5); + } catch (e) { + return ''; + } + })() : ''} onChange={(e) => { - 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() }); + const timeValue = e.target.value; + if (timeValue && formData.start_date_time) { + try { + // Create a new date object from start_date_time + const startDate = new Date(formData.start_date_time); + if (isNaN(startDate.getTime())) { + console.error('Invalid start date time'); + return; + } + + // Parse the time value + const [hours, minutes] = timeValue.split(':').map(Number); + + // Validate hours and minutes + if (isNaN(hours) || isNaN(minutes) || hours < 0 || hours > 23 || minutes < 0 || minutes > 59) { + console.error('Invalid time values'); + return; + } + + // Create a new date with the same date as start but different time + const endDate = new Date(startDate); + endDate.setHours(hours, minutes, 0, 0); + + // Update end_date_time with the new time but same date as start + onDataChange({ end_date_time: endDate.toISOString() }); + } catch (error) { + console.error('Error setting end time:', error); + } + } else if (!timeValue) { + // Clear end_date_time if time is cleared + onDataChange({ end_date_time: '' }); } }} required + disabled={!formData.start_date_time} whileHover="hover" variants={inputHoverVariants} />

- The end time will use the same date as the start date. + {!formData.start_date_time + ? "Please set the start date and time first." + : "The end time will use the same date as the start date." + }

diff --git a/src/components/dashboard/Officer_EventRequestForm/EventRequestForm.tsx b/src/components/dashboard/Officer_EventRequestForm/EventRequestForm.tsx index c74cb80..ebb14d1 100644 --- a/src/components/dashboard/Officer_EventRequestForm/EventRequestForm.tsx +++ b/src/components/dashboard/Officer_EventRequestForm/EventRequestForm.tsx @@ -176,9 +176,28 @@ const EventRequestForm: React.FC = () => { } setFormData(prevData => { - // Save to localStorage const updatedData = { ...prevData, ...sectionData }; - localStorage.setItem('eventRequestFormData', JSON.stringify(updatedData)); + + // Save to localStorage + try { + const dataToStore = { + ...updatedData, + // Remove file objects before saving to localStorage + other_logos: [], + room_booking: null, + invoice: null, + invoice_files: [] + }; + localStorage.setItem('eventRequestFormData', JSON.stringify(dataToStore)); + + // Also update the preview data + window.dispatchEvent(new CustomEvent('formDataUpdated', { + detail: { formData: updatedData } + })); + } catch (error) { + console.error('Error saving form data to localStorage:', error); + } + return updatedData; }); }; @@ -267,8 +286,36 @@ const EventRequestForm: React.FC = () => { requested_user: userId, name: formData.name, location: formData.location, - start_date_time: new Date(formData.start_date_time).toISOString(), - end_date_time: formData.end_date_time ? new Date(formData.end_date_time).toISOString() : new Date(formData.start_date_time).toISOString(), + start_date_time: (() => { + try { + const startDate = new Date(formData.start_date_time); + if (isNaN(startDate.getTime())) { + throw new Error('Invalid start date'); + } + return startDate.toISOString(); + } catch (e) { + throw new Error('Invalid start date format'); + } + })(), + end_date_time: (() => { + try { + if (formData.end_date_time) { + const endDate = new Date(formData.end_date_time); + if (isNaN(endDate.getTime())) { + throw new Error('Invalid end date'); + } + return endDate.toISOString(); + } else { + // Fallback to start date if no end date (should not happen with validation) + const startDate = new Date(formData.start_date_time); + return startDate.toISOString(); + } + } catch (e) { + // Fallback to start date + const startDate = new Date(formData.start_date_time); + return startDate.toISOString(); + } + })(), event_description: formData.event_description, flyers_needed: formData.flyers_needed, photography_needed: formData.photography_needed, @@ -277,7 +324,14 @@ const EventRequestForm: React.FC = () => { itemized_invoice: formData.itemized_invoice, flyer_type: formData.flyer_type, other_flyer_type: formData.other_flyer_type, - flyer_advertising_start_date: formData.flyer_advertising_start_date ? new Date(formData.flyer_advertising_start_date).toISOString() : '', + flyer_advertising_start_date: formData.flyer_advertising_start_date ? (() => { + try { + const advertDate = new Date(formData.flyer_advertising_start_date); + return isNaN(advertDate.getTime()) ? '' : advertDate.toISOString(); + } catch (e) { + return ''; + } + })() : '', flyer_additional_requests: formData.flyer_additional_requests, required_logos: formData.required_logos, advertising_format: formData.advertising_format, @@ -407,11 +461,47 @@ const EventRequestForm: React.FC = () => { if (!formData.start_date_time || formData.start_date_time.trim() === '') { errors.push('Event start date and time is required'); valid = false; + } else { + // Validate start date format + try { + const startDate = new Date(formData.start_date_time); + if (isNaN(startDate.getTime())) { + errors.push('Invalid start date and time format'); + valid = false; + } else { + // Check if start date is in the future + const now = new Date(); + if (startDate <= now) { + errors.push('Event start date must be in the future'); + valid = false; + } + } + } catch (e) { + errors.push('Invalid start date and time format'); + valid = false; + } } - if (!formData.end_date_time) { + if (!formData.end_date_time || formData.end_date_time.trim() === '') { errors.push('Event end time is required'); valid = false; + } else if (formData.start_date_time) { + // Validate end date format and logic + try { + const startDate = new Date(formData.start_date_time); + const endDate = new Date(formData.end_date_time); + + if (isNaN(endDate.getTime())) { + errors.push('Invalid end date and time format'); + valid = false; + } else if (!isNaN(startDate.getTime()) && endDate <= startDate) { + errors.push('Event end time must be after the start time'); + valid = false; + } + } catch (e) { + errors.push('Invalid end date and time format'); + valid = false; + } } if (!formData.location || formData.location.trim() === '') { @@ -419,7 +509,7 @@ const EventRequestForm: React.FC = () => { valid = false; } - if (formData.will_or_have_room_booking === undefined) { + if (formData.will_or_have_room_booking === undefined || formData.will_or_have_room_booking === null) { errors.push('Room booking status is required'); valid = false; } diff --git a/src/components/dashboard/Officer_EventRequestManagement/EventRequestDetails.tsx b/src/components/dashboard/Officer_EventRequestManagement/EventRequestDetails.tsx index 012b3f0..98236bd 100644 --- a/src/components/dashboard/Officer_EventRequestManagement/EventRequestDetails.tsx +++ b/src/components/dashboard/Officer_EventRequestManagement/EventRequestDetails.tsx @@ -1644,6 +1644,11 @@ const EventRequestDetails = ({

{formatDate(request.start_date_time)}

+ +
+ +

{formatDate(request.end_date_time)}

+
diff --git a/src/components/dashboard/Officer_EventRequestManagement/EventRequestManagementTable.tsx b/src/components/dashboard/Officer_EventRequestManagement/EventRequestManagementTable.tsx index 30733b4..a7680ad 100644 --- a/src/components/dashboard/Officer_EventRequestManagement/EventRequestManagementTable.tsx +++ b/src/components/dashboard/Officer_EventRequestManagement/EventRequestManagementTable.tsx @@ -231,6 +231,50 @@ const EventRequestManagementTable = ({ } }; + // Format date and time range for display + const formatDateTimeRange = (startDateString: string, endDateString: string) => { + if (!startDateString) return 'Not specified'; + + try { + const startDate = new Date(startDateString); + const endDate = endDateString ? new Date(endDateString) : null; + + const startFormatted = startDate.toLocaleDateString('en-US', { + month: 'short', + day: 'numeric', + hour: '2-digit', + minute: '2-digit' + }); + + if (endDate && endDate.getTime() !== startDate.getTime()) { + // Check if it's the same day + const isSameDay = startDate.toDateString() === endDate.toDateString(); + + if (isSameDay) { + // Same day, just show end time + const endTime = endDate.toLocaleTimeString('en-US', { + hour: '2-digit', + minute: '2-digit' + }); + return `${startFormatted} - ${endTime}`; + } else { + // Different day, show full end date + const endFormatted = endDate.toLocaleDateString('en-US', { + month: 'short', + day: 'numeric', + hour: '2-digit', + minute: '2-digit' + }); + return `${startFormatted} - ${endFormatted}`; + } + } + + return startFormatted; + } catch (e) { + return startDateString; + } + }; + // Get status badge class based on status const getStatusBadge = (status?: "submitted" | "pending" | "completed" | "declined") => { if (!status) return 'badge-warning'; @@ -489,7 +533,7 @@ const EventRequestManagementTable = ({ height: "auto" }} > - +
- + @@ -570,7 +614,11 @@ const EventRequestManagementTable = ({ {truncateText(request.name, 30)} - +
handleSortChange('start_date_time')} >
- Date + Date & Time {sortField === 'start_date_time' && ( @@ -559,7 +603,7 @@ const EventRequestManagementTable = ({ )}
ActionsActions
{formatDate(request.start_date_time)} +
+ {formatDateTimeRange(request.start_date_time, request.end_date_time)} +
+
{(() => { const { name, email } = getUserDisplayInfo(request); @@ -603,16 +651,17 @@ const EventRequestManagementTable = ({ -
+