Add EventsContext for managing events state and operations
Introduce an EventsContext and EventsProvider to centralize event-related logic, including queries, mutations, and pagination. Wrap the application with the EventsProvider in the providers index to make the context accessible throughout the app.
This commit is contained in:
260
frontend/src/context/event-context.tsx
Normal file
260
frontend/src/context/event-context.tsx
Normal file
@@ -0,0 +1,260 @@
|
||||
"use client";
|
||||
|
||||
import React, {
|
||||
createContext,
|
||||
ReactNode,
|
||||
useCallback,
|
||||
useContext,
|
||||
useState,
|
||||
} from "react";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import {
|
||||
createEventMutation,
|
||||
deleteEventMutation,
|
||||
getEventBySlugOptions,
|
||||
getEventOptions,
|
||||
getPublicEventsOptions,
|
||||
getUpcomingEventsOptions,
|
||||
getUserEventsOptions,
|
||||
updateEventMutation,
|
||||
} from "@/client/@tanstack/react-query.gen";
|
||||
import {
|
||||
EventCreate,
|
||||
EventResponse,
|
||||
EventUpdate,
|
||||
PaginatedResponseEventResponse,
|
||||
} from "@/client/types.gen";
|
||||
|
||||
// Events context state interface
|
||||
interface EventsContextState {
|
||||
// Query access methods
|
||||
userEvents: PaginatedResponseEventResponse | undefined;
|
||||
upcomingEvents: PaginatedResponseEventResponse | undefined;
|
||||
publicEvents: PaginatedResponseEventResponse | undefined;
|
||||
isLoadingUserEvents: boolean;
|
||||
isLoadingUpcomingEvents: boolean;
|
||||
isLoadingPublicEvents: boolean;
|
||||
|
||||
// Single event methods
|
||||
getEvent: (id: string) => Promise<EventResponse | undefined>;
|
||||
getEventBySlug: (slug: string) => Promise<EventResponse | undefined>;
|
||||
|
||||
// Mutation methods
|
||||
createEvent: (event: EventCreate) => Promise<EventResponse>;
|
||||
updateEvent: (id: string, event: EventUpdate) => Promise<EventResponse>;
|
||||
deleteEvent: (id: string) => Promise<void>;
|
||||
|
||||
// Pagination control
|
||||
currentPage: number;
|
||||
pageSize: number;
|
||||
setCurrentPage: (page: number) => void;
|
||||
setPageSize: (size: number) => void;
|
||||
|
||||
// Loading & error states
|
||||
isCreating: boolean;
|
||||
isUpdating: boolean;
|
||||
isDeleting: boolean;
|
||||
error: Error | null;
|
||||
}
|
||||
|
||||
// Default context state
|
||||
const defaultEventsState: EventsContextState = {
|
||||
userEvents: undefined,
|
||||
upcomingEvents: undefined,
|
||||
publicEvents: undefined,
|
||||
isLoadingUserEvents: false,
|
||||
isLoadingUpcomingEvents: false,
|
||||
isLoadingPublicEvents: false,
|
||||
|
||||
getEvent: async () => undefined,
|
||||
getEventBySlug: async () => undefined,
|
||||
|
||||
createEvent: async () => {
|
||||
throw new Error("EventsProvider not initialized");
|
||||
},
|
||||
updateEvent: async () => {
|
||||
throw new Error("EventsProvider not initialized");
|
||||
},
|
||||
deleteEvent: async () => {
|
||||
throw new Error("EventsProvider not initialized");
|
||||
},
|
||||
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
setCurrentPage: () => {},
|
||||
setPageSize: () => {},
|
||||
|
||||
isCreating: false,
|
||||
isUpdating: false,
|
||||
isDeleting: false,
|
||||
error: null,
|
||||
};
|
||||
|
||||
// Create context
|
||||
const EventsContext = createContext<EventsContextState>(defaultEventsState);
|
||||
|
||||
// Custom hook to use the events context
|
||||
export const useEvents = () => {
|
||||
const context = useContext(EventsContext);
|
||||
if (!context) {
|
||||
throw new Error("useEvents must be used within an EventsProvider");
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
// Events Provider Props
|
||||
interface EventsProviderProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
// Events Provider Component
|
||||
export const EventsProvider: React.FC<EventsProviderProps> = ({ children }) => {
|
||||
const queryClient = useQueryClient();
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [pageSize, setPageSize] = useState(10);
|
||||
|
||||
// Query options with pagination
|
||||
const paginationParams = {
|
||||
query: {
|
||||
skip: (currentPage - 1) * pageSize,
|
||||
limit: pageSize,
|
||||
},
|
||||
};
|
||||
|
||||
// Get the user's events
|
||||
const {
|
||||
data: userEvents,
|
||||
isLoading: isLoadingUserEvents,
|
||||
error: userEventsError,
|
||||
} = useQuery({
|
||||
...getUserEventsOptions(paginationParams),
|
||||
});
|
||||
|
||||
// Get upcoming events
|
||||
const {
|
||||
data: upcomingEvents,
|
||||
isLoading: isLoadingUpcomingEvents,
|
||||
error: upcomingEventsError,
|
||||
} = useQuery({
|
||||
...getUpcomingEventsOptions(paginationParams),
|
||||
});
|
||||
|
||||
// Get public events
|
||||
const {
|
||||
data: publicEvents,
|
||||
isLoading: isLoadingPublicEvents,
|
||||
error: publicEventsError,
|
||||
} = useQuery({
|
||||
...getPublicEventsOptions(paginationParams),
|
||||
});
|
||||
|
||||
// Get a single event by ID
|
||||
const getEvent = useCallback(
|
||||
async (id: string): Promise<EventResponse | undefined> => {
|
||||
return await queryClient.fetchQuery({
|
||||
...getEventOptions({ path: { event_id: id } }),
|
||||
});
|
||||
},
|
||||
[queryClient],
|
||||
);
|
||||
|
||||
// Get a single event by slug
|
||||
const getEventBySlug = useCallback(
|
||||
async (slug: string): Promise<EventResponse | undefined> => {
|
||||
return await queryClient.fetchQuery({
|
||||
...getEventBySlugOptions({ path: { slug } }),
|
||||
});
|
||||
},
|
||||
[queryClient],
|
||||
);
|
||||
|
||||
// Create event mutation
|
||||
const createEventMutationHook = useMutation(createEventMutation());
|
||||
|
||||
const createEvent = useCallback(
|
||||
async (event: EventCreate): Promise<EventResponse> => {
|
||||
const result = await createEventMutationHook.mutateAsync({
|
||||
body: event,
|
||||
});
|
||||
|
||||
// Invalidate queries to refresh the lists
|
||||
queryClient.invalidateQueries({ queryKey: ["getUserEvents"] });
|
||||
return result;
|
||||
},
|
||||
[createEventMutationHook, queryClient],
|
||||
);
|
||||
|
||||
// Update event mutation
|
||||
const updateEventMutationHook = useMutation(updateEventMutation());
|
||||
|
||||
const updateEvent = useCallback(
|
||||
async (id: string, event: EventUpdate): Promise<EventResponse> => {
|
||||
const result = await updateEventMutationHook.mutateAsync({
|
||||
path: { event_id: id },
|
||||
body: event,
|
||||
});
|
||||
|
||||
// Invalidate specific queries
|
||||
queryClient.invalidateQueries({ queryKey: ["getEvent", id] });
|
||||
queryClient.invalidateQueries({ queryKey: ["getUserEvents"] });
|
||||
if (event.slug) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["getEventBySlug", event.slug],
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
[updateEventMutationHook, queryClient],
|
||||
);
|
||||
|
||||
// Delete event mutation
|
||||
const deleteEventMutationHook = useMutation(deleteEventMutation());
|
||||
|
||||
const deleteEvent = useCallback(
|
||||
async (id: string): Promise<void> => {
|
||||
await deleteEventMutationHook.mutateAsync({
|
||||
path: { event_id: id },
|
||||
});
|
||||
|
||||
// Invalidate queries to refresh the lists
|
||||
queryClient.invalidateQueries({ queryKey: ["getUserEvents"] });
|
||||
},
|
||||
[deleteEventMutationHook, queryClient],
|
||||
);
|
||||
|
||||
// Combine all errors from queries for error state
|
||||
const error =
|
||||
userEventsError || upcomingEventsError || publicEventsError || null;
|
||||
|
||||
// Context value
|
||||
const value: EventsContextState = {
|
||||
userEvents,
|
||||
upcomingEvents,
|
||||
publicEvents,
|
||||
isLoadingUserEvents,
|
||||
isLoadingUpcomingEvents,
|
||||
isLoadingPublicEvents,
|
||||
|
||||
getEvent,
|
||||
getEventBySlug,
|
||||
|
||||
createEvent,
|
||||
updateEvent,
|
||||
deleteEvent,
|
||||
|
||||
currentPage,
|
||||
pageSize,
|
||||
setCurrentPage,
|
||||
setPageSize,
|
||||
|
||||
isCreating: createEventMutationHook.isPending,
|
||||
isUpdating: updateEventMutationHook.isPending,
|
||||
isDeleting: deleteEventMutationHook.isPending,
|
||||
error,
|
||||
};
|
||||
|
||||
return (
|
||||
<EventsContext.Provider value={value}>{children}</EventsContext.Provider>
|
||||
);
|
||||
};
|
||||
@@ -4,6 +4,7 @@ import React from "react";
|
||||
import { QueryClientProvider, QueryClient } from "@tanstack/react-query";
|
||||
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
|
||||
import { AuthProvider } from "@/context/auth-context";
|
||||
import { EventsProvider } from "@/context/event-context";
|
||||
import { ThemeProvider } from "next-themes";
|
||||
|
||||
// Create a client
|
||||
@@ -26,7 +27,9 @@ export function Providers({ children }: { children: React.ReactNode }) {
|
||||
enableSystem
|
||||
disableTransitionOnChange
|
||||
>
|
||||
<AuthProvider>{children}</AuthProvider>
|
||||
<AuthProvider>
|
||||
<EventsProvider>{children}</EventsProvider>
|
||||
</AuthProvider>
|
||||
</ThemeProvider>
|
||||
<ReactQueryDevtools initialIsOpen={false} />
|
||||
</QueryClientProvider>
|
||||
|
||||
Reference in New Issue
Block a user