update the files using the appropriate schema
This commit is contained in:
parent
f4db576400
commit
701854e633
24 changed files with 222 additions and 398 deletions
|
@ -1,6 +1,4 @@
|
|||
---
|
||||
import { Icon } from "@iconify/react";
|
||||
import JSZip from "jszip";
|
||||
import FilePreview from "./universal/FilePreview";
|
||||
import EventCheckIn from "./EventsSection/EventCheckIn";
|
||||
import EventLoad from "./EventsSection/EventLoad";
|
||||
|
|
|
@ -4,26 +4,11 @@ import { Authentication } from "../../../scripts/pocketbase/Authentication";
|
|||
import { Update } from "../../../scripts/pocketbase/Update";
|
||||
import { SendLog } from "../../../scripts/pocketbase/SendLog";
|
||||
import { Icon } from "@iconify/react";
|
||||
import type { Event, AttendeeEntry } from "../../../schemas/pocketbase";
|
||||
|
||||
|
||||
interface Event {
|
||||
id: string;
|
||||
event_name: string;
|
||||
event_code: string;
|
||||
location: string;
|
||||
points_to_reward: number;
|
||||
attendees: AttendeeEntry[];
|
||||
start_date: string;
|
||||
end_date: string;
|
||||
has_food: boolean;
|
||||
description: string;
|
||||
files: string[];
|
||||
}
|
||||
|
||||
interface AttendeeEntry {
|
||||
user_id: string;
|
||||
time_checked_in: string;
|
||||
food: string;
|
||||
// Extended Event interface with additional properties needed for this component
|
||||
interface ExtendedEvent extends Event {
|
||||
description?: string; // This component uses 'description' but schema has 'event_description'
|
||||
}
|
||||
|
||||
// Toast management system
|
||||
|
@ -109,7 +94,8 @@ const EventCheckIn = () => {
|
|||
|
||||
const currentUser = auth.getCurrentUser();
|
||||
if (!currentUser) {
|
||||
throw new Error("You must be logged in to check in to events");
|
||||
createToast("You must be logged in to check in to events", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the event with the given code
|
||||
|
@ -122,7 +108,8 @@ const EventCheckIn = () => {
|
|||
}
|
||||
|
||||
// Check if user is already checked in
|
||||
if (event.attendees.some((entry) => entry.user_id === currentUser.id)) {
|
||||
const attendees = event.attendees || [];
|
||||
if (attendees.some((entry) => entry.user_id === currentUser.id)) {
|
||||
throw new Error("You have already checked in to this event");
|
||||
}
|
||||
|
||||
|
@ -157,6 +144,27 @@ const EventCheckIn = () => {
|
|||
throw new Error("You must be logged in to check in to events");
|
||||
}
|
||||
|
||||
// Check if user is already checked in
|
||||
const userId = auth.getUserId();
|
||||
|
||||
if (!userId) {
|
||||
createToast("You must be logged in to check in to an event", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize attendees array if it doesn't exist
|
||||
const attendees = event.attendees || [];
|
||||
|
||||
// Check if user is already checked in
|
||||
const isAlreadyCheckedIn = attendees.some(
|
||||
(attendee) => attendee.user_id === userId
|
||||
);
|
||||
|
||||
if (isAlreadyCheckedIn) {
|
||||
createToast("You are already checked in to this event", "warning");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create attendee entry with check-in details
|
||||
const attendeeEntry: AttendeeEntry = {
|
||||
user_id: currentUser.id,
|
||||
|
|
|
@ -2,30 +2,16 @@ import { useEffect, useState } from "react";
|
|||
import { Icon } from "@iconify/react";
|
||||
import { Get } from "../../../scripts/pocketbase/Get";
|
||||
import { Authentication } from "../../../scripts/pocketbase/Authentication";
|
||||
import type { Event, AttendeeEntry } from "../../../schemas/pocketbase";
|
||||
|
||||
interface Event {
|
||||
id: string;
|
||||
event_name: string;
|
||||
event_code: string;
|
||||
location: string;
|
||||
points_to_reward: number;
|
||||
attendees: AttendeeEntry[];
|
||||
start_date: string;
|
||||
end_date: string;
|
||||
has_food: boolean;
|
||||
description: string;
|
||||
files: string[];
|
||||
}
|
||||
|
||||
interface AttendeeEntry {
|
||||
user_id: string;
|
||||
time_checked_in: string;
|
||||
food: string;
|
||||
// Extended Event interface with additional properties needed for this component
|
||||
interface ExtendedEvent extends Event {
|
||||
description?: string; // This component uses 'description' but schema has 'event_description'
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
openDetailsModal: (event: Event) => void;
|
||||
openDetailsModal: (event: ExtendedEvent) => void;
|
||||
downloadAllFiles: () => Promise<void>;
|
||||
currentEventId: string;
|
||||
[key: string]: any;
|
||||
|
@ -118,13 +104,13 @@ const EventLoad = () => {
|
|||
</div>
|
||||
|
||||
<div className="text-xs sm:text-sm text-base-content/70 my-2 line-clamp-2">
|
||||
{event.description || "No description available"}
|
||||
{event.event_description || "No description available"}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap items-center gap-2 mt-auto pt-2">
|
||||
{event.files && event.files.length > 0 && (
|
||||
<button
|
||||
onClick={() => window.openDetailsModal(event)}
|
||||
onClick={() => window.openDetailsModal(event as ExtendedEvent)}
|
||||
className="btn btn-ghost btn-sm text-xs sm:text-sm gap-1 h-8 min-h-0 px-2"
|
||||
>
|
||||
<Icon icon="heroicons:document-duplicate" className="h-3 w-3 sm:h-4 sm:w-4" />
|
||||
|
|
|
@ -5,32 +5,12 @@ import { Authentication } from "../../scripts/pocketbase/Authentication";
|
|||
import EventEditor from "./Officer_EventManagement/EventEditor";
|
||||
import FilePreview from "./universal/FilePreview";
|
||||
import Attendees from "./Officer_EventManagement/Attendees";
|
||||
import type { Event, AttendeeEntry } from "../../schemas/pocketbase";
|
||||
|
||||
// Get instances
|
||||
const get = Get.getInstance();
|
||||
const auth = Authentication.getInstance();
|
||||
|
||||
interface Event {
|
||||
id: string;
|
||||
event_name: string;
|
||||
event_description: string;
|
||||
event_code: string;
|
||||
location: string;
|
||||
files: string[];
|
||||
points_to_reward: number;
|
||||
start_date: string;
|
||||
end_date: string;
|
||||
published: boolean;
|
||||
has_food: boolean;
|
||||
attendees: AttendeeEntry[];
|
||||
}
|
||||
|
||||
interface AttendeeEntry {
|
||||
user_id: string;
|
||||
time_checked_in: string;
|
||||
food: string;
|
||||
}
|
||||
|
||||
interface ListResponse<T> {
|
||||
page: number;
|
||||
perPage: number;
|
||||
|
@ -64,7 +44,7 @@ const totalPages = eventResponse.totalPages;
|
|||
const currentPage = eventResponse.page;
|
||||
---
|
||||
|
||||
<div >
|
||||
<div>
|
||||
<div
|
||||
class="mb-4 md:mb-6 flex flex-col md:flex-row md:justify-between md:items-center gap-2"
|
||||
>
|
||||
|
|
|
@ -3,6 +3,12 @@ import { Get } from '../../../scripts/pocketbase/Get';
|
|||
import { Authentication } from '../../../scripts/pocketbase/Authentication';
|
||||
import { SendLog } from '../../../scripts/pocketbase/SendLog';
|
||||
import { Icon } from "@iconify/react";
|
||||
import type { Event, AttendeeEntry, User as SchemaUser } from "../../../schemas/pocketbase";
|
||||
|
||||
// Extended User interface with additional properties needed for this component
|
||||
interface User extends SchemaUser {
|
||||
member_type: string;
|
||||
}
|
||||
|
||||
// Cache for storing user data
|
||||
const userCache = new Map<string, {
|
||||
|
@ -46,29 +52,6 @@ const HighlightText = ({ text, searchTerms }: { text: string | number | null | u
|
|||
}
|
||||
};
|
||||
|
||||
interface AttendeeEntry {
|
||||
user_id: string;
|
||||
time_checked_in: string;
|
||||
food: string;
|
||||
}
|
||||
|
||||
interface User {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
pid: string;
|
||||
member_id: string;
|
||||
member_type: string;
|
||||
graduation_year: string;
|
||||
major: string;
|
||||
}
|
||||
|
||||
interface Event {
|
||||
id: string;
|
||||
event_name: string;
|
||||
attendees: AttendeeEntry[];
|
||||
}
|
||||
|
||||
// Add new interface for selected fields
|
||||
interface EventFields {
|
||||
id: true;
|
||||
|
|
|
@ -6,6 +6,13 @@ import { Update } from "../../../scripts/pocketbase/Update";
|
|||
import { FileManager } from "../../../scripts/pocketbase/FileManager";
|
||||
import { SendLog } from "../../../scripts/pocketbase/SendLog";
|
||||
import FilePreview from "../universal/FilePreview";
|
||||
import type { Event as SchemaEvent, AttendeeEntry } from "../../../schemas/pocketbase";
|
||||
|
||||
// Extended Event interface with optional created and updated fields
|
||||
interface Event extends Omit<SchemaEvent, 'created' | 'updated'> {
|
||||
created?: string;
|
||||
updated?: string;
|
||||
}
|
||||
|
||||
// Extend Window interface
|
||||
declare global {
|
||||
|
@ -17,27 +24,6 @@ declare global {
|
|||
}
|
||||
}
|
||||
|
||||
interface Event {
|
||||
id: string;
|
||||
event_name: string;
|
||||
event_description: string;
|
||||
event_code: string;
|
||||
location: string;
|
||||
files: string[];
|
||||
points_to_reward: number;
|
||||
start_date: string;
|
||||
end_date: string;
|
||||
published: boolean;
|
||||
has_food: boolean;
|
||||
attendees: AttendeeEntry[];
|
||||
}
|
||||
|
||||
interface AttendeeEntry {
|
||||
user_id: string;
|
||||
time_checked_in: string;
|
||||
food: string;
|
||||
}
|
||||
|
||||
interface EventEditorProps {
|
||||
onEventSaved?: () => void;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
---
|
||||
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 { toast, Toaster } from "react-hot-toast";
|
||||
import EventRequestFormPreview from "./Officer_EventRequestForm/EventRequestFormPreview";
|
||||
import EventRequestForm from "./Officer_EventRequestForm/EventRequestForm";
|
||||
import UserEventRequests from "./Officer_EventRequestForm/UserEventRequests";
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ 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 = {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import type { EventRequestFormData } from './EventRequestForm';
|
||||
import type { EventRequest } from '../../../schemas/pocketbase';
|
||||
|
||||
// Animation variants
|
||||
const itemVariants = {
|
||||
|
|
|
@ -5,6 +5,7 @@ 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 type { EventRequest } from '../../../schemas/pocketbase';
|
||||
|
||||
// Form sections
|
||||
import PRSection from './PRSection';
|
||||
|
@ -43,34 +44,42 @@ const itemVariants = {
|
|||
}
|
||||
};
|
||||
|
||||
// Form data interface
|
||||
// Form data interface - based on the schema EventRequest but with form-specific fields
|
||||
export interface EventRequestFormData {
|
||||
// Fields from EventRequest
|
||||
name: string;
|
||||
location: string;
|
||||
start_date_time: string;
|
||||
end_date_time: string;
|
||||
event_description: string;
|
||||
flyers_needed: boolean;
|
||||
photography_needed: boolean;
|
||||
as_funding_required: boolean;
|
||||
food_drinks_being_served: boolean;
|
||||
itemized_invoice?: string;
|
||||
status?: string;
|
||||
created_by?: string;
|
||||
id?: string;
|
||||
created?: string;
|
||||
updated?: string;
|
||||
|
||||
// Additional form-specific fields
|
||||
flyer_type: string[];
|
||||
other_flyer_type: string;
|
||||
flyer_advertising_start_date: string;
|
||||
flyer_additional_requests: string;
|
||||
photography_needed: boolean;
|
||||
required_logos: string[];
|
||||
other_logos: File[];
|
||||
other_logos: File[]; // Form uses File objects, schema uses strings
|
||||
advertising_format: string;
|
||||
will_or_have_room_booking: boolean;
|
||||
expected_attendance: number;
|
||||
room_booking: File | null;
|
||||
as_funding_required: boolean;
|
||||
food_drinks_being_served: boolean;
|
||||
itemized_invoice: string;
|
||||
invoice: File | null;
|
||||
invoice_files: File[]; // Support for multiple invoice files
|
||||
needs_graphics: boolean | null;
|
||||
needs_as_funding: boolean;
|
||||
invoice_files: File[];
|
||||
invoiceData: InvoiceData;
|
||||
formReviewed: boolean; // New field to track if the form has been reviewed
|
||||
needs_graphics?: boolean | null;
|
||||
needs_as_funding?: boolean | null;
|
||||
formReviewed?: boolean; // Track if the form has been reviewed
|
||||
}
|
||||
|
||||
const EventRequestForm: React.FC = () => {
|
||||
|
|
|
@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
|
|||
import { motion } from 'framer-motion';
|
||||
import type { EventRequestFormData } from './EventRequestForm';
|
||||
import type { InvoiceItem } from './InvoiceBuilder';
|
||||
import type { EventRequest } from '../../../schemas/pocketbase';
|
||||
|
||||
interface EventRequestFormPreviewProps {
|
||||
formData?: EventRequestFormData; // Optional prop to directly pass form data
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import type { EventRequestFormData } from './EventRequestForm';
|
||||
import type { EventRequest } from '../../../schemas/pocketbase';
|
||||
|
||||
// Animation variants
|
||||
const itemVariants = {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React, { useState } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import type { EventRequestFormData } from './EventRequestForm';
|
||||
import type { EventRequest } from '../../../schemas/pocketbase';
|
||||
|
||||
// Animation variants
|
||||
const itemVariants = {
|
||||
|
|
|
@ -3,31 +3,10 @@ import { motion, AnimatePresence } from 'framer-motion';
|
|||
import { Get } from '../../../scripts/pocketbase/Get';
|
||||
import { Authentication } from '../../../scripts/pocketbase/Authentication';
|
||||
import toast from 'react-hot-toast';
|
||||
import type { EventRequest as SchemaEventRequest } from '../../../schemas/pocketbase';
|
||||
|
||||
// Define the event request interface
|
||||
interface EventRequest {
|
||||
id: string;
|
||||
name: string;
|
||||
location: string;
|
||||
start_date_time: string;
|
||||
end_date_time: string;
|
||||
event_description: string;
|
||||
flyers_needed: boolean;
|
||||
photography_needed: boolean;
|
||||
as_funding_required: boolean;
|
||||
food_drinks_being_served: boolean;
|
||||
created: string;
|
||||
updated: string;
|
||||
status?: string; // Status might not be in the schema yet
|
||||
flyer_type?: string[];
|
||||
other_flyer_type?: string;
|
||||
flyer_advertising_start_date?: string;
|
||||
flyer_additional_requests?: string;
|
||||
required_logos?: string[];
|
||||
advertising_format?: string;
|
||||
will_or_have_room_booking?: boolean;
|
||||
expected_attendance?: number;
|
||||
itemized_invoice?: string;
|
||||
// Extended EventRequest interface with additional properties needed for this component
|
||||
export interface EventRequest extends SchemaEventRequest {
|
||||
invoice_data?: any;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,27 +3,14 @@ import { Authentication } from "../../scripts/pocketbase/Authentication";
|
|||
import { Get } from "../../scripts/pocketbase/Get";
|
||||
import { Toaster } from "react-hot-toast";
|
||||
import EventRequestManagementTable from "./Officer_EventRequestManagement/EventRequestManagementTable";
|
||||
import type { EventRequest } from "../../schemas/pocketbase";
|
||||
|
||||
// Get instances
|
||||
const get = Get.getInstance();
|
||||
const auth = Authentication.getInstance();
|
||||
|
||||
// Define the EventRequest interface
|
||||
interface EventRequest {
|
||||
id: string;
|
||||
name: string;
|
||||
location: string;
|
||||
start_date_time: string;
|
||||
end_date_time: string;
|
||||
event_description: string;
|
||||
flyers_needed: boolean;
|
||||
photography_needed: boolean;
|
||||
as_funding_required: boolean;
|
||||
food_drinks_being_served: boolean;
|
||||
created: string;
|
||||
updated: string;
|
||||
status: string;
|
||||
requested_user: string;
|
||||
// Extended EventRequest interface with additional properties needed for this component
|
||||
interface ExtendedEventRequest extends EventRequest {
|
||||
requested_user_expand?: {
|
||||
name: string;
|
||||
email: string;
|
||||
|
@ -42,26 +29,39 @@ interface EventRequest {
|
|||
}
|
||||
|
||||
// Initialize variables for all event requests
|
||||
let allEventRequests: EventRequest[] = [];
|
||||
let allEventRequests: ExtendedEventRequest[] = [];
|
||||
let error = null;
|
||||
|
||||
// Fetch all event requests if authenticated
|
||||
if (auth.isAuthenticated()) {
|
||||
try {
|
||||
try {
|
||||
// Expand the requested_user field to get user details
|
||||
allEventRequests = await get.getAll<EventRequest>(
|
||||
allEventRequests = await get.getAll<ExtendedEventRequest>(
|
||||
"event_request",
|
||||
"",
|
||||
"-created",
|
||||
{
|
||||
fields: ["*"],
|
||||
expand: ["requested_user"],
|
||||
},
|
||||
);
|
||||
} catch (err) {
|
||||
console.error("Failed to fetch event requests:", err);
|
||||
error = "Failed to load event requests. Please try again later.";
|
||||
|
||||
// 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) {
|
||||
console.error("Error fetching event requests:", err);
|
||||
error = err;
|
||||
}
|
||||
---
|
||||
|
||||
|
|
|
@ -1,49 +1,27 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import toast from 'react-hot-toast';
|
||||
import type { EventRequest as SchemaEventRequest } from '../../../schemas/pocketbase';
|
||||
|
||||
// Define the EventRequest interface
|
||||
interface EventRequest {
|
||||
id: string;
|
||||
name: string;
|
||||
location: string;
|
||||
start_date_time: string;
|
||||
end_date_time: string;
|
||||
event_description: string;
|
||||
flyers_needed: boolean;
|
||||
photography_needed: boolean;
|
||||
as_funding_required: boolean;
|
||||
food_drinks_being_served: boolean;
|
||||
created: string;
|
||||
updated: string;
|
||||
status: string;
|
||||
requested_user: string;
|
||||
// Extended EventRequest interface with additional properties needed for this component
|
||||
interface ExtendedEventRequest extends SchemaEventRequest {
|
||||
requested_user_expand?: {
|
||||
name: string;
|
||||
email: string;
|
||||
};
|
||||
flyer_type?: string[];
|
||||
other_flyer_type?: string;
|
||||
flyer_advertising_start_date?: string;
|
||||
flyer_additional_requests?: string;
|
||||
required_logos?: string[];
|
||||
advertising_format?: string;
|
||||
will_or_have_room_booking?: boolean;
|
||||
expected_attendance?: number;
|
||||
itemized_invoice?: string;
|
||||
invoice_data?: string | any;
|
||||
feedback?: string;
|
||||
}
|
||||
|
||||
interface EventRequestDetailsProps {
|
||||
request: EventRequest;
|
||||
request: ExtendedEventRequest;
|
||||
onClose: () => void;
|
||||
onStatusChange: (id: string, status: string) => Promise<void>;
|
||||
onFeedbackChange: (id: string, feedback: string) => Promise<boolean>;
|
||||
}
|
||||
|
||||
// Separate component for AS Funding tab to isolate any issues
|
||||
const ASFundingTab: React.FC<{ request: EventRequest }> = ({ request }) => {
|
||||
const ASFundingTab: React.FC<{ request: ExtendedEventRequest }> = ({ request }) => {
|
||||
if (!request.as_funding_required) {
|
||||
return (
|
||||
<div>
|
||||
|
|
|
@ -5,23 +5,10 @@ import { Update } from '../../../scripts/pocketbase/Update';
|
|||
import { Authentication } from '../../../scripts/pocketbase/Authentication';
|
||||
import toast from 'react-hot-toast';
|
||||
import EventRequestDetails from './EventRequestDetails';
|
||||
import type { EventRequest as SchemaEventRequest } from '../../../schemas/pocketbase';
|
||||
|
||||
// Define the EventRequest interface
|
||||
interface EventRequest {
|
||||
id: string;
|
||||
name: string;
|
||||
location: string;
|
||||
start_date_time: string;
|
||||
end_date_time: string;
|
||||
event_description: string;
|
||||
flyers_needed: boolean;
|
||||
photography_needed: boolean;
|
||||
as_funding_required: boolean;
|
||||
food_drinks_being_served: boolean;
|
||||
created: string;
|
||||
updated: string;
|
||||
status: string;
|
||||
requested_user: string;
|
||||
// Extended EventRequest interface with additional properties needed for this component
|
||||
interface ExtendedEventRequest extends SchemaEventRequest {
|
||||
requested_user_expand?: {
|
||||
name: string;
|
||||
email: string;
|
||||
|
@ -35,27 +22,18 @@ interface EventRequest {
|
|||
};
|
||||
[key: string]: any;
|
||||
};
|
||||
flyer_type?: string[];
|
||||
other_flyer_type?: string;
|
||||
flyer_advertising_start_date?: string;
|
||||
flyer_additional_requests?: string;
|
||||
required_logos?: string[];
|
||||
advertising_format?: string;
|
||||
will_or_have_room_booking?: boolean;
|
||||
expected_attendance?: number;
|
||||
itemized_invoice?: string;
|
||||
invoice_data?: any;
|
||||
feedback?: string;
|
||||
}
|
||||
|
||||
interface EventRequestManagementTableProps {
|
||||
eventRequests: EventRequest[];
|
||||
eventRequests: ExtendedEventRequest[];
|
||||
}
|
||||
|
||||
const EventRequestManagementTable: React.FC<EventRequestManagementTableProps> = ({ eventRequests: initialEventRequests }) => {
|
||||
const [eventRequests, setEventRequests] = useState<EventRequest[]>(initialEventRequests);
|
||||
const [filteredRequests, setFilteredRequests] = useState<EventRequest[]>(initialEventRequests);
|
||||
const [selectedRequest, setSelectedRequest] = useState<EventRequest | null>(null);
|
||||
const EventRequestManagementTable = ({ eventRequests: initialEventRequests }: EventRequestManagementTableProps) => {
|
||||
const [eventRequests, setEventRequests] = useState<ExtendedEventRequest[]>(initialEventRequests);
|
||||
const [filteredRequests, setFilteredRequests] = useState<ExtendedEventRequest[]>(initialEventRequests);
|
||||
const [selectedRequest, setSelectedRequest] = useState<ExtendedEventRequest | null>(null);
|
||||
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
|
||||
const [isRefreshing, setIsRefreshing] = useState<boolean>(false);
|
||||
const [statusFilter, setStatusFilter] = useState<string>('all');
|
||||
|
@ -77,7 +55,7 @@ const EventRequestManagementTable: React.FC<EventRequestManagementTableProps> =
|
|||
return;
|
||||
}
|
||||
|
||||
const updatedRequests = await get.getAll<EventRequest>(
|
||||
const updatedRequests = await get.getAll<ExtendedEventRequest>(
|
||||
'event_request',
|
||||
'',
|
||||
'-created',
|
||||
|
@ -123,8 +101,8 @@ const EventRequestManagementTable: React.FC<EventRequestManagementTableProps> =
|
|||
|
||||
// Apply sorting
|
||||
filtered.sort((a, b) => {
|
||||
let aValue: any = a[sortField as keyof EventRequest];
|
||||
let bValue: any = b[sortField as keyof EventRequest];
|
||||
let aValue: any = a[sortField as keyof ExtendedEventRequest];
|
||||
let bValue: any = b[sortField as keyof ExtendedEventRequest];
|
||||
|
||||
// Handle special cases
|
||||
if (sortField === 'requested_user') {
|
||||
|
@ -247,7 +225,7 @@ const EventRequestManagementTable: React.FC<EventRequestManagementTableProps> =
|
|||
};
|
||||
|
||||
// Open modal with event request details
|
||||
const openDetailModal = (request: EventRequest) => {
|
||||
const openDetailModal = (request: ExtendedEventRequest) => {
|
||||
setSelectedRequest(request);
|
||||
setIsModalOpen(true);
|
||||
};
|
||||
|
|
|
@ -2,14 +2,7 @@ import { useEffect, useState, useCallback, useMemo } from "react";
|
|||
import { Get } from "../../../scripts/pocketbase/Get";
|
||||
import { Authentication } from "../../../scripts/pocketbase/Authentication";
|
||||
import debounce from 'lodash/debounce';
|
||||
|
||||
interface Log {
|
||||
id: string;
|
||||
message: string;
|
||||
created: string;
|
||||
user_id?: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
import type { Log } from "../../../schemas/pocketbase";
|
||||
|
||||
interface PaginatedResponse {
|
||||
page: number;
|
||||
|
|
|
@ -1,25 +1,7 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import { Get } from "../../../scripts/pocketbase/Get";
|
||||
import { Authentication } from "../../../scripts/pocketbase/Authentication";
|
||||
|
||||
interface Event {
|
||||
id: string;
|
||||
event_name: string;
|
||||
attendees: Array<{
|
||||
food: string;
|
||||
time_checked_in: string;
|
||||
user_id: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
interface Log {
|
||||
id: string;
|
||||
message: string;
|
||||
created: string;
|
||||
type: string;
|
||||
part: string;
|
||||
user_id: string;
|
||||
}
|
||||
import type { Event, Log } from "../../../schemas/pocketbase";
|
||||
|
||||
export function Stats() {
|
||||
const [eventsAttended, setEventsAttended] = useState(0);
|
||||
|
|
|
@ -3,16 +3,11 @@ import { Icon } from '@iconify/react';
|
|||
import FilePreview from '../universal/FilePreview';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
|
||||
interface ExpenseItem {
|
||||
description: string;
|
||||
amount: number;
|
||||
category: string;
|
||||
}
|
||||
import type { ItemizedExpense } from '../../../schemas/pocketbase';
|
||||
|
||||
interface ReceiptFormData {
|
||||
field: File;
|
||||
itemized_expenses: ExpenseItem[];
|
||||
itemized_expenses: ItemizedExpense[];
|
||||
tax: number;
|
||||
date: string;
|
||||
location_name: string;
|
||||
|
@ -62,7 +57,7 @@ const itemVariants = {
|
|||
export default function ReceiptForm({ onSubmit, onCancel }: ReceiptFormProps) {
|
||||
const [file, setFile] = useState<File | null>(null);
|
||||
const [previewUrl, setPreviewUrl] = useState<string>('');
|
||||
const [itemizedExpenses, setItemizedExpenses] = useState<ExpenseItem[]>([
|
||||
const [itemizedExpenses, setItemizedExpenses] = useState<ItemizedExpense[]>([
|
||||
{ description: '', amount: 0, category: '' }
|
||||
]);
|
||||
const [tax, setTax] = useState<number>(0);
|
||||
|
@ -106,7 +101,7 @@ export default function ReceiptForm({ onSubmit, onCancel }: ReceiptFormProps) {
|
|||
setItemizedExpenses(itemizedExpenses.filter((_, i) => i !== index));
|
||||
};
|
||||
|
||||
const handleExpenseItemChange = (index: number, field: keyof ExpenseItem, value: string | number) => {
|
||||
const handleExpenseItemChange = (index: number, field: keyof ItemizedExpense, value: string | number) => {
|
||||
const newItems = [...itemizedExpenses];
|
||||
newItems[index] = {
|
||||
...newItems[index],
|
||||
|
|
|
@ -6,16 +6,11 @@ import { toast } from 'react-hot-toast';
|
|||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import FilePreview from '../universal/FilePreview';
|
||||
import ToastProvider from './ToastProvider';
|
||||
|
||||
interface ExpenseItem {
|
||||
description: string;
|
||||
amount: number;
|
||||
category: string;
|
||||
}
|
||||
import type { ItemizedExpense, Reimbursement } from '../../../schemas/pocketbase';
|
||||
|
||||
interface ReceiptFormData {
|
||||
field: File;
|
||||
itemized_expenses: ExpenseItem[];
|
||||
itemized_expenses: ItemizedExpense[];
|
||||
tax: number;
|
||||
date: string;
|
||||
location_name: string;
|
||||
|
@ -23,14 +18,13 @@ interface ReceiptFormData {
|
|||
notes: string;
|
||||
}
|
||||
|
||||
interface ReimbursementRequest {
|
||||
id?: string;
|
||||
// Extended Reimbursement interface with form-specific fields
|
||||
interface ReimbursementRequest extends Partial<Omit<Reimbursement, 'receipts'>> {
|
||||
title: string;
|
||||
total_amount: number;
|
||||
date_of_purchase: string;
|
||||
payment_method: string;
|
||||
status: 'submitted' | 'under_review' | 'approved' | 'rejected' | 'paid' | 'in_progress';
|
||||
submitted_by?: string;
|
||||
additional_info: string;
|
||||
receipts: string[];
|
||||
department: 'internal' | 'external' | 'projects' | 'events' | 'other';
|
||||
|
|
|
@ -7,12 +7,7 @@ import FilePreview from '../universal/FilePreview';
|
|||
import { toast } from 'react-hot-toast';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import ToastProvider from './ToastProvider';
|
||||
|
||||
interface ExpenseItem {
|
||||
description: string;
|
||||
amount: number;
|
||||
category: string;
|
||||
}
|
||||
import type { ItemizedExpense, Reimbursement, Receipt } from '../../../schemas/pocketbase';
|
||||
|
||||
interface AuditNote {
|
||||
note: string;
|
||||
|
@ -21,32 +16,14 @@ interface AuditNote {
|
|||
is_private: boolean;
|
||||
}
|
||||
|
||||
interface ReimbursementRequest {
|
||||
id: string;
|
||||
title: string;
|
||||
total_amount: number;
|
||||
date_of_purchase: string;
|
||||
payment_method: string;
|
||||
status: 'submitted' | 'under_review' | 'approved' | 'rejected' | 'paid' | 'in_progress';
|
||||
submitted_by: string;
|
||||
additional_info: string;
|
||||
receipts: string[];
|
||||
department: 'internal' | 'external' | 'projects' | 'events' | 'other';
|
||||
created: string;
|
||||
updated: string;
|
||||
// Extended Reimbursement interface with component-specific properties
|
||||
interface ReimbursementRequest extends Omit<Reimbursement, 'audit_notes'> {
|
||||
audit_notes: AuditNote[] | null;
|
||||
}
|
||||
|
||||
interface ReceiptDetails {
|
||||
id: string;
|
||||
field: string;
|
||||
created_by: string;
|
||||
itemized_expenses: ExpenseItem[];
|
||||
tax: number;
|
||||
date: string;
|
||||
location_name: string;
|
||||
location_address: string;
|
||||
notes: string;
|
||||
// Extended Receipt interface with component-specific properties
|
||||
interface ReceiptDetails extends Omit<Receipt, 'itemized_expenses' | 'audited_by'> {
|
||||
itemized_expenses: ItemizedExpense[];
|
||||
audited_by: string[];
|
||||
created: string;
|
||||
updated: string;
|
||||
|
|
|
@ -6,49 +6,23 @@ import { Update } from '../../../scripts/pocketbase/Update';
|
|||
import { Authentication } from '../../../scripts/pocketbase/Authentication';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import type { Receipt as SchemaReceipt, User, Reimbursement } from '../../../schemas/pocketbase';
|
||||
|
||||
interface Receipt {
|
||||
id: string;
|
||||
field: string;
|
||||
created_by: string;
|
||||
itemized_expenses: string; // JSON string
|
||||
tax: number;
|
||||
date: string;
|
||||
location_name: string;
|
||||
location_address: string;
|
||||
notes: string;
|
||||
audited_by: string[];
|
||||
// Extended Receipt interface with additional properties needed for this component
|
||||
interface ExtendedReceipt extends Omit<SchemaReceipt, 'audited_by'> {
|
||||
audited_by: string[]; // In schema it's a string, but in this component it's used as string[]
|
||||
auditor_names?: string[]; // Names of auditors
|
||||
created: string;
|
||||
updated: string;
|
||||
}
|
||||
|
||||
interface User {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
// Extended User interface with additional properties needed for this component
|
||||
interface ExtendedUser extends User {
|
||||
avatar: string;
|
||||
zelle_information: string;
|
||||
created: string;
|
||||
updated: string;
|
||||
}
|
||||
|
||||
interface Reimbursement {
|
||||
id: string;
|
||||
title: string;
|
||||
total_amount: number;
|
||||
date_of_purchase: string;
|
||||
payment_method: string;
|
||||
status: 'submitted' | 'under_review' | 'approved' | 'rejected' | 'in_progress' | 'paid';
|
||||
submitted_by: string;
|
||||
additional_info: string;
|
||||
receipts: string[]; // Array of Receipt IDs
|
||||
department: 'internal' | 'external' | 'projects' | 'events' | 'other';
|
||||
audit_notes: string | null; // JSON string for user-submitted notes
|
||||
audit_logs: string | null; // JSON string for system-generated logs
|
||||
created: string;
|
||||
updated: string;
|
||||
submitter?: User;
|
||||
// Extended Reimbursement interface with additional properties needed for this component
|
||||
interface ExtendedReimbursement extends Reimbursement {
|
||||
submitter?: ExtendedUser;
|
||||
}
|
||||
|
||||
interface FilterOptions {
|
||||
|
@ -66,10 +40,10 @@ interface ItemizedExpense {
|
|||
}
|
||||
|
||||
export default function ReimbursementManagementPortal() {
|
||||
const [reimbursements, setReimbursements] = useState<Reimbursement[]>([]);
|
||||
const [receipts, setReceipts] = useState<Record<string, Receipt>>({});
|
||||
const [selectedReimbursement, setSelectedReimbursement] = useState<Reimbursement | null>(null);
|
||||
const [selectedReceipt, setSelectedReceipt] = useState<Receipt | null>(null);
|
||||
const [reimbursements, setReimbursements] = useState<ExtendedReimbursement[]>([]);
|
||||
const [receipts, setReceipts] = useState<Record<string, ExtendedReceipt>>({});
|
||||
const [selectedReimbursement, setSelectedReimbursement] = useState<ExtendedReimbursement | null>(null);
|
||||
const [selectedReceipt, setSelectedReceipt] = useState<ExtendedReceipt | null>(null);
|
||||
const [showReceiptModal, setShowReceiptModal] = useState(false);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
@ -84,7 +58,7 @@ export default function ReimbursementManagementPortal() {
|
|||
const [loadingStatus, setLoadingStatus] = useState(false);
|
||||
const [expandedReceipts, setExpandedReceipts] = useState<Set<string>>(new Set());
|
||||
const [auditingReceipt, setAuditingReceipt] = useState<string | null>(null);
|
||||
const [users, setUsers] = useState<Record<string, User>>({});
|
||||
const [users, setUsers] = useState<Record<string, ExtendedUser>>({});
|
||||
const [showUserProfile, setShowUserProfile] = useState<string | null>(null);
|
||||
const [auditNotes, setAuditNotes] = useState<string[]>([]);
|
||||
const userDropdownRef = React.useRef<HTMLDivElement>(null);
|
||||
|
@ -157,7 +131,7 @@ export default function ReimbursementManagementPortal() {
|
|||
filter = filter ? `${filter} && ${dateFilter}` : dateFilter;
|
||||
}
|
||||
|
||||
const records = await get.getAll<Reimbursement>('reimbursement', filter, sort);
|
||||
const records = await get.getAll<ExtendedReimbursement>('reimbursement', filter, sort);
|
||||
console.log('Loaded reimbursements:', records);
|
||||
|
||||
// Load user data for submitters
|
||||
|
@ -165,7 +139,7 @@ export default function ReimbursementManagementPortal() {
|
|||
const userRecords = await Promise.all(
|
||||
Array.from(userIds).map(async id => {
|
||||
try {
|
||||
return await get.getOne<User>('users', id);
|
||||
return await get.getOne<ExtendedUser>('users', id);
|
||||
} catch (error) {
|
||||
console.error(`Failed to load user ${id}:`, error);
|
||||
return null;
|
||||
|
@ -173,7 +147,7 @@ export default function ReimbursementManagementPortal() {
|
|||
})
|
||||
);
|
||||
|
||||
const validUsers = userRecords.filter((u): u is User => u !== null);
|
||||
const validUsers = userRecords.filter((u): u is ExtendedUser => u !== null);
|
||||
const userMap = Object.fromEntries(
|
||||
validUsers.map(user => [user.id, user])
|
||||
);
|
||||
|
@ -197,7 +171,7 @@ export default function ReimbursementManagementPortal() {
|
|||
const receiptRecords = await Promise.all(
|
||||
receiptIds.map(async id => {
|
||||
try {
|
||||
const receipt = await get.getOne<Receipt>('receipts', id);
|
||||
const receipt = await get.getOne<ExtendedReceipt>('receipts', id);
|
||||
// Get auditor names from the users collection
|
||||
if (receipt.audited_by.length > 0) {
|
||||
const auditorUsers = await Promise.all(
|
||||
|
@ -216,7 +190,7 @@ export default function ReimbursementManagementPortal() {
|
|||
})
|
||||
);
|
||||
|
||||
const validReceipts = receiptRecords.filter((r): r is Receipt => r !== null);
|
||||
const validReceipts = receiptRecords.filter((r): r is ExtendedReceipt => r !== null);
|
||||
console.log('Successfully loaded receipt records:', validReceipts);
|
||||
|
||||
const receiptMap = Object.fromEntries(
|
||||
|
@ -295,11 +269,11 @@ export default function ReimbursementManagementPortal() {
|
|||
const refreshAuditData = async (reimbursementId: string) => {
|
||||
try {
|
||||
const get = Get.getInstance();
|
||||
const updatedReimbursement = await get.getOne<Reimbursement>('reimbursement', reimbursementId);
|
||||
const updatedReimbursement = await get.getOne<ExtendedReimbursement>('reimbursement', reimbursementId);
|
||||
|
||||
// Get updated user data if needed
|
||||
if (!users[updatedReimbursement.submitted_by]) {
|
||||
const user = await get.getOne<User>('users', updatedReimbursement.submitted_by);
|
||||
const user = await get.getOne<ExtendedUser>('users', updatedReimbursement.submitted_by);
|
||||
setUsers(prev => ({
|
||||
...prev,
|
||||
[user.id]: user
|
||||
|
@ -310,13 +284,13 @@ export default function ReimbursementManagementPortal() {
|
|||
const updatedReceipts = await Promise.all(
|
||||
updatedReimbursement.receipts.map(async id => {
|
||||
try {
|
||||
const receipt = await get.getOne<Receipt>('receipts', id);
|
||||
const receipt = await get.getOne<ExtendedReceipt>('receipts', id);
|
||||
// Get updated auditor names
|
||||
if (receipt.audited_by.length > 0) {
|
||||
const auditorUsers = await Promise.all(
|
||||
receipt.audited_by.map(async auditorId => {
|
||||
try {
|
||||
const user = await get.getOne<User>('users', auditorId);
|
||||
const user = await get.getOne<ExtendedUser>('users', auditorId);
|
||||
// Update users state with any new auditors
|
||||
setUsers(prev => ({
|
||||
...prev,
|
||||
|
@ -324,7 +298,7 @@ export default function ReimbursementManagementPortal() {
|
|||
}));
|
||||
return user;
|
||||
} catch {
|
||||
return { name: 'Unknown User' } as User;
|
||||
return { name: 'Unknown User' } as ExtendedUser;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
@ -338,7 +312,7 @@ export default function ReimbursementManagementPortal() {
|
|||
})
|
||||
);
|
||||
|
||||
const validReceipts = updatedReceipts.filter((r): r is Receipt => r !== null);
|
||||
const validReceipts = updatedReceipts.filter((r): r is ExtendedReceipt => r !== null);
|
||||
const receiptMap = Object.fromEntries(
|
||||
validReceipts.map(receipt => [receipt.id, receipt])
|
||||
);
|
||||
|
@ -476,7 +450,7 @@ export default function ReimbursementManagementPortal() {
|
|||
}
|
||||
};
|
||||
|
||||
const canApproveOrReject = (reimbursement: Reimbursement): boolean => {
|
||||
const canApproveOrReject = (reimbursement: ExtendedReimbursement): boolean => {
|
||||
const auth = Authentication.getInstance();
|
||||
const userId = auth.getUserId();
|
||||
|
||||
|
@ -489,14 +463,14 @@ export default function ReimbursementManagementPortal() {
|
|||
});
|
||||
};
|
||||
|
||||
const getReceiptUrl = (receipt: Receipt): string => {
|
||||
const getReceiptUrl = (receipt: ExtendedReceipt): string => {
|
||||
const auth = Authentication.getInstance();
|
||||
const pb = auth.getPocketBase();
|
||||
return pb.files.getURL(receipt, receipt.field);
|
||||
};
|
||||
|
||||
// Add this function to get the user avatar URL
|
||||
const getUserAvatarUrl = (user: User): string => {
|
||||
const getUserAvatarUrl = (user: ExtendedUser): string => {
|
||||
const auth = Authentication.getInstance();
|
||||
const pb = auth.getPocketBase();
|
||||
return pb.files.getURL(user, user.avatar);
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
import { Authentication } from "./Authentication";
|
||||
import { Collections } from "../../schemas/pocketbase";
|
||||
import type { Log } from "../../schemas/pocketbase";
|
||||
|
||||
// Log interface
|
||||
// Log data interface for creating new logs
|
||||
interface LogData {
|
||||
user_id: string;
|
||||
user: string; // Relation to User
|
||||
type: string; // Standard types: "error", "update", "delete", "create", "login", "logout"
|
||||
part: string; // The specific part/section being logged (can be multiple words, e.g., "profile settings", "resume upload")
|
||||
part: string; // The specific part/section being logged
|
||||
message: string;
|
||||
}
|
||||
|
||||
export class SendLog {
|
||||
private auth: Authentication;
|
||||
private static instance: SendLog;
|
||||
private readonly COLLECTION_NAME = "logs"; // Make collection name a constant
|
||||
private readonly COLLECTION_NAME = Collections.LOGS;
|
||||
|
||||
private constructor() {
|
||||
this.auth = Authentication.getInstance();
|
||||
|
@ -49,7 +51,12 @@ export class SendLog {
|
|||
* @param overrideUserId Optional user ID to override the current user
|
||||
* @returns Promise that resolves when the log is created
|
||||
*/
|
||||
public async send(type: string, part: string, message: string, overrideUserId?: string): Promise<void> {
|
||||
public async send(
|
||||
type: string,
|
||||
part: string,
|
||||
message: string,
|
||||
overrideUserId?: string,
|
||||
): Promise<void> {
|
||||
try {
|
||||
// Check authentication first
|
||||
if (!this.auth.isAuthenticated()) {
|
||||
|
@ -61,22 +68,24 @@ export class SendLog {
|
|||
const userId = overrideUserId || this.getCurrentUserId();
|
||||
if (!userId) {
|
||||
console.error("SendLog: No user ID available");
|
||||
throw new Error("No user ID available. User must be authenticated to create logs.");
|
||||
throw new Error(
|
||||
"No user ID available. User must be authenticated to create logs.",
|
||||
);
|
||||
}
|
||||
|
||||
// Prepare log data
|
||||
const logData: LogData = {
|
||||
user_id: userId,
|
||||
user: userId,
|
||||
type,
|
||||
part,
|
||||
message
|
||||
message,
|
||||
};
|
||||
|
||||
console.debug("SendLog: Preparing to send log:", {
|
||||
collection: this.COLLECTION_NAME,
|
||||
data: logData,
|
||||
authValid: this.auth.isAuthenticated(),
|
||||
userId
|
||||
userId,
|
||||
});
|
||||
|
||||
// Get PocketBase instance
|
||||
|
@ -94,7 +103,7 @@ export class SendLog {
|
|||
stack: error.stack,
|
||||
type,
|
||||
part,
|
||||
message
|
||||
message,
|
||||
});
|
||||
} else {
|
||||
console.error("SendLog: Unknown error:", error);
|
||||
|
@ -110,19 +119,26 @@ export class SendLog {
|
|||
* @param part Optional part/section to filter by
|
||||
* @returns Array of log entries
|
||||
*/
|
||||
public async getUserLogs(userId: string, type?: string, part?: string): Promise<LogData[]> {
|
||||
public async getUserLogs(
|
||||
userId: string,
|
||||
type?: string,
|
||||
part?: string,
|
||||
): Promise<Log[]> {
|
||||
if (!this.auth.isAuthenticated()) {
|
||||
throw new Error("User must be authenticated to retrieve logs");
|
||||
}
|
||||
|
||||
try {
|
||||
let filter = `user_id = "${userId}"`;
|
||||
let filter = `user = "${userId}"`;
|
||||
if (type) filter += ` && type = "${type}"`;
|
||||
if (part) filter += ` && part = "${part}"`;
|
||||
|
||||
const result = await this.auth.getPocketBase().collection(this.COLLECTION_NAME).getFullList<LogData>({
|
||||
const result = await this.auth
|
||||
.getPocketBase()
|
||||
.collection(this.COLLECTION_NAME)
|
||||
.getFullList<Log>({
|
||||
filter,
|
||||
sort: "-created"
|
||||
sort: "-created",
|
||||
});
|
||||
|
||||
return result;
|
||||
|
@ -139,7 +155,11 @@ export class SendLog {
|
|||
* @param part Optional part/section to filter by
|
||||
* @returns Array of recent log entries
|
||||
*/
|
||||
public async getRecentLogs(limit: number = 10, type?: string, part?: string): Promise<LogData[]> {
|
||||
public async getRecentLogs(
|
||||
limit: number = 10,
|
||||
type?: string,
|
||||
part?: string,
|
||||
): Promise<Log[]> {
|
||||
if (!this.auth.isAuthenticated()) {
|
||||
throw new Error("User must be authenticated to retrieve logs");
|
||||
}
|
||||
|
@ -150,13 +170,16 @@ export class SendLog {
|
|||
throw new Error("No user ID available");
|
||||
}
|
||||
|
||||
let filter = `user_id = "${userId}"`;
|
||||
let filter = `user = "${userId}"`;
|
||||
if (type) filter += ` && type = "${type}"`;
|
||||
if (part) filter += ` && part = "${part}"`;
|
||||
|
||||
const result = await this.auth.getPocketBase().collection(this.COLLECTION_NAME).getList<LogData>(1, limit, {
|
||||
const result = await this.auth
|
||||
.getPocketBase()
|
||||
.collection(this.COLLECTION_NAME)
|
||||
.getList<Log>(1, limit, {
|
||||
filter,
|
||||
sort: "-created"
|
||||
sort: "-created",
|
||||
});
|
||||
|
||||
return result.items;
|
||||
|
|
Loading…
Reference in a new issue