Add GuestContext for managing guest-related state
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:
31
frontend/package-lock.json
generated
31
frontend/package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
185
frontend/src/context/guest-context.tsx
Normal file
185
frontend/src/context/guest-context.tsx
Normal 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>
|
||||
);
|
||||
};
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user