Rebuild KPIs as a real dashboard (period deltas, tenant zoom), clarify objetivos/calendario/activos sources, and turn creatives into a status pipeline with delete. Co-authored-by: Cursor <cursoragent@cursor.com>
71 lines
1.8 KiB
TypeScript
71 lines
1.8 KiB
TypeScript
import { cookies } from 'next/headers';
|
|
import {
|
|
VIEW_TENANT_COOKIE,
|
|
VIEW_TENANT_NAME_COOKIE,
|
|
homeTenantId,
|
|
isAgencyRole,
|
|
serviceHeaders,
|
|
supabaseUrl,
|
|
userRole,
|
|
} from '@/lib/agency';
|
|
|
|
export type ResolvedTenant = {
|
|
tenantId: string | null;
|
|
/** true = agency zoomed into one client */
|
|
viaView: boolean;
|
|
/** true = agency with no client selected → all tenants */
|
|
portfolioWide: boolean;
|
|
label: string;
|
|
};
|
|
|
|
export async function resolveActiveTenant(user: {
|
|
app_metadata?: Record<string, unknown>;
|
|
user_metadata?: Record<string, unknown>;
|
|
} | null): Promise<ResolvedTenant> {
|
|
const role = userRole(user);
|
|
const cookieStore = await cookies();
|
|
const viewId = cookieStore.get(VIEW_TENANT_COOKIE)?.value || null;
|
|
const viewName = cookieStore.get(VIEW_TENANT_NAME_COOKIE)?.value || null;
|
|
|
|
if (isAgencyRole(role) && viewId) {
|
|
return {
|
|
tenantId: viewId,
|
|
viaView: true,
|
|
portfolioWide: false,
|
|
label: viewName || 'Cliente',
|
|
};
|
|
}
|
|
if (isAgencyRole(role) && !viewId) {
|
|
return {
|
|
tenantId: null,
|
|
viaView: false,
|
|
portfolioWide: true,
|
|
label: 'Portafolio (todos los clientes)',
|
|
};
|
|
}
|
|
return {
|
|
tenantId: homeTenantId(user),
|
|
viaView: false,
|
|
portfolioWide: false,
|
|
label:
|
|
(user?.user_metadata?.company as string) ||
|
|
(user?.app_metadata?.company as string) ||
|
|
'Cliente',
|
|
};
|
|
}
|
|
|
|
export async function restGet<T = unknown>(
|
|
path: string
|
|
): Promise<{ ok: boolean; data: T | null; error?: string }> {
|
|
const headers = serviceHeaders();
|
|
if (!headers) return { ok: false, data: null, error: 'no service role' };
|
|
const r = await fetch(`${supabaseUrl()}${path}`, {
|
|
headers,
|
|
cache: 'no-store',
|
|
});
|
|
if (!r.ok) {
|
|
return { ok: false, data: null, error: await r.text() };
|
|
}
|
|
return { ok: true, data: (await r.json()) as T };
|
|
}
|