feat(frontend): app do tenant, dashboard ao vivo, fluxo de login multi-tenant
Corrige um gap real: o login sempre mandava pra /platform mesmo pra usuarios sem role de plataforma, sem nunca chamar /auth/tenants ou select-tenant. Agora POST /api/post-login decide o destino server-side (plataforma / tenant unico / seletor com >1 tenant) antes de redirecionar, trocando o access token quando necessario sem nunca expor token ao client. Adiciona GET /reports/dashboard (secao 162) e a tela /app correspondente — chamadas/agentes/TME/TMA/rates ao vivo, "consumo do plano" e "valor estimado" seguindo a mesma disciplina de honestidade (null > numero inventado) do dashboard de plataforma. Shell (sidebar/topbar/drawer mobile) extraido pra components/shell, compartilhado entre os menus Platform e Tenant (secao 168-169) via wrappers client-only por area — corrige de quebra um erro real de serializacao RSC (passar NavSection[] com icones como prop de Server Component pra Client Component quebra: "Functions cannot be passed directly to Client Components"). Testado ponta a ponta com um tenant semeado (Acme Call Center): login → /app direto, platform admin barrado de /app e vice-versa, dashboard com numeros reais (zeros honestos), drawer mobile, dark mode. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EWHKmcVJtstQFErbZ1AanY
This commit is contained in:
29
apps/frontend/src/app/select-tenant/page.tsx
Normal file
29
apps/frontend/src/app/select-tenant/page.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import Image from "next/image";
|
||||
import { requireSession } from "@/lib/session";
|
||||
import { apiFetch } from "@/lib/api";
|
||||
import { TenantPicker } from "./picker";
|
||||
|
||||
interface TenantOption {
|
||||
tenantId: string;
|
||||
code: string;
|
||||
name: string;
|
||||
status: string;
|
||||
}
|
||||
|
||||
export default async function SelectTenantPage() {
|
||||
const session = await requireSession();
|
||||
const tenants = await apiFetch<TenantOption[]>("/auth/tenants", session.accessToken);
|
||||
|
||||
return (
|
||||
<div className="flex min-h-dvh flex-col items-center justify-center bg-background px-6 py-12">
|
||||
<div className="w-full max-w-sm">
|
||||
<Image src="/branding/b2blogo.png" alt="B2BCall" width={140} height={34} priority className="mx-auto mb-8" />
|
||||
<h1 className="text-center text-lg font-semibold text-foreground">Qual conta você quer acessar?</h1>
|
||||
<p className="mt-1 text-center text-sm text-muted-foreground">Sua conta tem acesso a mais de um tenant.</p>
|
||||
<div className="mt-6">
|
||||
<TenantPicker tenants={tenants} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user