From 9019a974966c71093e9fdbe53fa3d648e70dfa0f Mon Sep 17 00:00:00 2001 From: chark1es Date: Thu, 20 Feb 2025 01:24:05 -0800 Subject: [PATCH] added an event request form --- .../dashboard/Officer_EventRequestForm.astro | 323 ++++++++++++ .../ASFundingSection.tsx | 464 ++++++++++++++++++ .../EventDetailsSection.tsx | 149 ++++++ .../Officer_EventRequestForm/InfoCard.tsx | 78 +++ .../Officer_EventRequestForm/PRSection.tsx | 232 +++++++++ .../Officer_EventRequestForm/TAPSection.tsx | 262 ++++++++++ .../Officer_EventRequestForm/Tooltip.tsx | 66 +++ .../Officer_EventRequestForm/tooltips.ts | 99 ++++ src/config/dashboard.yaml | 9 +- 9 files changed, 1681 insertions(+), 1 deletion(-) create mode 100644 src/components/dashboard/Officer_EventRequestForm.astro create mode 100644 src/components/dashboard/Officer_EventRequestForm/ASFundingSection.tsx create mode 100644 src/components/dashboard/Officer_EventRequestForm/EventDetailsSection.tsx create mode 100644 src/components/dashboard/Officer_EventRequestForm/InfoCard.tsx create mode 100644 src/components/dashboard/Officer_EventRequestForm/PRSection.tsx create mode 100644 src/components/dashboard/Officer_EventRequestForm/TAPSection.tsx create mode 100644 src/components/dashboard/Officer_EventRequestForm/Tooltip.tsx create mode 100644 src/components/dashboard/Officer_EventRequestForm/tooltips.ts diff --git a/src/components/dashboard/Officer_EventRequestForm.astro b/src/components/dashboard/Officer_EventRequestForm.astro new file mode 100644 index 0000000..00b0bf4 --- /dev/null +++ b/src/components/dashboard/Officer_EventRequestForm.astro @@ -0,0 +1,323 @@ +--- +import { Authentication } from "../../scripts/pocketbase/Authentication"; +import { Update } from "../../scripts/pocketbase/Update"; +import { FileManager } from "../../scripts/pocketbase/FileManager"; + +// Form sections +import PRSection from "./Officer_EventRequestForm/PRSection"; +import EventDetailsSection from "./Officer_EventRequestForm/EventDetailsSection"; +import TAPSection from "./Officer_EventRequestForm/TAPSection"; +import ASFundingSection from "./Officer_EventRequestForm/ASFundingSection"; + +const auth = Authentication.getInstance(); +const update = Update.getInstance(); +const fileManager = FileManager.getInstance(); +--- + +
+

+ Event Request Form +

+ +
+
+
+

+ Do you need graphics from our design team? +

