// Copyright: © 2026 TWWIM UG. All rights reserved. (www.twwim.com) /** * /dashboard/plugin-settings — top-level Widget Configuration route. * * Mirrors the Knowledge pattern: a single canonical surface for editing * plugin settings, reachable via the sidebar AND from per-tenant deep links * (TenantsList / TenantDetail Megaphone buttons forward here with * ?tenantId=). Resolves the active tenant from the URL search param, or * falls back to the first available tenant in the company. */ import { useEffect, useMemo } from 'react'; import { createFileRoute, useNavigate, Link } from '@tanstack/react-router'; import { z } from 'zod'; import { Globe, Megaphone } from 'lucide-react'; import { PageLayout } from '@/components/shared'; import { PluginSettingsPage } from '@/features/plugin-settings/PluginSettingsPage'; import { useTenants } from '@/features/tenants/hooks'; import { useTranslation } from '@/i18n/TranslationProvider'; import type { TFunction } from '@/features/plugin-settings/lib/constants'; import type { Tenant } from '@/domain/entities'; import { CPZone } from '@archer/domain'; import { requireZone } from '@/presentation/guards/requireZone'; const pluginSettingsSearchSchema = z.object({ tenantId: z.string().uuid().optional().catch(undefined), }); function EmptyTenantsCard({ t }: { t: TFunction }) { return (

{t('knowledge.noTenantsTitle')}

{t('knowledge.noTenantsHint')}

{t('knowledge.goToTenants')}
); } interface TenantSelectorBarProps { tenants: Tenant[]; activeTenant: Tenant; onChange: (nextTenantId: string) => void; t: TFunction; } function TenantSelectorBar({ tenants, activeTenant, onChange, t }: TenantSelectorBarProps) { return (
{activeTenant.domain} {activeTenant.status}
); } function LoadingSkeleton() { return (
); } function PluginSettingsRoute() { const { tenantId } = Route.useSearch(); const navigate = useNavigate(); const { t } = useTranslation(); const tenantsQuery = useTenants(); const tenants = useMemo( () => tenantsQuery.data?.tenants ?? [], [tenantsQuery.data?.tenants], ); const resolvedTenantId = useMemo(() => { if (tenantId && tenants.some((tenant) => tenant.id === tenantId)) return tenantId; return tenants[0]?.id; }, [tenantId, tenants]); useEffect(() => { if (resolvedTenantId && resolvedTenantId !== tenantId) { navigate({ to: '/dashboard/plugin-settings', search: { tenantId: resolvedTenantId }, replace: true, }); } }, [resolvedTenantId, tenantId, navigate]); const activeTenant = tenants.find((tenant) => tenant.id === resolvedTenantId); const hasNoTenants = !tenantsQuery.isLoading && tenants.length === 0; const switchTenant = (nextTenantId: string) => { navigate({ to: '/dashboard/plugin-settings', search: { tenantId: nextTenantId }, replace: true, }); }; return ( } gradient={true} > {hasNoTenants ? ( ) : resolvedTenantId && activeTenant ? ( <> ) : ( )} ); } export const Route = createFileRoute('/_authenticated/dashboard/plugin-settings')({ validateSearch: pluginSettingsSearchSchema, beforeLoad: () => requireZone(CPZone.WIDGET_CONFIG), component: PluginSettingsRoute, });