Files
Calendar_Frontend/lib/env.ts
PaddyandClaude Opus 5.5 0cda40f85e Rewrite the calendar frontend in Next.js
Replaces the Angular 18 app with Next.js 16 / React 19 / Tailwind 4 / shadcn,
the same stack and design system as nachklang-feedback, planned in
docs/rewrite-plan.md.

- Admin: all calendars in one mobile-friendly list (month groups, calendar
  chips, Kommend/Vergangen/Alle, search, sort, filters in the URL), an edit
  sheet for create/edit/duplicate/delete, publish confirmation, and an
  "Abonnieren" dialog with subscription links for every calendar.
- Public landing page: subscribe links from env instead of hardcoded, plus
  the next public events, server-rendered and revalidated every 5 minutes.
- All times handled explicitly as Europe/Berlin; whole-day events stored as
  00:00-23:59. Fixes carried over from the Angular app: the move dialog
  leaking a cancelled calendar change, saves that looked saved when they
  failed, in-place Date mutation, and duplicated calendar-id mappings.
- Same shared-session auth as before (proxy.ts gate, /admin/me, 401 vs 403).
- 112 Vitest tests over lib/; docs in docs/ (architecture, features,
  gotchas, API wish list, deployment).

Needs the API branch feature/calendar-ical-escaping-subscriptions deployed
first (GET /calendar/events/subscriptions).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:15:59 +02:00

28 lines
1.3 KiB
TypeScript

/**
* The `NEXT_PUBLIC_*` values this app needs, read once and validated here
* rather than defaulted at each use site. Mirrors `lib/env.ts` in
* nachklang-feedback, nachklang-admin and nachklang-tickets.
*
* Throwing is the whole point. Next inlines `process.env.NEXT_PUBLIC_*` at
* **build** time, so a value missing when Plesk runs `npm run build` is baked
* into the bundle and cannot be fixed by restarting the app. A fallback to
* localhost would ship an admin area that sends every signed-out user to
* `http://localhost:3002` - no error, no log, just a dead end. A failed build is
* the better outcome, on the machine that can still do something about it.
*
* Referenced by their full literal name because that is what the inlining
* matches - no dynamic lookup, no destructuring of `process.env`.
*/
function requireEnv(name: string, value: string | undefined): string {
if (!value) {
throw new Error(`${name} is not set. Copy .env.local.example and fill it in before building.`);
}
// URL.origin never carries a trailing slash, and neither should anything we concatenate onto.
return value.replace(/\/+$/, "");
}
export const API_BASE_URL = requireEnv("NEXT_PUBLIC_API_BASE_URL", process.env.NEXT_PUBLIC_API_BASE_URL);
export const ADMIN_APP_URL = requireEnv("NEXT_PUBLIC_ADMIN_APP_URL", process.env.NEXT_PUBLIC_ADMIN_APP_URL);