fix(catalog): make the Builder Club catalog read and write its own offers
Gitea Actions Runner Test / test-job (push) Successful in 0s
CI / check (push) Successful in 28s
CI / tests-unit (push) Successful in 1m39s
CI / tests-integration (push) Successful in 1m42s
CI / tests-ui (push) Successful in 2m23s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 2m6s
Gitea Actions Runner Test / test-job (push) Successful in 0s
CI / check (push) Successful in 28s
CI / tests-unit (push) Successful in 1m39s
CI / tests-integration (push) Successful in 1m42s
CI / tests-ui (push) Successful in 2m23s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 2m6s
The previous commit taught bulk editing and delete-with-restore about the BC catalog. Neither actually worked, and one of them was destructive. `catalog_items_bc` has six columns: id, item_ids, page_id, catalog_name, order_number, extradata. There is no price, points, currency, offer_id, limit or membership column on it. The bulk path read and wrote columns that do not exist, and the UPDATE was aimed at catalog_items while the SELECT came from catalog_items_bc — so a BC category move wrote into the normal catalog. Two tests now pin that pairing: reads and writes have to stay in the same table. Underneath it the BC table was never being read at all. The inline editor fetched `/api/admin/catalog/items?pageId=N` without the catalog, so opening a BC category showed the normal catalog's offers, and the route selected BC rows directly instead of going through the loader, skipping the furni enrichment the table needs to render anything but a bare caption. Both catalogs now take the same path, and the catalog is in the fetch callback's dependencies — without that, a switch keeps reading the previous catalog's rows through a stale closure. Because a BC offer has no price, the editor no longer offers one. The server refuses price, points and currency changes with a readable message instead of letting them reach the database as an unknown-column error, and a BC bulk edit is what it can actually be: a category move. BC deletions also went through a bare DELETE, which made them the one catalog mutation with no way back. They now keep their rows and hand back a restoreId like the normal ones. The catalog is recorded in the audit target rather than in the payload, so a restore can never put a BC row into the normal offers table.
This commit is contained in:
1 parent
cebcf440c5
commit
e0efbef30d
12 files changed
+548
-218
No files matched your search
+30
-15
@@ -1,8 +1,8 @@
|
||||
"use server";
|
||||
|
||||
import { eq } from "drizzle-orm";
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { catalogFailure } from "@/features/catalog/server/errors";
|
||||
import { deleteCatalogItemsCommand } from "@/features/catalog/server/item-deletes";
|
||||
import {
|
||||
createBcOfferCommand,
|
||||
updateBcOfferCommand,
|
||||
@@ -16,7 +16,6 @@ import {
|
||||
} from "@/features/catalog/server/page-commands";
|
||||
import { sendCatalogUpdate } from "@/features/catalog/server/sync-status";
|
||||
import { requirePermission } from "@/lib/admin/guard";
|
||||
import { CatalogItemsBc, db } from "@/lib/db";
|
||||
import { PERMS } from "@/lib/permissions";
|
||||
import { withCatalogExport } from "@/lib/services/catalog-git-queue";
|
||||
import { logStaffActivity } from "@/lib/services/staff-activity";
|
||||
@@ -92,21 +91,37 @@ export async function updateBcPage({
|
||||
});
|
||||
}
|
||||
|
||||
export async function deleteBcItem({ id }: { id: number }) {
|
||||
/**
|
||||
* BC offers are deleted through the same keep-and-restore path as normal ones.
|
||||
* It used to be a bare `DELETE` here, so a BC deletion was the one catalog
|
||||
* mutation with no way back.
|
||||
*/
|
||||
export async function deleteBcItem({
|
||||
id,
|
||||
requestKey,
|
||||
}: {
|
||||
id: number;
|
||||
requestKey?: string;
|
||||
}) {
|
||||
const staff = await requirePermission(PERMS.CATALOG_EDIT);
|
||||
return await withCatalogExport(async () => {
|
||||
await db.delete(CatalogItemsBc).where(eq(CatalogItemsBc.id, id));
|
||||
await sendCatalogUpdate();
|
||||
await logStaffActivity({
|
||||
staffId: staff.id,
|
||||
action: "bc_item_delete",
|
||||
description: `Deleted BC catalog item #${id}`,
|
||||
targetType: "catalog_item_bc",
|
||||
targetId: id,
|
||||
try {
|
||||
return await withCatalogExport(async () => {
|
||||
const data: { deleted: number; restoreId: number } =
|
||||
await deleteCatalogItemsCommand([id], staff.id, requestKey, "bc");
|
||||
await sendCatalogUpdate();
|
||||
await logStaffActivity({
|
||||
staffId: staff.id,
|
||||
action: "bc_item_delete",
|
||||
description: `Deleted BC catalog offer #${id}`,
|
||||
targetType: "catalog_item_bc",
|
||||
targetId: id,
|
||||
});
|
||||
revalidatePath("/admin/catalog/builder-club");
|
||||
return { ok: true as const, data };
|
||||
});
|
||||
revalidatePath("/admin/catalog/builder-club");
|
||||
return { ok: true as const };
|
||||
});
|
||||
} catch (error) {
|
||||
return { ok: false as const, error: catalogFailure(error).message };
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateBcItem({
|
||||
|
||||
Reference in new issue
Block a user