74 lines
2.3 KiB
TypeScript
74 lines
2.3 KiB
TypeScript
import { json, type ActionFunctionArgs } from "@remix-run/node";
|
|
import { z } from "zod";
|
|
import {
|
|
SideMenuSectionIdSchema,
|
|
type SideMenuSectionId,
|
|
} from "~/components/navigation/sideMenuTypes";
|
|
import { updateItemOrder, updateSideMenuPreferences } from "~/services/dashboardPreferences.server";
|
|
import { requireUser } from "~/services/session.server";
|
|
|
|
// Transforms form data string "true"/"false" to boolean, or undefined if not present
|
|
const booleanFromFormData = z
|
|
.enum(["true", "false"])
|
|
.transform((val) => val === "true")
|
|
.optional();
|
|
|
|
const RequestSchema = z.object({
|
|
isCollapsed: booleanFromFormData,
|
|
sectionId: SideMenuSectionIdSchema.optional(),
|
|
sectionCollapsed: booleanFromFormData,
|
|
// Generic item order fields
|
|
organizationId: z.string().optional(),
|
|
listId: z.string().optional(),
|
|
itemOrder: z.string().optional(), // JSON-encoded string[]
|
|
});
|
|
|
|
export async function action({ request }: ActionFunctionArgs) {
|
|
const user = await requireUser(request);
|
|
|
|
const formData = await request.formData();
|
|
const rawData = Object.fromEntries(formData);
|
|
|
|
const result = RequestSchema.safeParse(rawData);
|
|
if (!result.success) {
|
|
return json({ success: false, error: "Invalid request data" }, { status: 400 });
|
|
}
|
|
|
|
// Handle item order update
|
|
if (result.data.organizationId && result.data.listId && result.data.itemOrder) {
|
|
let parsed: unknown;
|
|
try {
|
|
parsed = JSON.parse(result.data.itemOrder);
|
|
} catch {
|
|
parsed = [];
|
|
}
|
|
const orderResult = z.array(z.string()).safeParse(parsed);
|
|
if (orderResult.success) {
|
|
await updateItemOrder({
|
|
user,
|
|
organizationId: result.data.organizationId,
|
|
listId: result.data.listId,
|
|
order: orderResult.data,
|
|
});
|
|
}
|
|
return json({ success: true });
|
|
}
|
|
|
|
// Build sectionCollapsed parameter if both sectionId and sectionCollapsed are provided
|
|
const sectionCollapsed =
|
|
result.data.sectionId !== undefined && result.data.sectionCollapsed !== undefined
|
|
? {
|
|
sectionId: result.data.sectionId as SideMenuSectionId,
|
|
collapsed: result.data.sectionCollapsed,
|
|
}
|
|
: undefined;
|
|
|
|
await updateSideMenuPreferences({
|
|
user,
|
|
isCollapsed: result.data.isCollapsed,
|
|
sectionCollapsed,
|
|
});
|
|
|
|
return json({ success: true });
|
|
}
|