Files
HiveGrid-Wireframes/03 Quellen und Referenzen/hivegrid-cloud/apps/web/app/routeModules/admin/select-tenant.impl.ts
T
2026-07-08 16:15:37 +02:00

88 lines
3.2 KiB
TypeScript

import { redirect, type ActionFunctionArgs, type LoaderFunctionArgs } from "react-router";
import { loadRequiredWebConfig } from "@hivegrid/config";
import { buildSelectTenantVM, type SelectTenantData } from "@hivegrid/view-models";
import type { VMState } from "@hivegrid/view-models";
import { getTranslations } from "~/locale/i18next.server";
import { absoluteAppPath } from "~/utils/app/CrossHostUrls";
import { adminGetAllActiveTenantSimple } from "~/utils/db/tenants.db.server";
import { verifyUserHasPermission } from "~/utils/helpers/.server/PermissionsService";
import { getUserInfo, validateCSRFToken } from "~/utils/session.server";
type AdminSelectTenantVM = VMState<SelectTenantData>;
export type AdminSelectTenantLoaderData = {
title: string;
vm: AdminSelectTenantVM;
copy: {
titleKey: string;
subtitleKey: string;
infoTooltipKey: string;
searchPlaceholderKey: string;
emptyKey: string;
noResultsKey: string;
sectionLabelKey: string;
};
showCreateAction: false;
};
export type AdminSelectTenantActionData = {
error?: string;
};
const copy: AdminSelectTenantLoaderData["copy"] = {
titleKey: "admin.selectTenant.title",
subtitleKey: "admin.selectTenant.subtitle",
infoTooltipKey: "admin.selectTenant.infoTooltip",
searchPlaceholderKey: "admin.selectTenant.searchPlaceholder",
emptyKey: "admin.selectTenant.empty",
noResultsKey: "admin.selectTenant.noResults",
sectionLabelKey: "admin.selectTenant.sectionLabel",
};
async function requireAdminTenantSwitchAccess(request: Request) {
const userInfo = await getUserInfo(request);
if (!userInfo.userId) {
throw redirect("/login");
}
await verifyUserHasPermission(request, "admin.accounts.view");
return userInfo;
}
export async function loader({ request }: LoaderFunctionArgs) {
await requireAdminTenantSwitchAccess(request);
const { t } = await getTranslations(request);
const tenants = await adminGetAllActiveTenantSimple();
const vm = buildSelectTenantVM({
tenants: tenants.map((tenant) => ({
id: tenant.id,
name: tenant.name,
slug: tenant.slug,
image: tenant.icon ?? tenant.logo ?? null,
role: null,
subtitle: null,
})),
});
return Response.json({
title: t("admin.selectTenant.title"),
vm,
copy,
showCreateAction: false,
} satisfies AdminSelectTenantLoaderData);
}
export async function action({ request }: ActionFunctionArgs) {
await requireAdminTenantSwitchAccess(request);
const form = await request.formData();
await validateCSRFToken(request, { formData: form });
const tenantId = String(form.get("tenantId") ?? "");
const slug = String(form.get("slug") ?? "");
if (!tenantId || !slug) {
return Response.json({ error: "admin.selectTenant.errors.invalidSelection" } satisfies AdminSelectTenantActionData, { status: 400 });
}
const tenant = (await adminGetAllActiveTenantSimple()).find((candidate) => candidate.id === tenantId);
if (!tenant || tenant.slug !== slug) {
return Response.json({ error: "admin.selectTenant.errors.invalidSelection" } satisfies AdminSelectTenantActionData, { status: 400 });
}
throw redirect(absoluteAppPath(loadRequiredWebConfig().routing, tenant.slug, "dashboard"));
}