98 lines
2.8 KiB
TypeScript
98 lines
2.8 KiB
TypeScript
// Path: Frontend/src/components/app-shell/data/app-shell.context.tsx
|
|
|
|
import {
|
|
createContext,
|
|
createMemo,
|
|
createSignal,
|
|
onMount,
|
|
useContext,
|
|
type JSX,
|
|
} from "solid-js";
|
|
import { resolveAPIBase } from "../../../lib/api";
|
|
import {
|
|
buildActiveDepartment,
|
|
buildActiveProject,
|
|
buildActiveServer,
|
|
buildActiveUserProfile,
|
|
buildDepartmentItems,
|
|
buildProjectItems,
|
|
buildRailItems,
|
|
buildWorkspaceTree,
|
|
} from "./app-shell.builders";
|
|
import type { AppShellContextValue, AppShellPayload } from "./app-shell.types";
|
|
import { normalizeAppShellPayload } from "./app-shell.types";
|
|
|
|
const AppShellContext = createContext<AppShellContextValue>();
|
|
|
|
export const AppShellDataProvider = (props: { children: JSX.Element }): JSX.Element => {
|
|
const [status, setStatus] = createSignal<"idle" | "loading" | "success" | "error">("idle");
|
|
const [error, setError] = createSignal("");
|
|
const [payload, setPayload] = createSignal<AppShellPayload | null>(null);
|
|
|
|
const load = async (): Promise<void> => {
|
|
setStatus("loading");
|
|
setError("");
|
|
|
|
try {
|
|
const response = await fetch(`${resolveAPIBase()}/app-shell`, {
|
|
headers: {
|
|
Accept: "application/json",
|
|
},
|
|
});
|
|
|
|
const body = (await response.json()) as {
|
|
data?: AppShellPayload;
|
|
error?: { message?: string } | string;
|
|
message?: string;
|
|
};
|
|
const errorMessage =
|
|
typeof body.message === "string"
|
|
? body.message
|
|
: typeof body.error === "string"
|
|
? body.error
|
|
: body.error?.message;
|
|
|
|
if (!response.ok || !body.data) {
|
|
throw new Error(errorMessage || "Failed to load app shell state.");
|
|
}
|
|
|
|
setPayload(normalizeAppShellPayload(body.data));
|
|
setStatus("success");
|
|
} catch (loadError) {
|
|
setStatus("error");
|
|
setError(loadError instanceof Error ? loadError.message : "Failed to load app shell state.");
|
|
}
|
|
};
|
|
|
|
onMount(() => {
|
|
void load();
|
|
});
|
|
|
|
const value: AppShellContextValue = {
|
|
status,
|
|
error,
|
|
installation: createMemo(() => payload()?.installation),
|
|
railItems: createMemo(() => buildRailItems(payload())),
|
|
activeServer: createMemo(() => buildActiveServer(payload())),
|
|
activeProject: createMemo(() => buildActiveProject(payload())),
|
|
activeDepartment: createMemo(() => buildActiveDepartment(payload())),
|
|
projectItems: createMemo(() => buildProjectItems(payload())),
|
|
departmentItems: createMemo(() => buildDepartmentItems(payload())),
|
|
workspaceTree: createMemo(() => buildWorkspaceTree(payload())),
|
|
activeUserProfile: createMemo(() => buildActiveUserProfile(payload())),
|
|
reload: load,
|
|
};
|
|
|
|
return <AppShellContext.Provider value={value}>{props.children}</AppShellContext.Provider>;
|
|
};
|
|
|
|
export const useAppShellData = (): AppShellContextValue => {
|
|
const context = useContext(AppShellContext);
|
|
|
|
if (!context) {
|
|
throw new Error("useAppShellData must be used within AppShellDataProvider");
|
|
}
|
|
|
|
return context;
|
|
};
|