feat(housekeeping): deliver system vertical

This commit is contained in:
Simo committed 2026-08-28 23:31:47 +02:00
1 parent 0117b45d74
commit 3788ecd9f1
33 files changed
+4548 -423

No files matched your search

+29 -30
View File
@@ -1,10 +1,11 @@
"use server";
import { revalidatePath } from "next/cache";
import { systemMutationService } from "@/features/housekeeping/domains/system/services/mutations";
import { createHousekeepingCapabilityContext } from "@/features/housekeeping/foundation/capability-context";
import { createCorrelationId } from "@/features/housekeeping/foundation/correlation";
import { requirePermission } from "@/lib/admin/guard";
import { db, WebsiteSetting } from "@/lib/db";
import { PERMS } from "@/lib/permissions";
import { siteSettings } from "@/lib/services/site-settings";
// Maintenance mode lives in three CMS-owned website_settings rows (mirrors
// AtomCMS's MaintenanceToggle Livewire component):
@@ -14,32 +15,25 @@ import { siteSettings } from "@/lib/services/site-settings";
// The Laravel login flow reads these via setting() to gate non-staff logins
// while maintenance is on, so the website_settings keys are the source of truth.
const KEY_ENABLED = "maintenance_enabled";
const KEY_MESSAGE = "maintenance_message";
const KEY_MIN_RANK = "min_maintenance_login_rank";
const COMMENTS: Record<string, string> = {
[KEY_ENABLED]: "Determines whether maintenance is enabled or not",
[KEY_MESSAGE]:
"The maintenance message displayed to users while maintenance is activated",
[KEY_MIN_RANK]:
"The minimum rank required to login to the hotel during maintenance",
};
async function upsertSetting(key: string, value: string): Promise<void> {
await db
.insert(WebsiteSetting)
.values({
key,
value,
// eslint-disable-next-line security/detect-object-injection -- key is one of 3 known const values
comment: COMMENTS[key] ?? null,
})
.onDuplicateKeyUpdate({ set: { value } });
function mutationContext(staff: {
id: number;
rank: number;
username: string;
}) {
const matches = (slug: string) => slug === PERMS.SETTINGS_EDIT;
return {
capability: createHousekeepingCapabilityContext(staff, {
isSuperAdmin: false,
has: matches,
hasAny: (...slugs: string[]) => slugs.some(matches),
hasAll: (...slugs: string[]) => slugs.every(matches),
}),
correlationId: createCorrelationId(),
};
}
export async function saveMaintenance(formData: FormData): Promise<void> {
await requirePermission(PERMS.SETTINGS_EDIT);
const staff = await requirePermission(PERMS.SETTINGS_EDIT);
// Checkbox: present only when ticked. Normalise to the '1'/'0' string the
// emulator/Laravel side expects.
@@ -56,10 +50,15 @@ export async function saveMaintenance(formData: FormData): Promise<void> {
const minRank =
Number.isFinite(parsedRank) && parsedRank >= 0 ? parsedRank : 5;
await upsertSetting(KEY_ENABLED, enabled);
await upsertSetting(KEY_MESSAGE, message);
await upsertSetting(KEY_MIN_RANK, String(minRank));
siteSettings.reload();
const result = await systemMutationService.execute(
mutationContext(staff),
"operations.maintenance.update",
{
enabled: enabled === "1",
message,
minimumLoginRank: minRank,
},
);
if (!result.ok) throw new Error(result.error.messageKey);
revalidatePath("/admin/maintenance");
}