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 { QueryClientProvider, QueryClient } from "@tanstack/react-query";
|
||||||
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
|
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
|
||||||
import { AuthProvider } from "@/context/auth-context";
|
import { AuthProvider } from "@/context/auth-context";
|
||||||
|
import { EventsProvider } from "@/context/event-context";
|
||||||
import { ThemeProvider } from "next-themes";
|
import { ThemeProvider } from "next-themes";
|
||||||
|
|
||||||
// Create a client
|
// Create a client
|
||||||
@@ -26,7 +27,9 @@ export function Providers({ children }: { children: React.ReactNode }) {
|
|||||||
enableSystem
|
enableSystem
|
||||||
disableTransitionOnChange
|
disableTransitionOnChange
|
||||||
>
|
>
|
||||||
<AuthProvider>{children}</AuthProvider>
|
<AuthProvider>
|
||||||
|
<EventsProvider>{children}</EventsProvider>
|
||||||
|
</AuthProvider>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
<ReactQueryDevtools initialIsOpen={false} />
|
<ReactQueryDevtools initialIsOpen={false} />
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
|
|||||||
Reference in New Issue
Block a user