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-select": "^2.1.6",
|
||||||
"@radix-ui/react-slot": "^1.1.2",
|
"@radix-ui/react-slot": "^1.1.2",
|
||||||
"@radix-ui/react-switch": "^1.1.3",
|
"@radix-ui/react-switch": "^1.1.3",
|
||||||
|
"@radix-ui/react-tabs": "^1.1.3",
|
||||||
"@tanstack/react-query": "^5.67.1",
|
"@tanstack/react-query": "^5.67.1",
|
||||||
"axios": "^1.8.1",
|
"axios": "^1.8.1",
|
||||||
"class-variance-authority": "^0.7.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": {
|
"node_modules/@radix-ui/react-use-callback-ref": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz",
|
"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-select": "^2.1.6",
|
||||||
"@radix-ui/react-slot": "^1.1.2",
|
"@radix-ui/react-slot": "^1.1.2",
|
||||||
"@radix-ui/react-switch": "^1.1.3",
|
"@radix-ui/react-switch": "^1.1.3",
|
||||||
|
"@radix-ui/react-tabs": "^1.1.3",
|
||||||
"@tanstack/react-query": "^5.67.1",
|
"@tanstack/react-query": "^5.67.1",
|
||||||
"axios": "^1.8.1",
|
"axios": "^1.8.1",
|
||||||
"class-variance-authority": "^0.7.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 { EventsProvider } from "@/context/event-context";
|
||||||
import { EventThemesProvider } from "@/context/event-theme-context";
|
import { EventThemesProvider } from "@/context/event-theme-context";
|
||||||
import { RSVPProvider } from "@/context/rsvp-context";
|
import { RSVPProvider } from "@/context/rsvp-context";
|
||||||
|
import { GuestsProvider } from "@/context/guest-context";
|
||||||
|
|
||||||
export function DataProviders({ children }: { children: React.ReactNode }) {
|
export function DataProviders({ children }: { children: React.ReactNode }) {
|
||||||
return (
|
return (
|
||||||
<EventThemesProvider>
|
<EventThemesProvider>
|
||||||
<EventsProvider>
|
<EventsProvider>
|
||||||
<RSVPProvider>{children}</RSVPProvider>
|
<GuestsProvider>
|
||||||
|
<RSVPProvider>{children}</RSVPProvider>
|
||||||
|
</GuestsProvider>
|
||||||
</EventsProvider>
|
</EventsProvider>
|
||||||
</EventThemesProvider>
|
</EventThemesProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user