feat(waitlist): add lazy expiry for entries with past preferredDate (GRO-180)
When reading waitlist entries, active entries with preferredDate < today are marked as expired both in the database and in the response. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
committed by
Flea Flicker
parent
a0f93fbb3f
commit
1f56ba98f7
@@ -4,6 +4,7 @@ import { z } from "zod";
|
|||||||
import {
|
import {
|
||||||
and,
|
and,
|
||||||
eq,
|
eq,
|
||||||
|
lt,
|
||||||
getDb,
|
getDb,
|
||||||
waitlistEntries,
|
waitlistEntries,
|
||||||
clients,
|
clients,
|
||||||
@@ -15,6 +16,19 @@ import type { AppEnv } from "../middleware/rbac.js";
|
|||||||
|
|
||||||
export const waitlistRouter = new Hono<AppEnv>();
|
export const waitlistRouter = new Hono<AppEnv>();
|
||||||
|
|
||||||
|
async function markExpiredEntries(db: ReturnType<typeof getDb>, rows: typeof waitlistEntries.$inferSelect[]) {
|
||||||
|
const today = new Date().toISOString().split("T")[0];
|
||||||
|
const expiredIds = rows
|
||||||
|
.filter((r) => r.status === "active" && r.preferredDate < today)
|
||||||
|
.map((r) => r.id);
|
||||||
|
if (expiredIds.length > 0) {
|
||||||
|
await db
|
||||||
|
.update(waitlistEntries)
|
||||||
|
.set({ status: "expired", updatedAt: new Date() })
|
||||||
|
.where(and(eq(waitlistEntries.status, "active"), lt(waitlistEntries.preferredDate, today)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const waitlistStatusEnum = z.enum(["active", "notified", "expired", "cancelled"]);
|
const waitlistStatusEnum = z.enum(["active", "notified", "expired", "cancelled"]);
|
||||||
|
|
||||||
const createWaitlistEntrySchema = z.object({
|
const createWaitlistEntrySchema = z.object({
|
||||||
@@ -51,6 +65,10 @@ waitlistRouter.get("/", async (c) => {
|
|||||||
.from(waitlistEntries)
|
.from(waitlistEntries)
|
||||||
.orderBy(waitlistEntries.createdAt);
|
.orderBy(waitlistEntries.createdAt);
|
||||||
|
|
||||||
|
await markExpiredEntries(db, rows);
|
||||||
|
|
||||||
|
const today = new Date().toISOString().split("T")[0];
|
||||||
|
|
||||||
const enriched = await Promise.all(
|
const enriched = await Promise.all(
|
||||||
rows.map(async (entry) => {
|
rows.map(async (entry) => {
|
||||||
const [client] = await db
|
const [client] = await db
|
||||||
@@ -68,8 +86,10 @@ waitlistRouter.get("/", async (c) => {
|
|||||||
.from(services)
|
.from(services)
|
||||||
.where(eq(services.id, entry.serviceId))
|
.where(eq(services.id, entry.serviceId))
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
const isExpired = entry.status === "active" && entry.preferredDate < today;
|
||||||
return {
|
return {
|
||||||
...entry,
|
...entry,
|
||||||
|
status: isExpired ? "expired" : entry.status,
|
||||||
clientName: client?.name ?? null,
|
clientName: client?.name ?? null,
|
||||||
clientEmail: client?.email ?? null,
|
clientEmail: client?.email ?? null,
|
||||||
petName: pet?.name ?? null,
|
petName: pet?.name ?? null,
|
||||||
@@ -89,7 +109,14 @@ waitlistRouter.get("/:id", async (c) => {
|
|||||||
.where(eq(waitlistEntries.id, c.req.param("id")))
|
.where(eq(waitlistEntries.id, c.req.param("id")))
|
||||||
.limit(1);
|
.limit(1);
|
||||||
if (!row) return c.json({ error: "Not found" }, 404);
|
if (!row) return c.json({ error: "Not found" }, 404);
|
||||||
return c.json(row);
|
|
||||||
|
await markExpiredEntries(db, [row]);
|
||||||
|
const today = new Date().toISOString().split("T")[0];
|
||||||
|
const isExpired = row.status === "active" && row.preferredDate < today;
|
||||||
|
return c.json({
|
||||||
|
...row,
|
||||||
|
status: isExpired ? "expired" : row.status,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
waitlistRouter.post(
|
waitlistRouter.post(
|
||||||
|
|||||||
Reference in New Issue
Block a user