fix event request form
This commit is contained in:
parent
62c4c5f735
commit
38e45f3cb3
5 changed files with 231 additions and 142 deletions
|
@ -442,12 +442,7 @@ const EventRequestForm: React.FC = () => {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if there are items in the invoice
|
// No longer require items in the invoice
|
||||||
if (formData.invoiceData.items.length === 0) {
|
|
||||||
toast.error('Please add at least one item to the invoice');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if at least one invoice file is uploaded
|
// Check if at least one invoice file is uploaded
|
||||||
if (!formData.invoice && (!formData.invoice_files || formData.invoice_files.length === 0)) {
|
if (!formData.invoice && (!formData.invoice_files || formData.invoice_files.length === 0)) {
|
||||||
toast.error('Please upload at least one invoice file');
|
toast.error('Please upload at least one invoice file');
|
||||||
|
|
|
@ -108,8 +108,8 @@ const InvoiceBuilder: React.FC<InvoiceBuilderProps> = ({ invoiceData, onChange }
|
||||||
newErrors.quantity = 'Quantity must be greater than 0';
|
newErrors.quantity = 'Quantity must be greater than 0';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newItem.unitPrice <= 0) {
|
if (newItem.unitPrice < 0) {
|
||||||
newErrors.unitPrice = 'Unit price must be greater than 0';
|
newErrors.unitPrice = 'Unit price must be 0 or greater';
|
||||||
}
|
}
|
||||||
|
|
||||||
setErrors(newErrors);
|
setErrors(newErrors);
|
||||||
|
@ -183,7 +183,7 @@ const InvoiceBuilder: React.FC<InvoiceBuilderProps> = ({ invoiceData, onChange }
|
||||||
const value = parseFloat(e.target.value);
|
const value = parseFloat(e.target.value);
|
||||||
onChange({
|
onChange({
|
||||||
...invoiceData,
|
...invoiceData,
|
||||||
taxRate: isNaN(value) ? 0 : value
|
taxRate: isNaN(value) ? 0 : Math.max(0, value)
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -192,7 +192,7 @@ const InvoiceBuilder: React.FC<InvoiceBuilderProps> = ({ invoiceData, onChange }
|
||||||
const value = parseFloat(e.target.value);
|
const value = parseFloat(e.target.value);
|
||||||
onChange({
|
onChange({
|
||||||
...invoiceData,
|
...invoiceData,
|
||||||
tipPercentage: isNaN(value) ? 0 : value
|
tipPercentage: isNaN(value) ? 0 : Math.max(0, value)
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -341,7 +341,7 @@ const InvoiceBuilder: React.FC<InvoiceBuilderProps> = ({ invoiceData, onChange }
|
||||||
className={`input input-bordered input-sm ${errors.unitPrice ? 'input-error' : ''}`}
|
className={`input input-bordered input-sm ${errors.unitPrice ? 'input-error' : ''}`}
|
||||||
value={newItem.unitPrice}
|
value={newItem.unitPrice}
|
||||||
onChange={(e) => setNewItem({ ...newItem, unitPrice: parseFloat(e.target.value) || 0 })}
|
onChange={(e) => setNewItem({ ...newItem, unitPrice: parseFloat(e.target.value) || 0 })}
|
||||||
min="0.01"
|
min="0"
|
||||||
step="0.01"
|
step="0.01"
|
||||||
/>
|
/>
|
||||||
{errors.unitPrice && (
|
{errors.unitPrice && (
|
||||||
|
|
|
@ -11,21 +11,21 @@ const auth = Authentication.getInstance();
|
||||||
|
|
||||||
// Extended EventRequest interface with additional properties needed for this component
|
// Extended EventRequest interface with additional properties needed for this component
|
||||||
interface ExtendedEventRequest extends EventRequest {
|
interface ExtendedEventRequest extends EventRequest {
|
||||||
requested_user_expand?: {
|
requested_user_expand?: {
|
||||||
name: string;
|
name: string;
|
||||||
email: string;
|
email: string;
|
||||||
};
|
|
||||||
expand?: {
|
|
||||||
requested_user?: {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
email: string;
|
|
||||||
[key: string]: any;
|
|
||||||
};
|
};
|
||||||
[key: string]: any;
|
expand?: {
|
||||||
};
|
requested_user?: {
|
||||||
feedback?: string;
|
id: string;
|
||||||
[key: string]: any; // For other optional properties
|
name: string;
|
||||||
|
email: string;
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
feedback?: string;
|
||||||
|
[key: string]: any; // For other optional properties
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize variables for all event requests
|
// Initialize variables for all event requests
|
||||||
|
@ -33,113 +33,160 @@ let allEventRequests: ExtendedEventRequest[] = [];
|
||||||
let error = null;
|
let error = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Expand the requested_user field to get user details
|
// Don't check authentication here - let the client component handle it
|
||||||
allEventRequests = await get.getAll<ExtendedEventRequest>(
|
// The server-side check is causing issues when the token is valid client-side but not server-side
|
||||||
"event_request",
|
|
||||||
"",
|
|
||||||
"-created",
|
|
||||||
);
|
|
||||||
|
|
||||||
// Process the event requests to add the requested_user_expand property
|
console.log("Fetching event requests in Astro component...");
|
||||||
allEventRequests = allEventRequests.map((request) => {
|
// Expand the requested_user field to get user details
|
||||||
const requestWithExpand = { ...request };
|
allEventRequests = await get
|
||||||
|
.getAll<ExtendedEventRequest>("event_request", "", "-created", {
|
||||||
|
expand: ["requested_user"],
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error("Error in get.getAll:", err);
|
||||||
|
// Return empty array instead of throwing
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
|
||||||
// Add the requested_user_expand property if the expand data is available
|
console.log(
|
||||||
if (
|
`Fetched ${allEventRequests.length} event requests in Astro component`
|
||||||
request.expand &&
|
);
|
||||||
request.expand.requested_user &&
|
|
||||||
request.expand.requested_user.name &&
|
|
||||||
request.expand.requested_user.email
|
|
||||||
) {
|
|
||||||
requestWithExpand.requested_user_expand = {
|
|
||||||
name: request.expand.requested_user.name,
|
|
||||||
email: request.expand.requested_user.email,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestWithExpand;
|
// Process the event requests to add the requested_user_expand property
|
||||||
});
|
allEventRequests = allEventRequests.map((request) => {
|
||||||
|
const requestWithExpand = { ...request };
|
||||||
|
|
||||||
|
// Add the requested_user_expand property if the expand data is available
|
||||||
|
if (
|
||||||
|
request.expand &&
|
||||||
|
request.expand.requested_user &&
|
||||||
|
request.expand.requested_user.name &&
|
||||||
|
request.expand.requested_user.email
|
||||||
|
) {
|
||||||
|
requestWithExpand.requested_user_expand = {
|
||||||
|
name: request.expand.requested_user.name,
|
||||||
|
email: request.expand.requested_user.email,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return requestWithExpand;
|
||||||
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Error fetching event requests:", err);
|
console.error("Error fetching event requests:", err);
|
||||||
error = err;
|
error = err;
|
||||||
}
|
}
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="w-full max-w-7xl mx-auto py-8 px-4">
|
<div class="w-full max-w-7xl mx-auto py-8 px-4">
|
||||||
<style>
|
<style>
|
||||||
.event-table-container {
|
.event-table-container {
|
||||||
min-height: 600px;
|
min-height: 600px;
|
||||||
height: auto !important;
|
height: auto !important;
|
||||||
max-height: none !important;
|
max-height: none !important;
|
||||||
}
|
}
|
||||||
.event-table-container table {
|
.event-table-container table {
|
||||||
height: auto !important;
|
height: auto !important;
|
||||||
}
|
}
|
||||||
.event-table-container .overflow-x-auto {
|
.event-table-container .overflow-x-auto {
|
||||||
max-height: none !important;
|
max-height: none !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="mb-8">
|
<div class="mb-8">
|
||||||
<h1 class="text-3xl font-bold text-white mb-2">Event Request Management</h1>
|
<h1 class="text-3xl font-bold text-white mb-2">
|
||||||
<p class="text-gray-300 mb-4">
|
Event Request Management
|
||||||
Review and manage event requests submitted by officers. Update status,
|
</h1>
|
||||||
provide feedback, and coordinate with the team.
|
<p class="text-gray-300 mb-4">
|
||||||
</p>
|
Review and manage event requests submitted by officers. Update
|
||||||
<div class="bg-base-300/50 p-4 rounded-lg text-sm text-gray-300">
|
status, provide feedback, and coordinate with the team.
|
||||||
<p class="font-medium mb-2">As an executive officer, you can:</p>
|
</p>
|
||||||
<ul class="list-disc list-inside space-y-1 ml-2">
|
<div class="bg-base-300/50 p-4 rounded-lg text-sm text-gray-300">
|
||||||
<li>View all submitted event requests</li>
|
<p class="font-medium mb-2">As an executive officer, you can:</p>
|
||||||
<li>Update the status of requests (Pending, Completed, Declined)</li>
|
<ul class="list-disc list-inside space-y-1 ml-2">
|
||||||
<li>Add comments or feedback for the requesting officer</li>
|
<li>View all submitted event requests</li>
|
||||||
<li>Filter and sort requests by various criteria</li>
|
<li>
|
||||||
</ul>
|
Update the status of requests (Pending, Completed, Declined)
|
||||||
</div>
|
</li>
|
||||||
</div>
|
<li>Add comments or feedback for the requesting officer</li>
|
||||||
|
<li>Filter and sort requests by various criteria</li>
|
||||||
{
|
</ul>
|
||||||
error && (
|
|
||||||
<div class="alert alert-error mb-6">
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
class="h-6 w-6 stroke-current shrink-0"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<span>{error}</span>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
!error && (
|
|
||||||
<div class="bg-base-200 rounded-lg shadow-xl min-h-[600px] event-table-container">
|
|
||||||
<div class="p-4 md:p-6 h-auto">
|
|
||||||
<EventRequestManagementTable
|
|
||||||
client:load
|
|
||||||
eventRequests={allEventRequests}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
<!-- Toast container for notifications -->
|
{
|
||||||
<Toaster client:load position="bottom-right" />
|
error && (
|
||||||
|
<div class="alert alert-error mb-6">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="h-6 w-6 stroke-current shrink-0"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span>{error}</span>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
!error && (
|
||||||
|
<div class="bg-base-200 rounded-lg shadow-xl min-h-[600px] event-table-container">
|
||||||
|
<div class="p-4 md:p-6 h-auto">
|
||||||
|
<EventRequestManagementTable
|
||||||
|
client:load
|
||||||
|
eventRequests={allEventRequests}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Toast container for notifications -->
|
||||||
|
<Toaster client:load position="bottom-right" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Refresh the page when the user navigates back to it
|
// Refresh the page when the user navigates back to it
|
||||||
document.addEventListener("visibilitychange", () => {
|
document.addEventListener("visibilitychange", () => {
|
||||||
if (document.visibilityState === "visible") {
|
if (document.visibilityState === "visible") {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handle authentication errors
|
||||||
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
// Check for error message in the UI
|
||||||
|
const errorElement = document.querySelector(".alert-error span");
|
||||||
|
if (
|
||||||
|
errorElement &&
|
||||||
|
errorElement.textContent?.includes("Authentication error")
|
||||||
|
) {
|
||||||
|
console.log(
|
||||||
|
"Authentication error detected in UI, redirecting to login..."
|
||||||
|
);
|
||||||
|
// Redirect to login page after a short delay
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.href = "/login";
|
||||||
|
}, 3000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also check if we have any event requests
|
||||||
|
const tableContainer = document.querySelector(".event-table-container");
|
||||||
|
if (tableContainer) {
|
||||||
|
console.log(
|
||||||
|
"Event table container found, component should load normally"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
"Event table container not found, might be an issue with rendering"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
import type { EventRequest as SchemaEventRequest } from '../../../schemas/pocketbase';
|
import type { EventRequest as SchemaEventRequest } from '../../../schemas/pocketbase/schema';
|
||||||
|
|
||||||
// Extended EventRequest interface with additional properties needed for this component
|
// Extended EventRequest interface with additional properties needed for this component
|
||||||
interface ExtendedEventRequest extends SchemaEventRequest {
|
interface ExtendedEventRequest extends SchemaEventRequest {
|
||||||
|
@ -16,7 +16,7 @@ interface ExtendedEventRequest extends SchemaEventRequest {
|
||||||
interface EventRequestDetailsProps {
|
interface EventRequestDetailsProps {
|
||||||
request: ExtendedEventRequest;
|
request: ExtendedEventRequest;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onStatusChange: (id: string, status: string) => Promise<void>;
|
onStatusChange: (id: string, status: "submitted" | "pending" | "completed" | "declined") => Promise<void>;
|
||||||
onFeedbackChange: (id: string, feedback: string) => Promise<boolean>;
|
onFeedbackChange: (id: string, feedback: string) => Promise<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,16 +220,16 @@ const InvoiceTable: React.FC<{ invoiceData: any }> = ({ invoiceData }) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const EventRequestDetails: React.FC<EventRequestDetailsProps> = ({
|
const EventRequestDetails = ({
|
||||||
request,
|
request,
|
||||||
onClose,
|
onClose,
|
||||||
onStatusChange,
|
onStatusChange,
|
||||||
onFeedbackChange
|
onFeedbackChange
|
||||||
}) => {
|
}: EventRequestDetailsProps): React.ReactNode => {
|
||||||
const [feedback, setFeedback] = useState<string>(request.feedback || '');
|
const [feedback, setFeedback] = useState<string>(request.feedback || '');
|
||||||
const [isSaving, setIsSaving] = useState<boolean>(false);
|
const [isSaving, setIsSaving] = useState<boolean>(false);
|
||||||
const [activeTab, setActiveTab] = useState<'details' | 'pr' | 'funding'>('details');
|
const [activeTab, setActiveTab] = useState<'details' | 'pr' | 'funding'>('details');
|
||||||
const [status, setStatus] = useState(request.status);
|
const [status, setStatus] = useState<"submitted" | "pending" | "completed" | "declined">(request.status);
|
||||||
const [isStatusChanging, setIsStatusChanging] = useState(false);
|
const [isStatusChanging, setIsStatusChanging] = useState(false);
|
||||||
|
|
||||||
// Format date for display
|
// Format date for display
|
||||||
|
@ -250,16 +250,18 @@ const EventRequestDetails: React.FC<EventRequestDetailsProps> = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get status badge class based on status
|
// Get status badge class based on status
|
||||||
const getStatusBadge = (status?: string) => {
|
const getStatusBadge = (status?: "submitted" | "pending" | "completed" | "declined") => {
|
||||||
if (!status) return 'badge-warning';
|
if (!status) return 'badge-warning';
|
||||||
|
|
||||||
switch (status.toLowerCase()) {
|
switch (status) {
|
||||||
case 'completed':
|
case 'completed':
|
||||||
return 'badge-success';
|
return 'badge-success';
|
||||||
case 'declined':
|
case 'declined':
|
||||||
return 'badge-error';
|
return 'badge-error';
|
||||||
case 'pending':
|
case 'pending':
|
||||||
return 'badge-warning';
|
return 'badge-warning';
|
||||||
|
case 'submitted':
|
||||||
|
return 'badge-info';
|
||||||
default:
|
default:
|
||||||
return 'badge-warning';
|
return 'badge-warning';
|
||||||
}
|
}
|
||||||
|
@ -282,10 +284,10 @@ const EventRequestDetails: React.FC<EventRequestDetailsProps> = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle status change
|
// Handle status change
|
||||||
const handleStatusChange = async (status: string) => {
|
const handleStatusChange = async (newStatus: "submitted" | "pending" | "completed" | "declined") => {
|
||||||
setIsStatusChanging(true);
|
setIsStatusChanging(true);
|
||||||
await onStatusChange(request.id, status);
|
await onStatusChange(request.id, newStatus);
|
||||||
setStatus(status);
|
setStatus(newStatus);
|
||||||
setIsStatusChanging(false);
|
setIsStatusChanging(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { Update } from '../../../scripts/pocketbase/Update';
|
||||||
import { Authentication } from '../../../scripts/pocketbase/Authentication';
|
import { Authentication } from '../../../scripts/pocketbase/Authentication';
|
||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
import EventRequestDetails from './EventRequestDetails';
|
import EventRequestDetails from './EventRequestDetails';
|
||||||
import type { EventRequest as SchemaEventRequest } from '../../../schemas/pocketbase';
|
import type { EventRequest as SchemaEventRequest } from '../../../schemas/pocketbase/schema';
|
||||||
|
|
||||||
// Extended EventRequest interface with additional properties needed for this component
|
// Extended EventRequest interface with additional properties needed for this component
|
||||||
interface ExtendedEventRequest extends SchemaEventRequest {
|
interface ExtendedEventRequest extends SchemaEventRequest {
|
||||||
|
@ -24,6 +24,7 @@ interface ExtendedEventRequest extends SchemaEventRequest {
|
||||||
};
|
};
|
||||||
invoice_data?: any;
|
invoice_data?: any;
|
||||||
feedback?: string;
|
feedback?: string;
|
||||||
|
status: "submitted" | "pending" | "completed" | "declined";
|
||||||
}
|
}
|
||||||
|
|
||||||
interface EventRequestManagementTableProps {
|
interface EventRequestManagementTableProps {
|
||||||
|
@ -50,11 +51,10 @@ const EventRequestManagementTable = ({ eventRequests: initialEventRequests }: Ev
|
||||||
const get = Get.getInstance();
|
const get = Get.getInstance();
|
||||||
const auth = Authentication.getInstance();
|
const auth = Authentication.getInstance();
|
||||||
|
|
||||||
if (!auth.isAuthenticated()) {
|
// Don't check authentication here - try to fetch anyway
|
||||||
toast.error('You must be logged in to refresh event requests', { id: refreshToast });
|
// The token might be valid for the API even if isAuthenticated() returns false
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
console.log("Fetching event requests...");
|
||||||
const updatedRequests = await get.getAll<ExtendedEventRequest>(
|
const updatedRequests = await get.getAll<ExtendedEventRequest>(
|
||||||
'event_request',
|
'event_request',
|
||||||
'',
|
'',
|
||||||
|
@ -64,13 +64,26 @@ const EventRequestManagementTable = ({ eventRequests: initialEventRequests }: Ev
|
||||||
expand: ['requested_user']
|
expand: ['requested_user']
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
console.log(`Fetched ${updatedRequests.length} event requests`);
|
||||||
|
|
||||||
setEventRequests(updatedRequests);
|
setEventRequests(updatedRequests);
|
||||||
applyFilters(updatedRequests);
|
applyFilters(updatedRequests);
|
||||||
toast.success('Event requests refreshed successfully', { id: refreshToast });
|
toast.success('Event requests refreshed successfully', { id: refreshToast });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Failed to refresh event requests:', err);
|
console.error('Failed to refresh event requests:', err);
|
||||||
toast.error('Failed to refresh event requests. Please try again.', { id: refreshToast });
|
|
||||||
|
// 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 });
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
setIsRefreshing(false);
|
setIsRefreshing(false);
|
||||||
}
|
}
|
||||||
|
@ -129,7 +142,7 @@ const EventRequestManagementTable = ({ eventRequests: initialEventRequests }: Ev
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update event request status
|
// Update event request status
|
||||||
const updateEventRequestStatus = async (id: string, status: string) => {
|
const updateEventRequestStatus = async (id: string, status: "submitted" | "pending" | "completed" | "declined") => {
|
||||||
const updateToast = toast.loading(`Updating status to ${status}...`);
|
const updateToast = toast.loading(`Updating status to ${status}...`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -209,16 +222,18 @@ const EventRequestManagementTable = ({ eventRequests: initialEventRequests }: Ev
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get status badge class based on status
|
// Get status badge class based on status
|
||||||
const getStatusBadge = (status?: string) => {
|
const getStatusBadge = (status?: "submitted" | "pending" | "completed" | "declined") => {
|
||||||
if (!status) return 'badge-warning';
|
if (!status) return 'badge-warning';
|
||||||
|
|
||||||
switch (status.toLowerCase()) {
|
switch (status) {
|
||||||
case 'completed':
|
case 'completed':
|
||||||
return 'badge-success';
|
return 'badge-success';
|
||||||
case 'declined':
|
case 'declined':
|
||||||
return 'badge-error';
|
return 'badge-error';
|
||||||
case 'pending':
|
case 'pending':
|
||||||
return 'badge-warning';
|
return 'badge-warning';
|
||||||
|
case 'submitted':
|
||||||
|
return 'badge-info';
|
||||||
default:
|
default:
|
||||||
return 'badge-warning';
|
return 'badge-warning';
|
||||||
}
|
}
|
||||||
|
@ -253,6 +268,36 @@ const EventRequestManagementTable = ({ eventRequests: initialEventRequests }: Ev
|
||||||
applyFilters();
|
applyFilters();
|
||||||
}, [statusFilter, searchTerm, sortField, sortDirection]);
|
}, [statusFilter, searchTerm, sortField, sortDirection]);
|
||||||
|
|
||||||
|
// Check authentication and refresh token if needed
|
||||||
|
useEffect(() => {
|
||||||
|
const checkAuth = async () => {
|
||||||
|
const auth = Authentication.getInstance();
|
||||||
|
|
||||||
|
// Check if we're authenticated
|
||||||
|
if (!auth.isAuthenticated()) {
|
||||||
|
console.log("Authentication check failed - attempting to continue anyway");
|
||||||
|
|
||||||
|
// Don't show error or redirect immediately - try to refresh first
|
||||||
|
try {
|
||||||
|
// Try to refresh event requests anyway - the token might be valid
|
||||||
|
await refreshEventRequests();
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Failed to refresh after auth check:", err);
|
||||||
|
toast.error("Authentication error. Please log in again.");
|
||||||
|
|
||||||
|
// Only redirect if refresh fails
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.href = "/login";
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log("Authentication check passed");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
checkAuth();
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Auto refresh on component mount
|
// Auto refresh on component mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
refreshEventRequests();
|
refreshEventRequests();
|
||||||
|
@ -498,9 +543,9 @@ const EventRequestManagementTable = ({ eventRequests: initialEventRequests }: Ev
|
||||||
Update
|
Update
|
||||||
</label>
|
</label>
|
||||||
<ul tabIndex={0} className="dropdown-content z-[1] menu p-2 shadow bg-base-200 rounded-box w-52">
|
<ul tabIndex={0} className="dropdown-content z-[1] menu p-2 shadow bg-base-200 rounded-box w-52">
|
||||||
<li><a onClick={() => updateEventRequestStatus(request.id, 'Pending')}>Pending</a></li>
|
<li><a onClick={() => updateEventRequestStatus(request.id, "pending")}>Pending</a></li>
|
||||||
<li><a onClick={() => updateEventRequestStatus(request.id, 'Completed')}>Completed</a></li>
|
<li><a onClick={() => updateEventRequestStatus(request.id, "completed")}>Completed</a></li>
|
||||||
<li><a onClick={() => updateEventRequestStatus(request.id, 'Declined')}>Declined</a></li>
|
<li><a onClick={() => updateEventRequestStatus(request.id, "declined")}>Declined</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
|
|
Loading…
Reference in a new issue