more toast fixes

This commit is contained in:
chark1es 2025-03-01 04:56:51 -08:00
parent ef3e8f38d6
commit 5a453db3a4
10 changed files with 102 additions and 167 deletions

View file

@ -2,9 +2,6 @@
import FilePreview from "./universal/FilePreview";
import EventCheckIn from "./EventsSection/EventCheckIn";
import EventLoad from "./EventsSection/EventLoad";
import { Icon } from "astro-icon/components";
import { Get } from "../../scripts/pocketbase/Get";
import { toast } from "react-hot-toast";
---
<div id="" class="">

View file

@ -1,4 +1,4 @@
import { useEffect, useState } from "react";
import { useState } from "react";
import { Get } from "../../../scripts/pocketbase/Get";
import { Authentication } from "../../../scripts/pocketbase/Authentication";
import { Update } from "../../../scripts/pocketbase/Update";

View file

@ -4,10 +4,6 @@ import { Get } from "../../scripts/pocketbase/Get";
import EventRequestForm from "./Officer_EventRequestForm/EventRequestForm";
import UserEventRequests from "./Officer_EventRequestForm/UserEventRequests";
import { Collections } from "../../schemas/pocketbase/schema";
import { Icon } from "astro-icon/components";
import { Create } from "../../scripts/pocketbase/Create";
import { Update } from "../../scripts/pocketbase/Update";
import { toast } from "react-hot-toast";
// Import the EventRequest type from UserEventRequests to ensure consistency
import type { EventRequest as UserEventRequest } from "./Officer_EventRequestForm/UserEventRequests";

View file

