Add functionality to display gift reservations per guest
Implemented fetching and grouping of guests' gift reservations for events. Added a popover UI to display reservation details, including guest names and quantities, with a loading state for pending data. This enhances the gift dashboard's interactivity and usability.
This commit is contained in:
@@ -44,7 +44,7 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { GiftPriority, GiftStatus } from "@/client/types.gen";
|
||||
import { GiftPriority, GiftPurchase, GiftStatus } from "@/client/types.gen";
|
||||
import { CategoryModal } from "@/components/gifts/category-modal";
|
||||
import { GiftModal } from "@/components/gifts/gift-modal";
|
||||
import {
|
||||
@@ -52,6 +52,7 @@ import {
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { useGuests } from "@/context/guest-context";
|
||||
|
||||
export default function GiftRegistryPage() {
|
||||
const { slug } = useParams<{ slug: string }>();
|
||||
@@ -68,8 +69,10 @@ export default function GiftRegistryPage() {
|
||||
currentEventId,
|
||||
setCurrentEventId,
|
||||
deleteItem,
|
||||
fetchGuestsGiftPurchases,
|
||||
} = useGifts();
|
||||
|
||||
const { guests } = useGuests();
|
||||
// State for modals
|
||||
const [isAddGiftModalOpen, setIsAddGiftModalOpen] = useState(false);
|
||||
const [isEditGiftModalOpen, setIsEditGiftModalOpen] = useState(false);
|
||||
@@ -84,6 +87,39 @@ export default function GiftRegistryPage() {
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const [categoryFilter, setCategoryFilter] = useState<string>("all");
|
||||
const [statusFilter, setStatusFilter] = useState<string>("all");
|
||||
const [reservations, setReservations] = useState<
|
||||
Record<string, GiftPurchase[]>
|
||||
>({});
|
||||
const [loadingReservations, setLoadingReservations] = useState<boolean>(true);
|
||||
|
||||
useEffect(() => {
|
||||
const loadReservations = async () => {
|
||||
if (currentEventId) {
|
||||
setLoadingReservations(true);
|
||||
try {
|
||||
const data = await fetchGuestsGiftPurchases(currentEventId);
|
||||
if (data) {
|
||||
const groupedReservations = data.reduce(
|
||||
(acc, purchase) => {
|
||||
const giftId = purchase.gift_id;
|
||||
if (!acc[giftId]) acc[giftId] = [];
|
||||
acc[giftId].push(purchase);
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, GiftPurchase[]>,
|
||||
);
|
||||
setReservations(groupedReservations);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Unable to fetch reservations:", err);
|
||||
} finally {
|
||||
setLoadingReservations(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
loadReservations();
|
||||
}, [currentEventId, fetchGuestsGiftPurchases]);
|
||||
|
||||
// Filter items based on search query and filters
|
||||
const filteredItems = items
|
||||
@@ -436,20 +472,44 @@ export default function GiftRegistryPage() {
|
||||
{getStatusBadge(item.status)}
|
||||
</div>
|
||||
</PopoverTrigger>
|
||||
{/*<PopoverContent className="text-sm">*/}
|
||||
{/* {item.reservations &&*/}
|
||||
{/* item.reservations.length > 0 ? (*/}
|
||||
{/* <ul className="list-disc">*/}
|
||||
{/* {item.reservations.map((res) => (*/}
|
||||
{/* <li key={res.guest_id}>*/}
|
||||
{/* {res.guest_name}: {res.quantity}*/}
|
||||
{/* </li>*/}
|
||||
{/* ))}*/}
|
||||
{/* </ul>*/}
|
||||
{/* ) : (*/}
|
||||
{/* <p>No reservations available.</p>*/}
|
||||
{/* )}*/}
|
||||
{/*</PopoverContent>*/}
|
||||
<PopoverContent className="text-sm w-[220px]">
|
||||
{loadingReservations ? (
|
||||
<div className="flex items-center justify-center p-2">
|
||||
<Loader2
|
||||
className="animate-spin"
|
||||
size={16}
|
||||
/>
|
||||
<span className="ml-2">
|
||||
Loading reservations...
|
||||
</span>
|
||||
</div>
|
||||
) : reservations[item.id] &&
|
||||
reservations[item.id].length > 0 ? (
|
||||
<ul className="list-disc pl-4 py-2">
|
||||
{reservations[item.id].map(
|
||||
(purchase, index) => {
|
||||
const guest = guests?.find(
|
||||
(g) => g.id === purchase.guest_id,
|
||||
);
|
||||
|
||||
return (
|
||||
<li key={`${purchase.id}_${index}`}>
|
||||
<strong>
|
||||
{guest?.full_name ||
|
||||
purchase.guest_id}
|
||||
</strong>
|
||||
: {purchase.quantity}
|
||||
</li>
|
||||
);
|
||||
},
|
||||
)}
|
||||
</ul>
|
||||
) : (
|
||||
<p className="p-2 text-gray-500">
|
||||
No reservations available.
|
||||
</p>
|
||||
)}
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
) : (
|
||||
getStatusBadge(item.status)
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
readGiftPurchase,
|
||||
readGiftPurchasesByGift,
|
||||
readGiftPurchasesByGuest,
|
||||
readGuestsGiftReservations,
|
||||
} from "@/client/sdk.gen";
|
||||
import {
|
||||
GiftCategory,
|
||||
@@ -48,6 +49,10 @@ interface GiftContextState {
|
||||
refetchCategories: (eventId: string) => Promise<any>;
|
||||
|
||||
fetchCategoryById: (id: string, eventId?: string) => void;
|
||||
fetchGuestsGiftPurchases: (
|
||||
eventId: string,
|
||||
) => Promise<GiftPurchase[] | undefined>;
|
||||
|
||||
createCategory: (
|
||||
data: GiftCategoryCreate,
|
||||
) => Promise<GiftCategory | undefined>;
|
||||
@@ -147,6 +152,8 @@ const defaultGiftContextState: GiftContextState = {
|
||||
},
|
||||
|
||||
fetchCategoryById: () => {},
|
||||
fetchGuestsGiftPurchases: async () => undefined,
|
||||
|
||||
createCategory: async () => {
|
||||
throw new Error("GiftContext not initialized");
|
||||
},
|
||||
@@ -310,6 +317,20 @@ export const GiftProvider: React.FC<GiftProviderProps> = ({ children }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const fetchGuestsGiftPurchases = async (
|
||||
eventId: string,
|
||||
): Promise<GiftPurchase[] | undefined> => {
|
||||
try {
|
||||
const result = await readGuestsGiftReservations({
|
||||
query: { event_id: eventId },
|
||||
});
|
||||
return result.data;
|
||||
} catch (error) {
|
||||
console.error("Error fetching guests' gift purchases:", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// Create Category Mutation
|
||||
const createCategoryMutation = useMutation({
|
||||
mutationFn: (data: GiftCategoryCreate) =>
|
||||
@@ -771,7 +792,7 @@ export const GiftProvider: React.FC<GiftProviderProps> = ({ children }) => {
|
||||
isLoadingCategories,
|
||||
isLoadingCategory,
|
||||
refetchCategories,
|
||||
|
||||
fetchGuestsGiftPurchases,
|
||||
fetchCategoryById,
|
||||
createCategory: createCategoryMutation.mutateAsync,
|
||||
updateCategory: (id, data, eventId) =>
|
||||
|
||||
Reference in New Issue
Block a user