+
+ + +
+
+
+ + + +
+ +
+ +
+ { + // This will be handled in the client-side script + document.dispatchEvent( + new CustomEvent("tap-section-change", { + detail: data, + }), + ); + }} + /> +
+ + + +
+ + +
+
+
+ + diff --git a/src/components/dashboard/Officer_EventRequestForm/ASFundingSection.tsx b/src/components/dashboard/Officer_EventRequestForm/ASFundingSection.tsx new file mode 100644 index 0000000..93b9b33 --- /dev/null +++ b/src/components/dashboard/Officer_EventRequestForm/ASFundingSection.tsx @@ -0,0 +1,464 @@ +import React, { useState } from 'react'; +import { motion, AnimatePresence } from 'framer-motion'; +import { toast } from 'react-hot-toast'; +import InfoCard from './InfoCard'; +import Tooltip from './Tooltip'; +import { tooltips, infoNotes } from './tooltips'; +import { Icon } from '@iconify/react'; + +interface InvoiceItem { + quantity: number; + item_name: string; + unit_cost: number; +} + +interface InvoiceData { + items: InvoiceItem[]; + tax: number; + tip: number; + total: number; + vendor: string; +} + +interface ASFundingSectionProps { + onDataChange?: (data: any) => void; +} + +const ASFundingSection: React.FC = ({ onDataChange }) => { + const [invoiceData, setInvoiceData] = useState({ + items: [{ quantity: 0, item_name: '', unit_cost: 0 }], + tax: 0, + tip: 0, + total: 0, + vendor: '' + }); + + const handleItemChange = (index: number, field: keyof InvoiceItem, value: string | number) => { + const newItems = [...invoiceData.items]; + newItems[index] = { ...newItems[index], [field]: value }; + + // Calculate new total + const itemsTotal = newItems.reduce((sum, item) => sum + (item.quantity * item.unit_cost), 0); + const newTotal = itemsTotal + invoiceData.tax + invoiceData.tip; + + setInvoiceData(prev => ({ + ...prev, + items: newItems, + total: newTotal + })); + + // Notify parent with JSON string + onDataChange?.({ + itemized_invoice: JSON.stringify({ + ...invoiceData, + items: newItems, + total: newTotal + }) + }); + }; + + const addItem = () => { + setInvoiceData(prev => ({ + ...prev, + items: [...prev.items, { quantity: 0, item_name: '', unit_cost: 0 }] + })); + toast('New item added', { icon: '➕' }); + }; + + const removeItem = (index: number) => { + if (invoiceData.items.length > 1) { + const newItems = invoiceData.items.filter((_, i) => i !== index); + + // Recalculate total + const itemsTotal = newItems.reduce((sum, item) => sum + (item.quantity * item.unit_cost), 0); + const newTotal = itemsTotal + invoiceData.tax + invoiceData.tip; + + setInvoiceData(prev => ({ + ...prev, + items: newItems, + total: newTotal + })); + + // Notify parent with JSON string + onDataChange?.({ + itemized_invoice: JSON.stringify({ + ...invoiceData, + items: newItems, + total: newTotal + }) + }); + toast('Item removed', { icon: '🗑️' }); + } + }; + + const handleExtraChange = (field: 'tax' | 'tip' | 'vendor', value: string | number) => { + const numValue = field !== 'vendor' ? Number(value) : value; + + // Calculate new total for tax/tip changes + const itemsTotal = invoiceData.items.reduce((sum, item) => sum + (item.quantity * item.unit_cost), 0); + const newTotal = field === 'tax' ? + itemsTotal + Number(value) + invoiceData.tip : + field === 'tip' ? + itemsTotal + invoiceData.tax + Number(value) : + itemsTotal + invoiceData.tax + invoiceData.tip; + + setInvoiceData(prev => ({ + ...prev, + [field]: numValue, + total: field !== 'vendor' ? newTotal : prev.total + })); + + // Notify parent with JSON string + onDataChange?.({ + itemized_invoice: JSON.stringify({ + ...invoiceData, + [field]: numValue, + total: field !== 'vendor' ? newTotal : invoiceData.total + }) + }); + }; + + return ( + +
+ + + AS Funding Details + + +
+ + + +
+ + +
+ +
+
+
+ +
+ handleExtraChange('vendor', e.target.value)} + required + /> +
+ + + +
+
+
+ + +
+ + +
+ +
+
+
+ + +
+ {invoiceData.items.map((item, index) => ( + +
+ + handleItemChange(index, 'quantity', Number(e.target.value))} + required + /> +
+
+ + handleItemChange(index, 'item_name', e.target.value)} + required + /> +
+
+ +
+ handleItemChange(index, 'unit_cost', Number(e.target.value))} + required + /> +
+ $ +
+
+
+ removeItem(index)} + disabled={invoiceData.items.length === 1} + > + + + + +
+ ))} +
+
+ + + + Add Item + +
+ + +
+
+ + +
+ +
+
+
+
+ handleExtraChange('tax', Number(e.target.value))} + required + /> +
+ $ +
+
+
+
+
+ + +
+ +
+
+
+
+ handleExtraChange('tip', Number(e.target.value))} + required + /> +
+ $ +
+
+
+
+ + +
+ + +
+ +
+
+
+
+ +
+ $ +
+
+
+ + +
+ + +
+ +
+
+
+ + + +
+ { + onDataChange?.({ invoice: e.target.files?.[0] }); + if (e.target.files?.[0]) { + toast('Invoice file uploaded', { icon: '📄' }); + } + }} + required + /> +
+ + + +
+
+
+
+
+
+ ); +}; + +export default ASFundingSection; \ No newline at end of file diff --git a/src/components/dashboard/Officer_EventRequestForm/EventDetailsSection.tsx b/src/components/dashboard/Officer_EventRequestForm/EventDetailsSection.tsx new file mode 100644 index 0000000..25e44f4 --- /dev/null +++ b/src/components/dashboard/Officer_EventRequestForm/EventDetailsSection.tsx @@ -0,0 +1,149 @@ +import React from 'react'; + +interface EventDetailsSectionProps { + onDataChange?: (data: any) => void; +} + +const EventDetailsSection: React.FC = ({ onDataChange }) => { + return ( +
+
+

+ + + + Event Details +

+ +
+
+ + onDataChange?.({ name: e.target.value })} + required + /> +
+ +
+ +