diff --git a/package.json b/package.json index ef332d8..5ce9e5b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "abgeordnetenwatch-pwa", - "version": "2026.03.10", + "version": "2026.03.10.1", "type": "module", "scripts": { "dev": "vite", diff --git a/src/client/features/settings/components/settings-page.tsx b/src/client/features/settings/components/settings-page.tsx index a70dc8e..c13d587 100644 --- a/src/client/features/settings/components/settings-page.tsx +++ b/src/client/features/settings/components/settings-page.tsx @@ -10,6 +10,7 @@ import { fetchTopics } from "@/shared/lib/aw-api" import { APP_VERSION, BACKEND_URL, + STORAGE_KEYS, VAPID_PUBLIC_KEY, } from "@/shared/lib/constants" import { useCallback, useEffect, useState } from "react" @@ -52,7 +53,9 @@ export function SettingsPage() { string | null >(null) const [devReload, setDevReload] = useState(null) - const [devSeedMock, setDevSeedMock] = useState(null) + const [devMode, setDevMode] = useState( + () => localStorage.getItem(STORAGE_KEYS.devMode) === "true", + ) useEffect(() => { loadCachedResult(db).then((cached) => { @@ -247,227 +250,218 @@ export function SettingsPage() { {deviceId} +
+ + Entwicklermodus + + { + setDevMode(checked) + localStorage.setItem(STORAGE_KEYS.devMode, String(checked)) + try { + await fetch(`${BACKEND_URL}/legislation/seed-mock`, { + method: checked ? "POST" : "DELETE", + }) + } catch { + // best-effort + } + }} + /> +
- {/* --- Developer --- */} -
-

- Entwickler -

- - -
- Backend Health -
- {devHealth && ( - +

+ Entwickler +

+ + +
+ Backend Health +
+ {devHealth && ( + + {devHealth} + + )} + + Prüfen + +
-
-
- Test-Push -
- {devPush && ( - + Test-Push +
+ {devPush && ( + + {devPush} + + )} + + Senden + +
-
-
- Alle Themen folgen -
- {devTopics && ( - {devTopics} - )} - -
-
-
- Allen Themen entfolgen -
- {devUnfollowTopics && ( - - {devUnfollowTopics} - - )} - -
-
-
- Alle Abgeordnete folgen -
- {devPoliticians && ( - - {devPoliticians} - - )} - -
-
-
- Allen Abgeordneten entfolgen -
- {devUnfollowPoliticians && ( - - {devUnfollowPoliticians} - - )} - -
-
-
- Testdaten laden -
- {devSeedMock && ( - + Alle Themen folgen +
+ {devTopics && ( + {devTopics} + )} + +
+
+
+ Allen Themen entfolgen +
+ {devUnfollowTopics && ( + + {devUnfollowTopics} + + )} + +
+
+
+ Alle Abgeordnete folgen +
+ {devPoliticians && ( + + {devPoliticians} + + )} + + for (const m of cached.mandates) { + follow( + "politician", + m.politician.id, + m.politician.label, + ) + } + setDevPoliticians(`${cached.mandates.length}`) + }} + > + Folgen + +
-
-
- Abgeordnete neu laden -
- {devReload && ( - {devReload} - )} - +
+ Allen Abgeordneten entfolgen +
+ {devUnfollowPoliticians && ( + + {devUnfollowPoliticians} + + )} + +
-
- - -
+
+ Abgeordnete neu laden +
+ {devReload && ( + {devReload} + )} + +
+
+ + + + )} ) } diff --git a/src/client/shared/lib/constants.ts b/src/client/shared/lib/constants.ts index 64e9dac..99a69d2 100644 --- a/src/client/shared/lib/constants.ts +++ b/src/client/shared/lib/constants.ts @@ -1,4 +1,4 @@ -export const APP_VERSION = "2026.03.10" +export const APP_VERSION = "2026.03.10.1" export const AW_API_BASE = "https://www.abgeordnetenwatch.de/api/v2" export const AW_API_TIMEOUT_MS = 20_000 @@ -20,4 +20,5 @@ export const STORAGE_KEYS = { follows: "agw_follows", geoCache: "agw_geo_cache", pushEnabled: "agw_push_enabled", + devMode: "agw_dev_mode", } as const diff --git a/src/server/features/legislation/router.ts b/src/server/features/legislation/router.ts index 2ce5254..45c46e7 100644 --- a/src/server/features/legislation/router.ts +++ b/src/server/features/legislation/router.ts @@ -2,6 +2,7 @@ import { Hono } from "hono" import { castVoteSchema } from "./schema" import { castVote, + deleteMockLegislation, getLegislation, getLegislationResults, getLegislationText, @@ -18,6 +19,11 @@ legislationRouter.post("/seed-mock", async (c) => { return c.json({ ok: true, count: ids.length, ids }, 201) }) +legislationRouter.delete("/seed-mock", async (c) => { + const count = await deleteMockLegislation() + return c.json({ ok: true, deleted: count }) +}) + legislationRouter.get("/upcoming", async (c) => { const items = await getUpcomingLegislation() return c.json(items) diff --git a/src/server/features/legislation/service.ts b/src/server/features/legislation/service.ts index a64ec9d..e0278a9 100644 --- a/src/server/features/legislation/service.ts +++ b/src/server/features/legislation/service.ts @@ -1,4 +1,4 @@ -import { and, desc, eq } from "drizzle-orm" +import { and, desc, eq, inArray } from "drizzle-orm" import { db } from "../../shared/db/client" import { legislationSummaries, @@ -254,3 +254,19 @@ export async function seedMockLegislation() { return inserted } + +const MOCK_IDS = MOCK_LEGISLATION.map((m) => m.dipVorgangsId) + +export async function deleteMockLegislation() { + const rows = await db + .select({ id: legislationTexts.id }) + .from(legislationTexts) + .where(inArray(legislationTexts.dipVorgangsId, MOCK_IDS)) + + if (rows.length === 0) return 0 + + const ids = rows.map((r) => r.id) + await db.delete(legislationTexts).where(inArray(legislationTexts.id, ids)) + + return ids.length +}