@ -4,7 +4,6 @@ import toast from 'react-hot-toast';
import type { EventRequestFormData } from './EventRequestForm';
import InvoiceBuilder from './InvoiceBuilder';
import type { InvoiceData } from './InvoiceBuilder';
import type { EventRequest } from '../../../schemas/pocketbase';
// Animation variants
const itemVariants = {

View file

@ -4,10 +4,8 @@ import toast from 'react-hot-toast';
import { Authentication } from '../../../scripts/pocketbase/Authentication';
import { Update } from '../../../scripts/pocketbase/Update';
import { FileManager } from '../../../scripts/pocketbase/FileManager';
import { Get } from '../../../scripts/pocketbase/Get';
import { DataSyncService } from '../../../scripts/database/DataSyncService';
import { Collections } from '../../../schemas/pocketbase/schema';
import type { EventRequest } from '../../../schemas/pocketbase';
import { EventRequestStatus } from '../../../schemas/pocketbase';
// Form sections
@ -16,7 +14,6 @@ import EventDetailsSection from './EventDetailsSection';
import TAPFormSection from './TAPFormSection';
import ASFundingSection from './ASFundingSection';
import EventRequestFormPreview from './EventRequestFormPreview';
import InvoiceBuilder from './InvoiceBuilder';
import type { InvoiceData, InvoiceItem } from './InvoiceBuilder';
// Animation variants
@ -173,6 +170,50 @@ const EventRequestForm: React.FC = () => {
}));
};
// Add this function before the handleSubmit function
const resetForm = () => {
setFormData({
name: '',
location: '',
start_date_time: '',
end_date_time: '',
event_description: '',
flyers_needed: false,
flyer_type: [],
other_flyer_type: '',
flyer_advertising_start_date: '',
flyer_additional_requests: '',
photography_needed: false,
required_logos: [],
other_logos: [],
advertising_format: '',
will_or_have_room_booking: false,
expected_attendance: 0,
room_booking: null,
as_funding_required: false,
food_drinks_being_served: false,
itemized_invoice: '',
invoice: null,
invoice_files: [], // Reset multiple invoice files
needs_graphics: null,
needs_as_funding: false,
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: ''
},
formReviewed: false // Reset review status
});
// Reset to first step
setCurrentStep(1);
};
// Handle form submission
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
@ -186,9 +227,6 @@ const EventRequestForm: React.FC = () => {
setIsSubmitting(true);
setError(null);
// Show initial submitting toast
const submittingToast = toast.loading('Preparing to submit your event request...');
try {
const auth = Authentication.getInstance();
const update = Update.getInstance();
@ -196,14 +234,14 @@ const EventRequestForm: React.FC = () => {
const dataSync = DataSyncService.getInstance();
if (!auth.isAuthenticated()) {
toast.error('You must be logged in to submit an event request', { id: submittingToast });
toast.error('You must be logged in to submit an event request');
throw new Error('You must be logged in to submit an event request');
}
// Create the event request record
const userId = auth.getUserId();
if (!userId) {
toast.error('User ID not found', { id: submittingToast });
toast.error('User ID not found');
throw new Error('User ID not found');
}
@ -245,102 +283,53 @@ const EventRequestForm: React.FC = () => {
status: EventRequestStatus.SUBMITTED,
};
toast.loading('Creating event request record...', { id: submittingToast });
// Create the record using the Update service
// This will send the data to the server
const record = await update.create('event_request', submissionData);
try {
// Create the record using the Update service
// This will send the data to the server
const record = await update.create('event_request', submissionData);
// Force sync the event requests collection to update IndexedDB
await dataSync.syncCollection(Collections.EVENT_REQUESTS);
// Force sync the event requests collection to update IndexedDB
await dataSync.syncCollection(Collections.EVENT_REQUESTS);
// Upload files if they exist
if (formData.other_logos.length > 0) {
toast.loading('Uploading logo files...', { id: submittingToast });
await fileManager.uploadFiles('event_request', record.id, 'other_logos', formData.other_logos);
}
if (formData.room_booking) {
toast.loading('Uploading room booking confirmation...', { id: submittingToast });
await fileManager.uploadFile('event_request', record.id, 'room_booking', formData.room_booking);
}
// Upload multiple invoice files
if (formData.invoice_files && formData.invoice_files.length > 0) {
toast.loading('Uploading invoice files...', { id: submittingToast });
// Use appendFiles instead of uploadFiles to ensure we're adding files, not replacing them
await fileManager.appendFiles('event_request', record.id, 'invoice_files', formData.invoice_files);
// For backward compatibility, also upload the first file as the main invoice
if (formData.invoice || formData.invoice_files[0]) {
const mainInvoice = formData.invoice || formData.invoice_files[0];
await fileManager.uploadFile('event_request', record.id, 'invoice', mainInvoice);
}
} else if (formData.invoice) {
// If there are no invoice_files but there is a main invoice, upload it
toast.loading('Uploading invoice file...', { id: submittingToast });
await fileManager.uploadFile('event_request', record.id, 'invoice', formData.invoice);
}
// Clear form data from localStorage
localStorage.removeItem('eventRequestFormData');
// Show success message
toast.success('Event request submitted successfully!', { id: submittingToast });
// Reset form
setFormData({
name: '',
location: '',
start_date_time: '',
end_date_time: '',
event_description: '',
flyers_needed: false,
flyer_type: [],
other_flyer_type: '',
flyer_advertising_start_date: '',
flyer_additional_requests: '',
photography_needed: false,
required_logos: [],
other_logos: [],
advertising_format: '',
will_or_have_room_booking: false,
expected_attendance: 0,
room_booking: null,
as_funding_required: false,
food_drinks_being_served: false,
itemized_invoice: '',
invoice: null,
invoice_files: [], // Reset multiple invoice files
needs_graphics: null,
needs_as_funding: false,
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: ''
},
formReviewed: false // Reset review status
});
// Reset to first step
setCurrentStep(1);
} catch (uploadErr: any) {
console.error('Error during file upload:', uploadErr);
toast.error(`Error during file upload: ${uploadErr.message || 'Unknown error'}`, { id: submittingToast });
throw uploadErr;
// Upload files if they exist
if (formData.other_logos.length > 0) {
await fileManager.uploadFiles('event_request', record.id, 'other_logos', formData.other_logos);
}
} catch (err: any) {
console.error('Error submitting event request:', err);
setError(err.message || 'An error occurred while submitting your request');
toast.error(err.message || 'An error occurred while submitting your request', { id: submittingToast });
if (formData.room_booking) {
await fileManager.uploadFile('event_request', record.id, 'room_booking', formData.room_booking);
}
// Upload multiple invoice files
if (formData.invoice_files && formData.invoice_files.length > 0) {
await fileManager.appendFiles('event_request', record.id, 'invoice_files', formData.invoice_files);
// For backward compatibility, also upload the first file as the main invoice
if (formData.invoice || formData.invoice_files[0]) {
const mainInvoice = formData.invoice || formData.invoice_files[0];
await fileManager.uploadFile('event_request', record.id, 'invoice', mainInvoice);
}
} else if (formData.invoice) {
await fileManager.uploadFile('event_request', record.id, 'invoice', formData.invoice);
}
// Clear form data from localStorage
localStorage.removeItem('eventRequestFormData');
// Keep success toast for form submission since it's a user action
toast.success('Event request submitted successfully!');
// Reset form
resetForm();
// Switch to the submissions tab
const submissionsTab = document.getElementById('submissions-tab');
if (submissionsTab) {
submissionsTab.click();
}
} catch (error) {
console.error('Error submitting event request:', error);
toast.error('Failed to submit event request. Please try again.');
setError('Failed to submit event request. Please try again.');
} finally {
setIsSubmitting(false);
}

View file

@ -1,10 +1,8 @@
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 { DataSyncService } from '../../../scripts/database/DataSyncService';
import { Collections } from '../../../schemas/pocketbase/schema';
import toast from 'react-hot-toast';
import type { EventRequest as SchemaEventRequest } from '../../../schemas/pocketbase';
// Extended EventRequest interface with additional properties needed for this component
@ -27,19 +25,16 @@ const UserEventRequests: React.FC<UserEventRequestsProps> = ({ eventRequests: in
// Refresh event requests
const refreshEventRequests = async () => {
setIsRefreshing(true);
const refreshToast = toast.loading('Refreshing submissions...');
try {
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;
}
@ -52,10 +47,8 @@ const UserEventRequests: React.FC<UserEventRequestsProps> = ({ eventRequests: in
);
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);
}

View file

@ -48,8 +48,6 @@ const EventRequestManagementTable = ({ eventRequests: initialEventRequests }: Ev
// Refresh event requests
const refreshEventRequests = async () => {
setIsRefreshing(true);
const refreshToast = toast.loading('Refreshing event requests...');
try {
const auth = Authentication.getInstance();
@ -71,22 +69,9 @@ const EventRequestManagementTable = ({ eventRequests: initialEventRequests }: Ev
setEventRequests(updatedRequests);
applyFilters(updatedRequests);
toast.success('Event requests refreshed successfully', { id: refreshToast });
} catch (err) {
console.error('Failed to refresh event requests:', err);
// Check if it's an authentication error
if (err instanceof Error &&
(err.message.includes('authentication') ||
err.message.includes('auth') ||
err.message.includes('logged in'))) {
toast.error('Authentication error. Please log in again.', { id: refreshToast });
setTimeout(() => {
window.location.href = "/login";
}, 2000);
} else {
toast.error('Failed to refresh event requests. Please try again.', { id: refreshToast });
}
} catch (error) {
console.error('Error refreshing event requests:', error);
toast.error('Failed to refresh event requests');
} finally {
setIsRefreshing(false);
}
@ -146,8 +131,6 @@ const EventRequestManagementTable = ({ eventRequests: initialEventRequests }: Ev
// Update event request status
const updateEventRequestStatus = async (id: string, status: "submitted" | "pending" | "completed" | "declined") => {
const updateToast = toast.loading(`Updating status to ${status}...`);
try {
const update = Update.getInstance();
const result = await update.updateField('event_request', id, 'status', status);
@ -173,17 +156,15 @@ const EventRequestManagementTable = ({ eventRequests: initialEventRequests }: Ev
// Force sync to update IndexedDB
await dataSync.syncCollection<ExtendedEventRequest>(Collections.EVENT_REQUESTS);
toast.success(`Status updated to ${status}`, { id: updateToast });
} catch (err) {
console.error('Failed to update event request status:', err);
toast.error('Failed to update status. Please try again.', { id: updateToast });
// Remove success toast for updating status
} catch (error) {
console.error('Error updating status:', error);
toast.error('Failed to update status');
}
};
// Add feedback to event request
const addFeedback = async (id: string, feedback: string) => {
const feedbackToast = toast.loading('Saving feedback...');
try {
const update = Update.getInstance();
const result = await update.updateField('event_request', id, 'feedback', feedback);
@ -204,11 +185,11 @@ const EventRequestManagementTable = ({ eventRequests: initialEventRequests }: Ev
// Force sync to update IndexedDB
await dataSync.syncCollection<ExtendedEventRequest>(Collections.EVENT_REQUESTS);
toast.success('Feedback saved successfully', { id: feedbackToast });
// Remove success toast for saving feedback
return true;
} catch (err) {
console.error('Failed to save feedback:', err);
toast.error('Failed to save feedback. Please try again.', { id: feedbackToast });
} catch (error) {
console.error('Error saving feedback:', error);
toast.error('Failed to save feedback');
return false;
}
};

View file

@ -180,8 +180,6 @@ export default function ReimbursementForm() {
throw new Error('User not authenticated');
}
toast.loading('Adding receipt...');
// Create receipt record
const formData = new FormData();
formData.append('field', receiptData.field);
@ -211,11 +209,9 @@ export default function ReimbursementForm() {
}));
setShowReceiptForm(false);
toast.dismiss();
toast.success('Receipt added successfully');
} catch (error) {
console.error('Error creating receipt:', error);
toast.dismiss();
toast.error('Failed to add receipt');
setError('Failed to add receipt. Please try again.');
}
@ -252,8 +248,6 @@ export default function ReimbursementForm() {
throw new Error('User not authenticated');
}
const loadingToast = toast.loading('Submitting reimbursement request...');
// Create reimbursement record
const formData = new FormData();
formData.append('title', request.title);
@ -286,8 +280,6 @@ export default function ReimbursementForm() {
setReceipts([]);
setError('');
// Dismiss loading toast and show success
toast.dismiss(loadingToast);
toast.success('🎉 Reimbursement request submitted successfully! Check "My Requests" to view it.', {
duration: 5000,
position: 'top-center',

View file

@ -4,7 +4,6 @@ import { Get } from '../../../scripts/pocketbase/Get';
import { Authentication } from '../../../scripts/pocketbase/Authentication';
import { FileManager } from '../../../scripts/pocketbase/FileManager';
import FilePreview from '../universal/FilePreview';
import { toast } from 'react-hot-toast';
import { motion, AnimatePresence } from 'framer-motion';
import type { ItemizedExpense, Reimbursement, Receipt } from '../../../schemas/pocketbase';
import { DataSyncService } from '../../../scripts/database/DataSyncService';
@ -133,8 +132,6 @@ export default function ReimbursementList() {
throw new Error('User not authenticated');
}
const loadingToast = toast.loading('Loading reimbursements...');
// Use DataSyncService to get data from IndexedDB with forced sync
const dataSync = DataSyncService.getInstance();
@ -181,7 +178,6 @@ export default function ReimbursementList() {
});
setRequests(processedRecords);
toast.success('Reimbursements loaded successfully', { id: loadingToast });
// Fetch receipt details for each reimbursement
for (const record of processedRecords) {
@ -237,7 +233,6 @@ export default function ReimbursementList() {
} catch (err) {
console.error('Error fetching reimbursements:', err);
setError('Failed to load reimbursements. Please try again.');
toast.error('Failed to load reimbursements');
} finally {
setLoading(false);
}
@ -245,7 +240,6 @@ export default function ReimbursementList() {
const handlePreviewFile = async (request: ReimbursementRequest, receiptId: string) => {
try {
const loadingToast = toast.loading('Loading receipt...');
const pb = auth.getPocketBase();
// Check if we already have the receipt details in our map
@ -258,8 +252,6 @@ export default function ReimbursementList() {
setPreviewUrl(url);
setPreviewFilename(receiptDetailsMap[receiptId].field);
setShowPreview(true);
toast.dismiss(loadingToast);
toast.success('Receipt loaded successfully');
return;
}
@ -302,14 +294,11 @@ export default function ReimbursementList() {
setPreviewUrl(url);
setPreviewFilename(receiptRecord.field);
setShowPreview(true);
toast.dismiss(loadingToast);
toast.success('Receipt loaded successfully');
} else {
throw new Error('Receipt not found');
}
} catch (error) {
console.error('Error loading receipt:', error);
toast.error('Failed to load receipt');
}
};

View file

@ -1,11 +1,10 @@
import React from 'react';
import { Toaster } from 'react-hot-toast';
// Centralized toast provider to ensure consistent rendering
export default function ToastProvider() {
return (
<Toaster
position="bottom-right"
position="top-center"
toastOptions={{
duration: 4000,
style: {