feat(admin): settings page with tabs, system checks and email test
Docker Image bauen und veroeffentlichen / build-and-push (push) Successful in 2m26s
Docker Image bauen und veroeffentlichen / build-and-push (push) Successful in 2m26s
"Inhalte" becomes Admin -> Einstellungen, grouped into tabs so each area stands on its own: Firma & Versand, Marke, Startseite, Seiten, Social Media, Rechtstexte and System & Tests. Tabs are plain links (?reiter=...), bookmarkable and usable without JavaScript; saving returns to the same tab. System & Tests brings everything that checks the running shop into one place: - integration overview (Stripe, Stripe webhook, Microsoft 365 mail, Microsoft sign-in, Turnstile, Google reviews, DHL, ApiCore): only whether each is set up and the names of missing variables, never a value; warns when Stripe runs on test keys or mixes test/live - the email test, now with the IPv4 network checks for smtp.office365.com:587 and login.microsoftonline.com:443 /admin/inhalte and /admin/e-mail-test redirect to the new page; the separate "E-Mail-Test" menu entry is gone. The tab parameter and the saved group are validated against a fixed list before they are used in a redirect. Docs point to the new location and cover the ENETUNREACH (IPv6) case. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
b5311fae83
commit
de82ad0233
17 files changed
+654
-288
No files matched your search
@@ -0,0 +1,36 @@
|
||||
import type { ContentFieldDef } from "@/lib/content-registry";
|
||||
|
||||
/**
|
||||
* Reiter von Admin → Einstellungen und welche Inhaltsgruppen
|
||||
* (lib/content-registry.ts) sie tragen. "system" hat keine Inhaltsfelder,
|
||||
* sondern Anbindungsstatus und E-Mail-Test.
|
||||
*/
|
||||
export const SETTINGS_TABS = [
|
||||
{ id: "firma", groups: ["company", "shipping"] },
|
||||
{ id: "marke", groups: ["brand"] },
|
||||
{ id: "startseite", groups: ["home"] },
|
||||
{ id: "seiten", groups: ["pages"] },
|
||||
{ id: "social", groups: ["social"] },
|
||||
{ id: "recht", groups: ["legal"] },
|
||||
{ id: "system", groups: [] },
|
||||
] as const satisfies readonly { id: string; groups: readonly ContentFieldDef["group"][] }[];
|
||||
|
||||
export type SettingsTabId = (typeof SETTINGS_TABS)[number]["id"];
|
||||
|
||||
export const SETTINGS_PATH = "/admin/einstellungen";
|
||||
|
||||
/** Reiter aus ?reiter=…; alles Unbekannte (auch Mehrfachwerte) faellt auf den ersten Reiter zurueck. */
|
||||
export function parseSettingsTab(value: string | string[] | undefined): SettingsTabId {
|
||||
const match = SETTINGS_TABS.find((tab) => tab.id === value);
|
||||
return match ? match.id : SETTINGS_TABS[0].id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ziel nach dem Speichern: derselbe Reiter. Der group-Wert kommt aus dem
|
||||
* Formular und ist damit Nutzereingabe — nur bekannte Gruppen fuehren zu
|
||||
* einem Reiter, alles andere zur Uebersicht.
|
||||
*/
|
||||
export function settingsPathForGroup(group: string): string {
|
||||
const tab = SETTINGS_TABS.find((t) => (t.groups as readonly string[]).includes(group));
|
||||
return tab ? `${SETTINGS_PATH}?reiter=${tab.id}` : SETTINGS_PATH;
|
||||
}
|
||||
Reference in new issue
Block a user