import { PERMS } from "@/lib/permission-slugs"; import { anyCapability, type CanonicalHousekeepingHref, type HousekeepingRouteDefinition, } from "../../foundation/contracts"; import { HOTEL_ASSET_QUERY_OWNERSHIP } from "./queries/assets"; export const HOTEL_ROUTE_GROUPS = ["rooms", "navigation", "radio"] as const; export type HotelRouteGroup = (typeof HOTEL_ROUTE_GROUPS)[number]; export const HOTEL_PRIMARY_ROUTE_IDS = [ "hotel.rooms", "hotel.room-detail", "hotel.room-furni", "hotel.navigation", "hotel.radio.overview", "hotel.radio.settings", "hotel.radio.monitoring", "hotel.radio.moderation", "hotel.radio.autodj", "hotel.radio.history", "hotel.radio.points", "hotel.radio.ranks", "hotel.radio.api-keys", "hotel.radio.banners", "hotel.radio.embed", ] as const; export type HotelPrimaryRouteId = (typeof HOTEL_PRIMARY_ROUTE_IDS)[number]; export const HOTEL_STUDIO_ROUTE_IDS = [ "hotel.studio.audit", "hotel.studio.badges", "hotel.studio.clone", "hotel.studio.clothing", "hotel.studio.effects", "hotel.studio.furni", "hotel.studio.maintenance", "hotel.studio.pets", "hotel.studio.repair-icons", "hotel.studio.sync", "hotel.studio.upload", ] as const; export type HotelStudioRouteId = (typeof HOTEL_STUDIO_ROUTE_IDS)[number]; export type HotelRouteId = HotelPrimaryRouteId | HotelStudioRouteId; export const HOTEL_STUDIO_OPERATION_BY_ROUTE = Object.freeze({ "hotel.studio.badges": "badge", "hotel.studio.clone": "clone", "hotel.studio.clothing": "clothing", "hotel.studio.effects": "effect", "hotel.studio.furni": "furni", "hotel.studio.maintenance": "maintenance", "hotel.studio.pets": "pet", "hotel.studio.repair-icons": "repair-icons", "hotel.studio.sync": "sync", "hotel.studio.upload": "upload", } as const); function route( id: Id, href: CanonicalHousekeepingHref, permissions: readonly string[], ): HousekeepingRouteDefinition & { readonly id: Id } { return routeDefinition(id, href, permissions); } export const HOTEL_PRIMARY_ROUTES = [ route("hotel.rooms", "/ase-next/hotel/rooms", [PERMS.ROOMS_VIEW]), route("hotel.room-detail", "/ase-next/hotel/rooms/:id", [ PERMS.ROOMS_VIEW, PERMS.ROOMS_EDIT, ]), route("hotel.room-furni", "/ase-next/hotel/rooms/:id/furni", [ PERMS.ROOMS_VIEW, PERMS.ROOMS_EDIT, ]), route("hotel.navigation", "/ase-next/hotel/navigation", [PERMS.PAGES_VIEW]), ...( [ ["hotel.radio.overview", "/ase-next/hotel/radio/overview"], ["hotel.radio.settings", "/ase-next/hotel/radio/settings"], ["hotel.radio.monitoring", "/ase-next/hotel/radio/monitoring"], ["hotel.radio.moderation", "/ase-next/hotel/radio/moderation"], ["hotel.radio.autodj", "/ase-next/hotel/radio/autodj"], ["hotel.radio.history", "/ase-next/hotel/radio/history"], ["hotel.radio.points", "/ase-next/hotel/radio/points"], ["hotel.radio.ranks", "/ase-next/hotel/radio/ranks"], ["hotel.radio.api-keys", "/ase-next/hotel/radio/api-keys"], ["hotel.radio.banners", "/ase-next/hotel/radio/banners"], ["hotel.radio.embed", "/ase-next/hotel/radio/embed"], ] as const ).map(([id, href]) => route(id, href, [PERMS.RADIO_VIEW])), ] as const satisfies readonly HousekeepingRouteDefinition[]; function studioRoute( id: Id, href: CanonicalHousekeepingHref, ): HousekeepingRouteDefinition & { readonly id: Id } { return routeDefinition( id, href, id === "hotel.studio.maintenance" ? [PERMS.CATALOG_EDIT] : [PERMS.ASSETS_IMPORT], ); } function routeDefinition( id: Id, href: CanonicalHousekeepingHref, permissions: readonly string[], ): HousekeepingRouteDefinition & { readonly id: Id } { return { id, href, labelKey: `pages.housekeeping.routes.${id}`, capability: anyCapability(...permissions), }; } export const HOTEL_STUDIO_ROUTES = [ studioRoute("hotel.studio.audit", "/ase-next/hotel/studio/audit"), studioRoute("hotel.studio.badges", "/ase-next/hotel/studio/badges"), studioRoute("hotel.studio.clone", "/ase-next/hotel/studio/clone"), studioRoute("hotel.studio.clothing", "/ase-next/hotel/studio/clothing"), studioRoute("hotel.studio.effects", "/ase-next/hotel/studio/effects"), studioRoute("hotel.studio.furni", "/ase-next/hotel/studio/furni"), studioRoute("hotel.studio.maintenance", "/ase-next/hotel/studio/maintenance"), studioRoute("hotel.studio.pets", "/ase-next/hotel/studio/pets"), studioRoute( "hotel.studio.repair-icons", "/ase-next/hotel/studio/repair-icons", ), studioRoute("hotel.studio.sync", "/ase-next/hotel/studio/sync"), studioRoute("hotel.studio.upload", "/ase-next/hotel/studio/upload"), ] as const satisfies readonly HousekeepingRouteDefinition[]; export const HOTEL_ROUTE_IDS = [ ...HOTEL_PRIMARY_ROUTE_IDS, ...HOTEL_STUDIO_ROUTE_IDS, ] as const; export const HOTEL_ROUTES = [ ...HOTEL_PRIMARY_ROUTES, ...HOTEL_STUDIO_ROUTES, ] as const satisfies readonly HousekeepingRouteDefinition[]; const ROUTE_BY_ID = new Map( HOTEL_ROUTES.map((definition) => [definition.id, definition]), ); export function hotelRouteById(id: HotelRouteId): HousekeepingRouteDefinition { const definition = ROUTE_BY_ID.get(id); if (!definition) throw new Error(`unknown Hotel route: ${id}`); return definition; } export function hotelStudioOperationKind(id: HotelStudioRouteId) { if (id === "hotel.studio.audit") return null; return HOTEL_STUDIO_OPERATION_BY_ROUTE[id]; } export function hotelRouteGroup(id: HotelPrimaryRouteId): HotelRouteGroup { if (id === "hotel.navigation") return "navigation"; return id.startsWith("hotel.radio.") ? "radio" : "rooms"; } export const HOTEL_ASSET_CANONICAL_ROUTES = Object.freeze([ Object.freeze({ legacyPath: "/admin/badges", routeId: HOTEL_ASSET_QUERY_OWNERSHIP.badges, href: "/ase-next/economy/rewards/badges", }), Object.freeze({ legacyPath: "/admin/sounds", routeId: HOTEL_ASSET_QUERY_OWNERSHIP.sounds, href: "/ase-next/economy/rewards/sounds", }), ] as const);