nxtgauge-frontend-solid/src/routes/workspace.tsx

83 lines
3.2 KiB
TypeScript
Raw Normal View History

import { createSignal, createResource, Show, For } from 'solid-js';
import { A, useSearchParams } from '@solidjs/router';
import ProfileWidget from '~/components/dashboard/ProfileWidget';
async function fetchRuntimeConfig(roleKey: string) {
const RUST_API_URL = import.meta.env.VITE_RUST_API_URL || 'http://localhost:8080';
// Try to lookup Role ID first
const roleRes = await fetch(`${RUST_API_URL}/api/admin/roles/${roleKey}`);
if (!roleRes.ok) throw new Error("Role not found");
const role = await roleRes.json();
// Then fetch Dashboard config for that role
const configRes = await fetch(`${RUST_API_URL}/api/admin/dashboard-config/${role.id}?audience=EXTERNAL`);
if (!configRes.ok) throw new Error("Dashboard config not found");
const dashboardConfig = await configRes.json();
return dashboardConfig.config_json; // Returns `{ sidebar: [...], widgets: [...] }`
}
export default function WorkspaceLayout(props: { children?: any }) {
const [searchParams] = useSearchParams();
const rawRoleKey = searchParams.roleKey;
const roleKey = () => (Array.isArray(rawRoleKey) ? rawRoleKey[0] : rawRoleKey) || 'PHOTOGRAPHER';
const [config] = createResource<any, string>(roleKey, fetchRuntimeConfig);
return (
<div class="min-h-screen bg-slate-50 flex">
{/* Sidebar rendered magically from Rust Config */}
<aside class="w-64 bg-white border-r border-slate-200 flex flex-col">
<div class="p-6 border-b border-slate-200">
<h1 class="font-bold text-xl text-orange-600">Nxtgauge Workspace</h1>
<p class="text-xs text-slate-500 mt-1 capitalize">{roleKey().toLowerCase()}</p>
</div>
<nav class="flex-1 p-4 space-y-1">
<Show when={config.loading}>
<p class="text-sm text-slate-500">Loading modules...</p>
</Show>
<Show when={config.error}>
<p class="text-sm text-red-500">Failed to load shell config.</p>
</Show>
<Show when={config()}>
<For each={config().sidebar}>
{(item: any) => (
<A
href={item.route}
class="block px-4 py-2 rounded-lg text-slate-700 hover:bg-orange-50 hover:text-orange-600 transition-colors"
>
{item.label}
</A>
)}
</For>
</Show>
</nav>
</aside>
{/* Main Content Area */}
<main class="flex-1 p-8">
<Show when={config() && config().widgets}>
<div class="grid grid-cols-2 gap-6 mb-8">
<For each={config().widgets}>
{(widget: any) => (
<Show when={widget.enabled}>
<div class="bg-white p-6 rounded-xl border border-slate-200 shadow-sm">
<h3 class="font-medium text-slate-800">{widget.title}</h3>
<p class="text-xs text-slate-400 mt-2">Dynamic Widget Module</p>
</div>
</Show>
)}
</For>
</div>
</Show>
{/* Profile Settings specifically for this Role */}
<ProfileWidget roleKey={roleKey()} />
{props.children}
</main>
</div>
);
}