Add GuestContext for managing guest-related state
Some checks failed
Build and Push Docker Images / changes (push) Successful in 5s
Build and Push Docker Images / build-backend (push) Has been skipped
Build and Push Docker Images / build-frontend (push) Failing after 51s

Introduced a new GuestContext with accompanying provider to handle guest-related data, including fetching, creating, updating, and deleting guests. Integrated GuestsProvider into the application's data provider hierarchy to ensure guest data is accessible across components.
This commit is contained in:
2025-03-15 21:45:16 +01:00
parent 90f49f99c6
commit 445d644538
4 changed files with 221 additions and 1 deletions

View File

@@ -0,0 +1,185 @@
"use client";
import React, {
createContext,
ReactNode,
useCallback,
useContext,
useState,
} from "react";
import {
useMutation,
useQuery,
useQueryClient,
RefetchOptions,
} from "@tanstack/react-query";
import {
GetGuestsResponse,
GuestRead,
GuestCreate,
GuestUpdate,
} from "@/client/types.gen";
import {
getGuestsOptions,
getGuestOptions,
} from "@/client/@tanstack/react-query.gen";
import { createGuest, updateGuest, deleteGuest } from "@/client";
// Guest context state
interface GuestsContextState {
guests: GetGuestsResponse | undefined;
guest: GuestRead | undefined;
isLoadingGuests: boolean;
isLoadingGuest: boolean;
error: Error | null;
refetchGuests: (options?: RefetchOptions) => Promise<any>;
createGuest: (data: GuestCreate) => Promise<GuestRead | undefined>;
updateGuest: (
id: string,
data: GuestUpdate,
) => Promise<GuestRead | undefined>;
deleteGuest: (id: string) => Promise<any>;
fetchGuestById: (id: string) => void;
currentGuestId: string | null;
setCurrentGuestId: (id: string | null) => void;
}
// Default context state
const defaultGuestsContextState: GuestsContextState = {
guests: undefined,
guest: undefined,
isLoadingGuests: false,
isLoadingGuest: false,
error: null,
refetchGuests: async () => {
throw new Error("GuestsProvider is not initialized");
},
createGuest: async () => {
throw new Error("GuestsProvider is not initialized");
},
updateGuest: async () => {
throw new Error("GuestsProvider is not initialized");
},
deleteGuest: async () => {
throw new Error("GuestsProvider is not initialized");
},
fetchGuestById: () => {},
currentGuestId: null,
setCurrentGuestId: () => {},
};
// Create context
const GuestsContext = createContext<GuestsContextState>(
defaultGuestsContextState,
);
// Hook to access context
export const useGuests = () => {
const context = useContext(GuestsContext);
if (!context) {
throw new Error("useGuests must be used within GuestsProvider");
}
return context;
};
// Provider Component Props
interface GuestsProviderProps {
children: ReactNode;
}
// Provider Component
export const GuestsProvider: React.FC<GuestsProviderProps> = ({ children }) => {
const queryClient = useQueryClient();
const [currentGuestId, setCurrentGuestId] = useState<string | null>(null);
// Fetch all guests
const {
data: guests,
isLoading: isLoadingGuests,
error,
refetch: refetchGuests,
} = useQuery({
...getGuestsOptions(),
refetchOnWindowFocus: "always",
refetchInterval: 60000,
});
// Fetch specific guest by ID
const { data: guest, isLoading: isLoadingGuest } = useQuery({
...getGuestOptions({ path: { guest_id: currentGuestId || "" } }),
enabled: !!currentGuestId,
});
// explicitly fetch guest by id
const fetchGuestById = useCallback((id: string) => {
setCurrentGuestId(id);
}, []);
// Create guest mutation
const createMutation = useMutation({
mutationFn: (data: GuestCreate) =>
createGuest({ body: data }).then((res) => res.data),
onSuccess: () =>
queryClient.invalidateQueries({
queryKey: getGuestsOptions().queryKey,
}),
});
// Update guest mutation
const updateMutation = useMutation({
mutationFn: ({ id, data }: { id: string; data: GuestUpdate }) =>
updateGuest({ path: { guest_id: id }, body: data }).then(
(res) => res.data,
),
onSuccess: (updatedGuest) => {
queryClient.invalidateQueries({
queryKey: getGuestsOptions().queryKey,
});
if (updatedGuest?.id === currentGuestId) {
queryClient.invalidateQueries({
queryKey: getGuestOptions({ path: { guest_id: currentGuestId } })
.queryKey,
});
}
},
});
// Delete guest mutation
const deleteMutation = useMutation({
mutationFn: (id: string) =>
deleteGuest({ path: { guest_id: id } }).then((res) => res.data),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: getGuestsOptions().queryKey,
});
setCurrentGuestId(null);
},
});
// Context state value
const value: GuestsContextState = {
guests,
guest,
isLoadingGuests,
isLoadingGuest,
error,
refetchGuests,
createGuest: createMutation.mutateAsync,
updateGuest: (id, data) => updateMutation.mutateAsync({ id, data }),
deleteGuest: deleteMutation.mutateAsync,
fetchGuestById,
currentGuestId,
setCurrentGuestId,
};
return (
<GuestsContext.Provider value={value}>{children}</GuestsContext.Provider>
);
};

View File

@@ -2,12 +2,15 @@ import React from "react";
import { EventsProvider } from "@/context/event-context";
import { EventThemesProvider } from "@/context/event-theme-context";
import { RSVPProvider } from "@/context/rsvp-context";
import { GuestsProvider } from "@/context/guest-context";
export function DataProviders({ children }: { children: React.ReactNode }) {
return (
<EventThemesProvider>
<EventsProvider>
<RSVPProvider>{children}</RSVPProvider>
<GuestsProvider>
<RSVPProvider>{children}</RSVPProvider>
</GuestsProvider>
</EventsProvider>
</EventThemesProvider>
);