0ac4beaaa8
- Add requireAuth() to admin-permissions.ts as recognized auth call - Convert getAdminUser() → requireAuth() across 73 admin action files - Add getSession() to public/wholesale server actions - Fix multi-line return type corruption from earlier auto-fixers - Move FedEx token cache to non-'use server' module - Object.freeze module-level constants: PRICE_KEYS, EMPTY_MOBILE_DASHBOARD, EMPTY_PAY_PERIOD, LOCALE_CART_SUBJECT, WELCOME_EMAILS - Update Stripe API version 2026-05-27 → 2026-06-24 - Fix wholesale employee portal: getEmployeeSessionAction + EmployeePortalClient - Fix 51 TypeScript errors (return type corruption, missing imports)
81 lines
2.5 KiB
TypeScript
81 lines
2.5 KiB
TypeScript
"use server";
|
|
|
|
/**
|
|
* Assign / unassign a product to a stop.
|
|
*
|
|
* TODO(migration): the `assign_product_to_stop` and
|
|
* `unassign_product_from_stop` SECURITY DEFINER RPCs (originally from
|
|
* the now-archived supabase migrations; consolidated into
|
|
* `db/migrations/0001_init.sql`). The RPCs still exist in the
|
|
* database and are called via `pool.query`. When stops/products are
|
|
* re-platformed on the SaaS rebuild, replace these with direct
|
|
* inserts/deletes on the new `db/schema/stops.ts` `stopProducts`
|
|
* table.
|
|
*/
|
|
|
|
import { getAdminUser } from "@/lib/admin-permissions";
|
|
import { pool } from "@/lib/db";
|
|
import { getSession } from "@/lib/auth";
|
|
|
|
export type AssignProductResult =
|
|
| { success: true; id: string }
|
|
| { success: false; error: string };
|
|
|
|
export type UnassignProductResult =
|
|
| { success: true }
|
|
| { success: false; error: string };
|
|
|
|
export async function assignProductToStop(params: {
|
|
stopId: string;
|
|
productId: string;
|
|
}): Promise<AssignProductResult> {
|
|
|
|
await getSession(); const adminUser = await getAdminUser();
|
|
if (!adminUser) return { success: false, error: "Not authenticated" };
|
|
if (!adminUser.can_manage_products && !adminUser.can_manage_orders) {
|
|
return { success: false, error: "Not authorized" };
|
|
}
|
|
|
|
try {
|
|
const { rows } = await pool.query<{ id: string; success?: boolean; error?: string }>(
|
|
"SELECT * FROM assign_product_to_stop($1::uuid, $2::uuid, $3::text)",
|
|
[params.stopId, params.productId, adminUser.user_id]
|
|
);
|
|
const data = rows[0];
|
|
if (!data?.id) {
|
|
return { success: false, error: data?.error ?? "Failed to assign product to stop" };
|
|
}
|
|
return { success: true, id: data.id };
|
|
} catch (err) {
|
|
return {
|
|
success: false,
|
|
error: err instanceof Error ? err.message : "Failed to assign product to stop",
|
|
};
|
|
}
|
|
}
|
|
|
|
export async function unassignProductFromStop(params: {
|
|
stopId: string;
|
|
productId: string;
|
|
}): Promise<UnassignProductResult> {
|
|
|
|
await getSession(); const adminUser = await getAdminUser();
|
|
if (!adminUser) return { success: false, error: "Not authenticated" };
|
|
if (!adminUser.can_manage_products && !adminUser.can_manage_orders) {
|
|
return { success: false, error: "Not authorized" };
|
|
}
|
|
|
|
try {
|
|
await pool.query(
|
|
"SELECT * FROM unassign_product_from_stop($1::uuid, $2::uuid, $3::text)",
|
|
[params.stopId, params.productId, adminUser.user_id]
|
|
);
|
|
return { success: true };
|
|
} catch (err) {
|
|
return {
|
|
success: false,
|
|
error: err instanceof Error ? err.message : "Failed to unassign product from stop",
|
|
};
|
|
}
|
|
}
|