diff --git a/.env.example b/.env.example index 953e3eb..daf8546 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,7 @@ DATABASE_URL="postgresql://postgres:postgres@db:5432/moh_sass?schema=public" NEXT_PUBLIC_APP_URL="https://mohfarawati.de" +NEXT_PUBLIC_SITE_URL="https://mohfarawati.de" +NEXT_PUBLIC_ADMIN_URL="https://root.mohfarawati.de" NEXT_TELEMETRY_DISABLED="1" ADMIN_PASSWORD="123Yolo!321" ADMIN_AUTH_SECRET="Us0z76jwlTQLOeQWAGGxAxDcc0rHwp4q" diff --git a/app/_admin/layout.tsx b/app/_admin/layout.tsx new file mode 100644 index 0000000..aaa652e --- /dev/null +++ b/app/_admin/layout.tsx @@ -0,0 +1,2 @@ +export { metadata } from "../root/layout"; +export { default } from "../root/layout"; diff --git a/app/_admin/maintenance/page.tsx b/app/_admin/maintenance/page.tsx new file mode 100644 index 0000000..b100301 --- /dev/null +++ b/app/_admin/maintenance/page.tsx @@ -0,0 +1,2 @@ +export { dynamic } from "../../root/maintenance/page"; +export { default } from "../../root/maintenance/page"; diff --git a/app/_admin/marquee/page.tsx b/app/_admin/marquee/page.tsx new file mode 100644 index 0000000..292ef2f --- /dev/null +++ b/app/_admin/marquee/page.tsx @@ -0,0 +1 @@ +export { default } from "../../root/marquee/page"; diff --git a/app/_admin/media/page.tsx b/app/_admin/media/page.tsx new file mode 100644 index 0000000..966e62f --- /dev/null +++ b/app/_admin/media/page.tsx @@ -0,0 +1,2 @@ +export { dynamic } from "../../root/media/page"; +export { default } from "../../root/media/page"; diff --git a/app/_admin/page.tsx b/app/_admin/page.tsx new file mode 100644 index 0000000..d087c07 --- /dev/null +++ b/app/_admin/page.tsx @@ -0,0 +1,2 @@ +export { dynamic } from "../root/page"; +export { default } from "../root/page"; diff --git a/app/_admin/portfolio/categories/page.tsx b/app/_admin/portfolio/categories/page.tsx new file mode 100644 index 0000000..9b60cd3 --- /dev/null +++ b/app/_admin/portfolio/categories/page.tsx @@ -0,0 +1 @@ +export { default } from "../../../root/portfolio/categories/page"; diff --git a/app/_admin/portfolio/media/page.tsx b/app/_admin/portfolio/media/page.tsx new file mode 100644 index 0000000..732fa29 --- /dev/null +++ b/app/_admin/portfolio/media/page.tsx @@ -0,0 +1 @@ +export { default } from "../../../root/portfolio/media/page"; diff --git a/app/_admin/portfolio/page.tsx b/app/_admin/portfolio/page.tsx new file mode 100644 index 0000000..9b44930 --- /dev/null +++ b/app/_admin/portfolio/page.tsx @@ -0,0 +1 @@ +export { default } from "../../root/portfolio/page"; diff --git a/app/_admin/portfolio/projects/[id]/page.tsx b/app/_admin/portfolio/projects/[id]/page.tsx new file mode 100644 index 0000000..37a898d --- /dev/null +++ b/app/_admin/portfolio/projects/[id]/page.tsx @@ -0,0 +1 @@ +export { default } from "../../../../root/portfolio/projects/[id]/page"; diff --git a/app/_admin/portfolio/projects/new/page.tsx b/app/_admin/portfolio/projects/new/page.tsx new file mode 100644 index 0000000..60a3a51 --- /dev/null +++ b/app/_admin/portfolio/projects/new/page.tsx @@ -0,0 +1 @@ +export { default } from "../../../../root/portfolio/projects/new/page"; diff --git a/app/_admin/portfolio/projects/page.tsx b/app/_admin/portfolio/projects/page.tsx new file mode 100644 index 0000000..88752dd --- /dev/null +++ b/app/_admin/portfolio/projects/page.tsx @@ -0,0 +1 @@ +export { default } from "../../../root/portfolio/projects/page"; diff --git a/app/_admin/site-settings/page.tsx b/app/_admin/site-settings/page.tsx new file mode 100644 index 0000000..01d04ea --- /dev/null +++ b/app/_admin/site-settings/page.tsx @@ -0,0 +1 @@ +export { default } from "../../root/site-settings/page"; diff --git a/app/_admin/smtp/contact-protection/page.tsx b/app/_admin/smtp/contact-protection/page.tsx new file mode 100644 index 0000000..34e80a5 --- /dev/null +++ b/app/_admin/smtp/contact-protection/page.tsx @@ -0,0 +1 @@ +export { default } from "../../../root/smtp/contact-protection/page"; diff --git a/app/_admin/smtp/page.tsx b/app/_admin/smtp/page.tsx new file mode 100644 index 0000000..8c935aa --- /dev/null +++ b/app/_admin/smtp/page.tsx @@ -0,0 +1 @@ +export { default } from "../../root/smtp/page"; diff --git a/app/_admin/ui-kit/page.tsx b/app/_admin/ui-kit/page.tsx new file mode 100644 index 0000000..a9d5ab1 --- /dev/null +++ b/app/_admin/ui-kit/page.tsx @@ -0,0 +1 @@ +export { default } from "../../root/ui-kit/page"; diff --git a/app/robots.ts b/app/robots.ts index 6525321..a5b7c47 100644 --- a/app/robots.ts +++ b/app/robots.ts @@ -7,7 +7,7 @@ export default function robots(): MetadataRoute.Robots { rules: [ { userAgent: "*", - disallow: ["/root"], + disallow: ["/_admin"], }, ], sitemap: new URL("/sitemap.xml", siteUrl).toString(), diff --git a/app/root/maintenance/actions.ts b/app/root/maintenance/actions.ts index 8d213eb..d4ebfd3 100644 --- a/app/root/maintenance/actions.ts +++ b/app/root/maintenance/actions.ts @@ -4,6 +4,7 @@ import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import { routing } from "@/i18n/routing"; +import { toInternalAdminPath } from "@/lib/admin-routing"; import { clearAdminSessionCookie, isAdminAuthenticated } from "@/lib/admin-auth"; import { getLocalizedPath } from "@/lib/locale"; import { setMaintenanceMode } from "@/lib/app-config"; @@ -11,7 +12,7 @@ import { setMaintenanceMode } from "@/lib/app-config"; function ensureAdmin() { if (!isAdminAuthenticated()) { clearAdminSessionCookie(); - redirect("/root"); + redirect("/"); } } @@ -19,7 +20,7 @@ export async function updateMaintenanceModeAction(formData: FormData) { ensureAdmin(); const nextValue = formData.get("enabled") === "true"; - const redirectPath = String(formData.get("redirectPath") ?? "/root"); + const redirectPath = String(formData.get("redirectPath") ?? "/"); const redirectUrl = new URL(redirectPath, "http://localhost"); redirectUrl.searchParams.set( "success", @@ -29,9 +30,9 @@ export async function updateMaintenanceModeAction(formData: FormData) { await setMaintenanceMode(nextValue); revalidatePath("/", "layout"); revalidatePath("/coming-soon"); - revalidatePath("/root"); - revalidatePath("/root/maintenance"); - revalidatePath(redirectPath); + revalidatePath(toInternalAdminPath("/")); + revalidatePath(toInternalAdminPath("/maintenance")); + revalidatePath(toInternalAdminPath(redirectUrl.pathname)); for (const appLocale of routing.locales) { revalidatePath(getLocalizedPath(appLocale), "layout"); diff --git a/app/root/maintenance/page.tsx b/app/root/maintenance/page.tsx index 0139cf4..e5e4342 100644 --- a/app/root/maintenance/page.tsx +++ b/app/root/maintenance/page.tsx @@ -31,7 +31,7 @@ export default async function RootMaintenancePage() { const authenticated = isAdminAuthenticated(); if (!authenticated) { - redirect("/root"); + redirect("/"); } const maintenanceEnabled = await getMaintenanceMode(); @@ -39,7 +39,7 @@ export default async function RootMaintenancePage() { "use server"; clearAdminSessionCookie(); - redirect("/root"); + redirect("/"); } return ( diff --git a/app/root/marquee/actions.ts b/app/root/marquee/actions.ts index eea05ad..26365d4 100644 --- a/app/root/marquee/actions.ts +++ b/app/root/marquee/actions.ts @@ -4,6 +4,7 @@ import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import { isRedirectError } from "next/dist/client/components/redirect"; +import { toInternalAdminPath } from "@/lib/admin-routing"; import { clearAdminSessionCookie, isAdminAuthenticated } from "@/lib/admin-auth"; import { updateMarqueeSettings } from "@/lib/app-config"; import { routing } from "@/i18n/routing"; @@ -12,7 +13,7 @@ import { getLocalizedPath } from "@/lib/locale"; function ensureAdmin() { if (!isAdminAuthenticated()) { clearAdminSessionCookie(); - redirect("/root"); + redirect("/"); } } @@ -24,8 +25,8 @@ function withMessage(pathname: string, type: "success" | "error", message: strin } async function revalidateMarqueePages() { - revalidatePath("/root"); - revalidatePath("/root/marquee"); + revalidatePath(toInternalAdminPath("/")); + revalidatePath(toInternalAdminPath("/marquee")); for (const locale of routing.locales) { revalidatePath(getLocalizedPath(locale), "layout"); @@ -71,13 +72,13 @@ export async function saveMarqueeSettingsAction(formData: FormData) { await updateMarqueeSettings(settings); await revalidateMarqueePages(); - redirect(withMessage("/root/marquee", "success", "Marquee gespeichert.")); + redirect(withMessage("/marquee", "success", "Marquee gespeichert.")); } catch (error) { if (isRedirectError(error)) { throw error; } const message = error instanceof Error ? error.message : "Marquee konnte nicht gespeichert werden."; - redirect(withMessage("/root/marquee", "error", message)); + redirect(withMessage("/marquee", "error", message)); } } diff --git a/app/root/marquee/page.tsx b/app/root/marquee/page.tsx index cca3c52..4aaff81 100644 --- a/app/root/marquee/page.tsx +++ b/app/root/marquee/page.tsx @@ -27,14 +27,14 @@ const copy = { export default async function RootMarqueePage() { if (!isAdminAuthenticated()) { - redirect("/root"); + redirect("/"); } async function logoutAction() { "use server"; clearAdminSessionCookie(); - redirect("/root"); + redirect("/"); } const marqueeSettings = await getMarqueeSettings(); diff --git a/app/root/media/actions.ts b/app/root/media/actions.ts index d98acf8..b655c6a 100644 --- a/app/root/media/actions.ts +++ b/app/root/media/actions.ts @@ -5,6 +5,7 @@ import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import { isRedirectError } from "next/dist/client/components/redirect"; +import { toInternalAdminPath } from "@/lib/admin-routing"; import { clearAdminSessionCookie, isAdminAuthenticated } from "@/lib/admin-auth"; import { countMediaUsageReferences, getMediaAssetById } from "@/lib/media"; import { createStandaloneMediaAsset, deleteMediaAssetAndFile } from "@/lib/media-service"; @@ -14,7 +15,7 @@ import { prisma } from "@/lib/prisma"; function ensureAdmin() { if (!isAdminAuthenticated()) { clearAdminSessionCookie(); - redirect("/root"); + redirect("/"); } } @@ -26,10 +27,10 @@ function withMessage(pathname: string, type: "success" | "error", message: strin } function revalidateMediaPages() { - revalidatePath("/root"); - revalidatePath("/root/media"); - revalidatePath("/root/portfolio"); - revalidatePath("/root/portfolio/projects"); + revalidatePath(toInternalAdminPath("/")); + revalidatePath(toInternalAdminPath("/media")); + revalidatePath(toInternalAdminPath("/portfolio")); + revalidatePath(toInternalAdminPath("/portfolio/projects")); } export async function createMediaAssetAction(formData: FormData) { @@ -46,14 +47,14 @@ export async function createMediaAssetAction(formData: FormData) { }); revalidateMediaPages(); - redirect(withMessage("/root/media", "success", "Datei gespeichert.")); + redirect(withMessage("/media", "success", "Datei gespeichert.")); } catch (error) { if (isRedirectError(error)) { throw error; } const message = error instanceof Error ? error.message : "Datei konnte nicht gespeichert werden."; - redirect(withMessage("/root/media", "error", message)); + redirect(withMessage("/media", "error", message)); } } @@ -66,13 +67,13 @@ export async function deleteMediaAssetAction(formData: FormData) { const asset = await getMediaAssetById(assetId); if (!asset) { - redirect(withMessage("/root/media", "error", "Datei nicht gefunden.")); + redirect(withMessage("/media", "error", "Datei nicht gefunden.")); } const usageCount = await countMediaUsageReferences(asset.id); if (usageCount > 0) { - redirect(withMessage("/root/media", "error", "Datei wird noch verwendet.")); + redirect(withMessage("/media", "error", "Datei wird noch verwendet.")); } await prisma.mediaAsset.delete({ @@ -89,13 +90,13 @@ export async function deleteMediaAssetAction(formData: FormData) { } revalidateMediaPages(); - redirect(withMessage("/root/media", "success", "Datei geloescht.")); + redirect(withMessage("/media", "success", "Datei geloescht.")); } catch (error) { if (isRedirectError(error)) { throw error; } const message = error instanceof Error ? error.message : "Datei konnte nicht geloescht werden."; - redirect(withMessage("/root/media", "error", message)); + redirect(withMessage("/media", "error", message)); } } diff --git a/app/root/media/page.tsx b/app/root/media/page.tsx index 3047fb0..1f4fa7e 100644 --- a/app/root/media/page.tsx +++ b/app/root/media/page.tsx @@ -22,14 +22,14 @@ const copy = { export default async function RootMediaPage() { if (!isAdminAuthenticated()) { - redirect("/root"); + redirect("/"); } async function logoutAction() { "use server"; clearAdminSessionCookie(); - redirect("/root"); + redirect("/"); } const mediaAssets = await getAdminMediaAssets(); diff --git a/app/root/page.tsx b/app/root/page.tsx index 03ee884..ef5b468 100644 --- a/app/root/page.tsx +++ b/app/root/page.tsx @@ -75,28 +75,28 @@ export default async function RootPage({ searchParams }: RootPageProps) { const currentLockState = getAdminLockState(); if (currentLockState.locked) { - redirect("/root?error=locked"); + redirect("/?error=locked"); } if (!isAdminAuthConfigured() || !isPasswordValid(password)) { const failState = registerFailedAdminAttempt(); if (failState.locked) { - redirect("/root?error=locked"); + redirect("/?error=locked"); } - redirect("/root?error=invalid"); + redirect("/?error=invalid"); } resetAdminFailedAttempts(); setAdminSessionCookie(); - redirect("/root"); + redirect("/"); } async function logoutAction() { "use server"; clearAdminSessionCookie(); - redirect("/root"); + redirect("/"); } if (!authenticated) { diff --git a/app/root/portfolio/actions.ts b/app/root/portfolio/actions.ts index f89241c..288f044 100644 --- a/app/root/portfolio/actions.ts +++ b/app/root/portfolio/actions.ts @@ -7,6 +7,7 @@ import { isRedirectError } from "next/dist/client/components/redirect"; import { ZodError } from "zod"; import { routing } from "@/i18n/routing"; +import { toInternalAdminPath } from "@/lib/admin-routing"; import { clearAdminSessionCookie, isAdminAuthenticated } from "@/lib/admin-auth"; import { deleteEntityMediaUsages, replaceEntityMediaUsages } from "@/lib/media"; import { resolveMediaSelection } from "@/lib/media-service"; @@ -25,7 +26,7 @@ import { function ensureAdmin() { if (!isAdminAuthenticated()) { clearAdminSessionCookie(); - redirect("/root"); + redirect("/"); } } @@ -85,11 +86,11 @@ function parseZodError(error: ZodError) { } async function revalidatePortfolioPages() { - revalidatePath("/root"); - revalidatePath("/root/media"); - revalidatePath("/root/portfolio"); - revalidatePath("/root/portfolio/categories"); - revalidatePath("/root/portfolio/projects"); + revalidatePath(toInternalAdminPath("/")); + revalidatePath(toInternalAdminPath("/media")); + revalidatePath(toInternalAdminPath("/portfolio")); + revalidatePath(toInternalAdminPath("/portfolio/categories")); + revalidatePath(toInternalAdminPath("/portfolio/projects")); revalidatePath("/portfolio"); for (const locale of routing.locales) { @@ -106,7 +107,7 @@ async function removeManagedPaths(paths: string[]) { export async function upsertCategoryAction(formData: FormData) { ensureAdmin(); - const redirectPath = getRedirectPath(formData, "/root/portfolio/categories"); + const redirectPath = getRedirectPath(formData, "/portfolio/categories"); try { const parsed = categoryInputSchema.parse({ @@ -156,7 +157,7 @@ export async function upsertCategoryAction(formData: FormData) { export async function deleteCategoryAction(formData: FormData) { ensureAdmin(); - const redirectPath = getRedirectPath(formData, "/root/portfolio/categories"); + const redirectPath = getRedirectPath(formData, "/portfolio/categories"); const id = String(formData.get("id") ?? ""); try { @@ -191,8 +192,8 @@ export async function saveProjectAction(formData: FormData) { ensureAdmin(); const fallbackRedirect = String(formData.get("id") ?? "").trim() - ? `/root/portfolio/projects/${String(formData.get("id") ?? "").trim()}` - : "/root/portfolio/projects/new"; + ? `/portfolio/projects/${String(formData.get("id") ?? "").trim()}` + : "/portfolio/projects/new"; const redirectPath = getRedirectPath(formData, fallbackRedirect); const uploadedPaths: string[] = []; const createdMediaAssetIds: string[] = []; @@ -517,7 +518,7 @@ export async function saveProjectAction(formData: FormData) { }); await revalidatePortfolioPages(); - revalidatePath(`/root/portfolio/projects/${projectResult.project.id}`); + revalidatePath(toInternalAdminPath(`/portfolio/projects/${projectResult.project.id}`)); revalidatePath(`/portfolio/${projectResult.project.slug}`); for (const locale of routing.locales) { @@ -525,7 +526,7 @@ export async function saveProjectAction(formData: FormData) { } redirect( - withMessage(`/root/portfolio/projects/${projectResult.project.id}`, "success", "Projekt gespeichert."), + withMessage(`/portfolio/projects/${projectResult.project.id}`, "success", "Projekt gespeichert."), ); } catch (error) { if (isRedirectError(error)) { @@ -578,7 +579,7 @@ export async function deleteProjectAction(formData: FormData) { }); if (!project) { - redirect(withMessage("/root/portfolio", "error", "Project not found.")); + redirect(withMessage("/portfolio", "error", "Project not found.")); } await prisma.portfolioProject.delete({ @@ -595,12 +596,12 @@ export async function deleteProjectAction(formData: FormData) { revalidatePath(getLocalizedPath(locale, `/portfolio/${project.slug}`)); } - redirect(withMessage("/root/portfolio", "success", "Project deleted.")); + redirect(withMessage("/portfolio", "success", "Project deleted.")); } catch (error) { if (isRedirectError(error)) { throw error; } - redirect(withMessage("/root/portfolio", "error", "Unable to delete project.")); + redirect(withMessage("/portfolio", "error", "Unable to delete project.")); } } diff --git a/app/root/portfolio/categories/page.tsx b/app/root/portfolio/categories/page.tsx index c1c4858..2455d7b 100644 --- a/app/root/portfolio/categories/page.tsx +++ b/app/root/portfolio/categories/page.tsx @@ -24,14 +24,14 @@ const copy = { export default async function RootPortfolioCategoriesPage() { if (!isAdminAuthenticated()) { - redirect("/root"); + redirect("/"); } async function logoutAction() { "use server"; clearAdminSessionCookie(); - redirect("/root"); + redirect("/"); } const categories = await getAdminPortfolioCategories(); diff --git a/app/root/portfolio/media/page.tsx b/app/root/portfolio/media/page.tsx index 478883e..3d84c73 100644 --- a/app/root/portfolio/media/page.tsx +++ b/app/root/portfolio/media/page.tsx @@ -1,5 +1,5 @@ import { redirect } from "next/navigation"; export default function RootPortfolioMediaRedirectPage() { - redirect("/root/media"); + redirect("/media"); } diff --git a/app/root/portfolio/page.tsx b/app/root/portfolio/page.tsx index 1d71781..91104c5 100644 --- a/app/root/portfolio/page.tsx +++ b/app/root/portfolio/page.tsx @@ -31,14 +31,14 @@ type RootPortfolioPageProps = { export default async function RootPortfolioPage({ searchParams }: RootPortfolioPageProps) { if (!isAdminAuthenticated()) { - redirect("/root"); + redirect("/"); } async function logoutAction() { "use server"; clearAdminSessionCookie(); - redirect("/root"); + redirect("/"); } const selectedCategory = searchParams?.category && searchParams.category !== "__all__" diff --git a/app/root/portfolio/projects/[id]/page.tsx b/app/root/portfolio/projects/[id]/page.tsx index 8ebca64..1023886 100644 --- a/app/root/portfolio/projects/[id]/page.tsx +++ b/app/root/portfolio/projects/[id]/page.tsx @@ -53,14 +53,14 @@ export default async function RootPortfolioProjectPage({ params, }: RootPortfolioProjectPageProps) { if (!isAdminAuthenticated()) { - redirect("/root"); + redirect("/"); } async function logoutAction() { "use server"; clearAdminSessionCookie(); - redirect("/root"); + redirect("/"); } const [categories, mediaOptions, project] = await Promise.all([ @@ -70,7 +70,7 @@ export default async function RootPortfolioProjectPage({ ]); if (!project) { - redirect("/root/portfolio?error=Project+not+found."); + redirect("/portfolio?error=Project+not+found."); } return ( @@ -90,7 +90,7 @@ export default async function RootPortfolioProjectPage({ mediaOptions={mediaOptions} project={project} formId="portfolio-project-form" - redirectPath={`/root/portfolio/projects/${project.id}`} + redirectPath={`/portfolio/projects/${project.id}`} /> diff --git a/app/root/portfolio/projects/new/page.tsx b/app/root/portfolio/projects/new/page.tsx index 0b7c46b..04af32b 100644 --- a/app/root/portfolio/projects/new/page.tsx +++ b/app/root/portfolio/projects/new/page.tsx @@ -26,14 +26,14 @@ const copy = { export default async function RootNewPortfolioProjectPage() { if (!isAdminAuthenticated()) { - redirect("/root"); + redirect("/"); } async function logoutAction() { "use server"; clearAdminSessionCookie(); - redirect("/root"); + redirect("/"); } const [categories, mediaOptions] = await Promise.all([ @@ -57,7 +57,7 @@ export default async function RootNewPortfolioProjectPage() { categories={categories} mediaOptions={mediaOptions} formId="portfolio-project-form" - redirectPath="/root/portfolio/projects/new" + redirectPath="/portfolio/projects/new" /> diff --git a/app/root/portfolio/projects/page.tsx b/app/root/portfolio/projects/page.tsx index 2232167..6dfdac4 100644 --- a/app/root/portfolio/projects/page.tsx +++ b/app/root/portfolio/projects/page.tsx @@ -31,14 +31,14 @@ export default async function RootPortfolioProjectsPage({ searchParams, }: RootPortfolioProjectsPageProps) { if (!isAdminAuthenticated()) { - redirect("/root"); + redirect("/"); } async function logoutAction() { "use server"; clearAdminSessionCookie(); - redirect("/root"); + redirect("/"); } const selectedCategory = searchParams?.category && searchParams.category !== "__all__" diff --git a/app/root/site-settings/actions.ts b/app/root/site-settings/actions.ts index 8d9154c..f337123 100644 --- a/app/root/site-settings/actions.ts +++ b/app/root/site-settings/actions.ts @@ -14,6 +14,7 @@ import { SITE_SETTINGS_LOGO_LIGHT_FIELD_KEY, updateSiteSettings, } from "@/lib/app-config"; +import { toInternalAdminPath } from "@/lib/admin-routing"; import { PAGE_TITLE_TOKEN, type SiteSettings } from "@/lib/site-settings"; import { clearAdminSessionCookie, isAdminAuthenticated } from "@/lib/admin-auth"; import { replaceEntityMediaUsages } from "@/lib/media"; @@ -27,7 +28,7 @@ import { prisma } from "@/lib/prisma"; function ensureAdmin() { if (!isAdminAuthenticated()) { clearAdminSessionCookie(); - redirect("/root"); + redirect("/"); } } @@ -74,8 +75,8 @@ async function cleanupCreatedMedia(assetIds: string[], uploadedPaths: string[]) async function revalidateSiteSettingsPages() { revalidatePath("/", "layout"); - revalidatePath("/root"); - revalidatePath("/root/site-settings"); + revalidatePath(toInternalAdminPath("/")); + revalidatePath(toInternalAdminPath("/site-settings")); revalidatePath("/coming-soon"); const publicPaths = ["/", "/about", "/portfolio", "/contact", "/success", "/coming-soon"]; @@ -277,7 +278,7 @@ export async function saveSiteSettingsAction(formData: FormData) { }); await revalidateSiteSettingsPages(); - redirect(withMessage("/root/site-settings", "success", "Einstellungen gespeichert.")); + redirect(withMessage("/site-settings", "success", "Einstellungen gespeichert.")); } catch (error) { if (isRedirectError(error)) { throw error; @@ -290,6 +291,6 @@ export async function saveSiteSettingsAction(formData: FormData) { ? error.message : "Einstellungen konnten nicht gespeichert werden."; - redirect(withMessage("/root/site-settings", "error", message)); + redirect(withMessage("/site-settings", "error", message)); } } diff --git a/app/root/site-settings/page.tsx b/app/root/site-settings/page.tsx index 8d9cd59..ba67e5e 100644 --- a/app/root/site-settings/page.tsx +++ b/app/root/site-settings/page.tsx @@ -31,14 +31,14 @@ const copy = { export default async function RootSiteSettingsPage() { if (!isAdminAuthenticated()) { - redirect("/root"); + redirect("/"); } async function logoutAction() { "use server"; clearAdminSessionCookie(); - redirect("/root"); + redirect("/"); } const [siteSettings, mediaBindings, mediaOptions] = await Promise.all([ diff --git a/app/root/smtp/actions.ts b/app/root/smtp/actions.ts index 4de36ed..418206c 100644 --- a/app/root/smtp/actions.ts +++ b/app/root/smtp/actions.ts @@ -4,6 +4,7 @@ import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import { isRedirectError } from "next/dist/client/components/redirect"; +import { toInternalAdminPath } from "@/lib/admin-routing"; import { clearAdminSessionCookie, isAdminAuthenticated } from "@/lib/admin-auth"; import { isCheckedFormValue } from "@/lib/form-data"; import { @@ -16,7 +17,7 @@ import type { MailSettings } from "@/lib/mail-settings"; function ensureAdmin() { if (!isAdminAuthenticated()) { clearAdminSessionCookie(); - redirect("/root"); + redirect("/"); } } @@ -77,8 +78,8 @@ export async function saveMailSettingsAction(formData: FormData) { const nextMailSettings = parseMailSettingsFormData(formData, existingMailSettings); await updateMailSettings(nextMailSettings); - revalidatePath("/root/smtp"); - redirect(withMessage("/root/smtp", "success", "SMTP Einstellungen gespeichert.")); + revalidatePath(toInternalAdminPath("/smtp")); + redirect(withMessage("/smtp", "success", "SMTP Einstellungen gespeichert.")); } catch (error) { if (isRedirectError(error)) { throw error; @@ -89,7 +90,7 @@ export async function saveMailSettingsAction(formData: FormData) { ? error.message : "SMTP Einstellungen konnten nicht gespeichert werden."; - redirect(withMessage("/root/smtp", "error", message)); + redirect(withMessage("/smtp", "error", message)); } } @@ -98,7 +99,7 @@ export async function sendTestEmailAction() { try { await sendTestEmail(); - redirect(withMessage("/root/smtp", "success", "Test-E-Mail gesendet.")); + redirect(withMessage("/smtp", "success", "Test-E-Mail gesendet.")); } catch (error) { if (isRedirectError(error)) { throw error; @@ -109,6 +110,6 @@ export async function sendTestEmailAction() { ? error.message : "Test-E-Mail konnte nicht gesendet werden."; - redirect(withMessage("/root/smtp", "error", message)); + redirect(withMessage("/smtp", "error", message)); } } diff --git a/app/root/smtp/contact-protection/actions.ts b/app/root/smtp/contact-protection/actions.ts index 66d5b9c..3f73e23 100644 --- a/app/root/smtp/contact-protection/actions.ts +++ b/app/root/smtp/contact-protection/actions.ts @@ -4,6 +4,7 @@ import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import { isRedirectError } from "next/dist/client/components/redirect"; +import { toInternalAdminPath } from "@/lib/admin-routing"; import { clearAdminSessionCookie, isAdminAuthenticated } from "@/lib/admin-auth"; import { isCheckedFormValue } from "@/lib/form-data"; import { @@ -15,7 +16,7 @@ import type { ContactProtectionSettings } from "@/lib/contact-protection"; function ensureAdmin() { if (!isAdminAuthenticated()) { clearAdminSessionCookie(); - redirect("/root"); + redirect("/"); } } @@ -85,13 +86,13 @@ export async function saveContactProtectionSettingsAction(formData: FormData) { const nextSettings = parseContactProtectionFormData(formData, existingSettings); await updateContactProtectionSettings(nextSettings); - revalidatePath("/root/smtp/contact-protection"); + revalidatePath(toInternalAdminPath("/smtp/contact-protection")); revalidatePath("/contact"); revalidatePath("/ar/contact"); revalidatePath("/en/contact"); redirect( withMessage( - "/root/smtp/contact-protection", + "/smtp/contact-protection", "success", "Contact Protection gespeichert.", ), @@ -106,6 +107,6 @@ export async function saveContactProtectionSettingsAction(formData: FormData) { ? error.message : "Contact Protection konnte nicht gespeichert werden."; - redirect(withMessage("/root/smtp/contact-protection", "error", message)); + redirect(withMessage("/smtp/contact-protection", "error", message)); } } diff --git a/app/root/smtp/contact-protection/page.tsx b/app/root/smtp/contact-protection/page.tsx index 8e383ed..0f5cdc9 100644 --- a/app/root/smtp/contact-protection/page.tsx +++ b/app/root/smtp/contact-protection/page.tsx @@ -27,14 +27,14 @@ const copy = { export default async function RootSMTPProtectionPage() { if (!isAdminAuthenticated()) { - redirect("/root"); + redirect("/"); } async function logoutAction() { "use server"; clearAdminSessionCookie(); - redirect("/root"); + redirect("/"); } const settings = await getContactProtectionFormValues(); diff --git a/app/root/smtp/page.tsx b/app/root/smtp/page.tsx index b35ed8b..5c0994b 100644 --- a/app/root/smtp/page.tsx +++ b/app/root/smtp/page.tsx @@ -28,14 +28,14 @@ const copy = { export default async function RootSMTPPage() { if (!isAdminAuthenticated()) { - redirect("/root"); + redirect("/"); } async function logoutAction() { "use server"; clearAdminSessionCookie(); - redirect("/root"); + redirect("/"); } const mailSettings = await getMailSettingsFormValues(); diff --git a/app/root/ui-kit/page.tsx b/app/root/ui-kit/page.tsx index c903bb3..eb431ac 100644 --- a/app/root/ui-kit/page.tsx +++ b/app/root/ui-kit/page.tsx @@ -24,14 +24,14 @@ export default async function RootUiKitPage() { const authenticated = isAdminAuthenticated(); if (!authenticated) { - redirect("/root"); + redirect("/"); } async function logoutAction() { "use server"; clearAdminSessionCookie(); - redirect("/root"); + redirect("/"); } return ( diff --git a/components/layout/app-sidebar.tsx b/components/layout/app-sidebar.tsx index 014788e..5a33e4d 100644 --- a/components/layout/app-sidebar.tsx +++ b/components/layout/app-sidebar.tsx @@ -27,10 +27,10 @@ export function AppSidebar({ items, footer, }: AppSidebarProps) { - const portfolioItem = items.find((item) => item.href === "/root/portfolio"); - const systemOrder = ["/root", "/root/media", "/root/maintenance", "/root/ui-kit"]; + const portfolioItem = items.find((item) => item.href === "/portfolio"); + const systemOrder = ["/", "/media", "/maintenance", "/ui-kit"]; const systemItems = items - .filter((item) => item.href !== "/root/portfolio") + .filter((item) => item.href !== "/portfolio") .sort((left, right) => systemOrder.indexOf(left.href) - systemOrder.indexOf(right.href)); function renderItem(item: SidebarItem, nested = false) { diff --git a/components/layout/site-footer.tsx b/components/layout/site-footer.tsx index 7180ddb..9699176 100644 --- a/components/layout/site-footer.tsx +++ b/components/layout/site-footer.tsx @@ -2,6 +2,7 @@ import Link from "next/link"; import { useLocale, useTranslations } from "next-intl"; import { Container } from "@/components/layout/container"; +import { buildAdminUrl } from "@/lib/admin-routing"; import { getLocalizedPath } from "@/lib/locale"; const navItems = [ @@ -34,7 +35,7 @@ export function SiteFooter({ isAdmin = false }: SiteFooterProps) { ))} {isAdmin ? ( - + {tNav("root")} ) : null} diff --git a/components/layout/site-header.tsx b/components/layout/site-header.tsx index 215a81b..d571a0d 100644 --- a/components/layout/site-header.tsx +++ b/components/layout/site-header.tsx @@ -13,6 +13,7 @@ import { SiteLogo } from "@/components/layout/site-logo"; import { SoundToggle } from "@/components/sound-toggle"; import { ThemeToggle } from "@/components/theme-toggle"; import { Button } from "@/components/ui/button"; +import { buildAdminUrl } from "@/lib/admin-routing"; import { getLocalizedPath, stripLocalePrefix } from "@/lib/locale"; import { toast } from "@/lib/toast"; import { cn } from "@/lib/utils"; @@ -314,7 +315,7 @@ export function SiteHeader({ /> {isAdmin ? ( @@ -464,7 +465,7 @@ export function SiteHeader({ /> {isAdmin ? ( diff --git a/components/root/portfolio-categories-manager.tsx b/components/root/portfolio-categories-manager.tsx index 630174d..d510532 100644 --- a/components/root/portfolio-categories-manager.tsx +++ b/components/root/portfolio-categories-manager.tsx @@ -159,7 +159,7 @@ function CategoryForm({ return (