more toast fixes
This commit is contained in:
parent
ef3e8f38d6
commit
5a453db3a4
10 changed files with 102 additions and 167 deletions
|
@ -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="">
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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: {
|
||||
|
|
Loading…
Reference in a new issue