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

@@ -19,6 +19,7 @@
"@radix-ui/react-select": "^2.1.6",
"@radix-ui/react-slot": "^1.1.2",
"@radix-ui/react-switch": "^1.1.3",
"@radix-ui/react-tabs": "^1.1.3",
"@tanstack/react-query": "^5.67.1",
"axios": "^1.8.1",
"class-variance-authority": "^0.7.1",
@@ -1595,6 +1596,36 @@
}
}
},
"node_modules/@radix-ui/react-tabs": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.3.tgz",
"integrity": "sha512-9mFyI30cuRDImbmFF6O2KUJdgEOsGh9Vmx9x/Dh9tOhL7BngmQPQfwW4aejKm5OHpfWIdmeV6ySyuxoOGjtNng==",
"license": "MIT",
"dependencies": {
"@radix-ui/primitive": "1.1.1",
"@radix-ui/react-context": "1.1.1",
"@radix-ui/react-direction": "1.1.0",
"@radix-ui/react-id": "1.1.0",
"@radix-ui/react-presence": "1.1.2",
"@radix-ui/react-primitive": "2.0.2",
"@radix-ui/react-roving-focus": "1.1.2",
"@radix-ui/react-use-controllable-state": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-callback-ref": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz",

View File

@@ -24,6 +24,7 @@
"@radix-ui/react-select": "^2.1.6",
"@radix-ui/react-slot": "^1.1.2",
"@radix-ui/react-switch": "^1.1.3",
"@radix-ui/react-tabs": "^1.1.3",
"@tanstack/react-query": "^5.67.1",
"axios": "^1.8.1",
"class-variance-authority": "^0.7.1",

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>
);