Files
PolyMPR/routes/apps.tsx
T
djalim 9a4c6863d1 feat: stages module, mobility frontend, theme toggle, employeeOnly access control
- Add stages module with full CRUD API and admin overview island
- Add mobility overview island (Liste, Kanban, Detail CRUD views)
- Add contract PDF upload/download endpoints for mobilites
- Add light/dark theme toggle in header
- Add employeeOnly flag to hide entire modules from students (admin, students, stages)
- Add read-only GET endpoints for modules/ues/ue-modules in notes module
- Add [slug].tsx catch-all routes for direct URL navigation
- Replace old mobility table with mobilites + stages schema (migration 0004)
- Allow students to create mobilites and upload contracts
- Redirect authenticated users from / to /apps catalog
2026-05-01 12:47:23 +02:00

64 lines
1.7 KiB
TypeScript

import { FreshContext, Handlers } from "$fresh/server.ts";
import { AppProperties, State } from "$root/defaults/interfaces.ts";
import AppNavigator from "$root/routes/(_islands)/AppNavigator.tsx";
const apps: Record<string, AppProperties> = {};
export const handler: Handlers<Record<string, AppProperties>, State> = {
/**
* Generate the app catalog page from pages.
* Catalog is only computed once, then the cached version is used.
* @param _request The HTTP incomming request.
* @param context The Fresh context with `State`.
* @returns The rendered page with all apps as catalog.
*/
async GET(
_request: Request,
context: FreshContext<State, Record<string, AppProperties>>,
): Promise<Response> {
if (Object.keys(apps).length != 0) {
return context.render(apps);
}
for await (const appDir of Deno.readDir("routes/(apps)")) {
if (appDir.isFile) {
continue;
}
try {
const properties: AppProperties = (await import(
`./(apps)/${appDir.name}/(_props)/props.ts`
)).default;
apps[appDir.name] = properties;
} catch (error) {
console.error(`Couldn't import app "${appDir.name}": ${error}`);
}
}
return context.render(apps);
},
};
// deno-lint-ignore require-await
export default async function Apps(
_request: Request,
context: FreshContext<State, Record<string, AppProperties>>,
) {
let visibleApps = context.data;
if (
context.state.isAuthenticated &&
context.state.session.eduPersonPrimaryAffiliation === "student"
) {
visibleApps = Object.fromEntries(
Object.entries(context.data).filter(([_, app]) => !app.employeeOnly),
);
}
return (
<>
<AppNavigator apps={visibleApps} />
</>
);
}