feat(api): tokens on all routes; items expose claims/claimedQuantity/remainingQuantity

This commit is contained in:
belisards
2026-05-03 16:25:19 -03:00
parent 844951c832
commit e518e28957
12 changed files with 139 additions and 214 deletions

View File

@@ -71,6 +71,15 @@ export interface Wishlist {
updatedAt: string;
}
export interface ItemClaim {
id: string;
quantity: number;
note: string | null;
isPurchased: boolean;
claimedAt: string;
guest: { id: string; name: string };
}
export interface Item {
id: string;
wishlistId: string;
@@ -82,10 +91,9 @@ export interface Item {
imageUrl: string | null;
purchaseUrls: Array<{ label: string; url: string }> | null;
isArchived: boolean;
claimedByName: string | null;
claimedByNote: string | null;
claimedAt: string | null;
isPurchased: boolean;
claims: ItemClaim[];
claimedQuantity: number;
remainingQuantity: number;
sortOrder: number;
createdAt: string;
updatedAt: string;

55
lib/items-with-claims.ts Normal file
View File

@@ -0,0 +1,55 @@
import { eq, inArray } from 'drizzle-orm';
import { db, wishlistItems, itemClaims, guests } from '@/lib/db';
type RawItem = typeof wishlistItems.$inferSelect;
export async function attachClaimsToItems(items: RawItem[]) {
if (items.length === 0) return [];
const itemIds = items.map((i) => i.id);
const rows = await db
.select({
id: itemClaims.id,
itemId: itemClaims.itemId,
quantity: itemClaims.quantity,
note: itemClaims.note,
isPurchased: itemClaims.isPurchased,
claimedAt: itemClaims.claimedAt,
guestId: guests.id,
guestName: guests.name,
})
.from(itemClaims)
.innerJoin(guests, eq(itemClaims.guestId, guests.id))
.where(inArray(itemClaims.itemId, itemIds));
const byItem = new Map<string, ReturnType<typeof shapeClaim>[]>();
for (const r of rows) {
const arr = byItem.get(r.itemId) ?? [];
arr.push(shapeClaim(r));
byItem.set(r.itemId, arr);
}
return items.map((it) => {
const claims = byItem.get(it.id) ?? [];
const claimedQuantity = claims.reduce((s, c) => s + c.quantity, 0);
return {
...it,
claims,
claimedQuantity,
remainingQuantity: Math.max(0, it.quantity - claimedQuantity),
};
});
}
function shapeClaim(r: {
id: string; quantity: number; note: string | null; isPurchased: boolean;
claimedAt: Date; guestId: string; guestName: string;
}) {
return {
id: r.id,
quantity: r.quantity,
note: r.note,
isPurchased: r.isPurchased,
claimedAt: r.claimedAt,
guest: { id: r.guestId, name: r.guestName },
};
}