Upgrade app to Next.js 16
CI / quality (push) Waiting to run

This commit is contained in:
MOH
2026-03-13 15:50:37 +01:00
parent f14116b56c
commit e32ac4cacb
40 changed files with 1853 additions and 1157 deletions
+4 -4
View File
@@ -9,15 +9,15 @@ import { clearAdminSessionCookie, isAdminAuthenticated } from "@/lib/admin-auth"
import { getLocalizedPath } from "@/lib/locale";
import { setMaintenanceMode } from "@/lib/app-config";
function ensureAdmin() {
if (!isAdminAuthenticated()) {
clearAdminSessionCookie();
async function ensureAdmin() {
if (!(await isAdminAuthenticated())) {
await clearAdminSessionCookie();
redirect("/");
}
}
export async function updateMaintenanceModeAction(formData: FormData) {
ensureAdmin();
await ensureAdmin();
const nextValue = formData.get("enabled") === "true";
const redirectPath = String(formData.get("redirectPath") ?? "/");
+2 -2
View File
@@ -28,7 +28,7 @@ const copy = {
};
export default async function RootMaintenancePage() {
const authenticated = isAdminAuthenticated();
const authenticated = await isAdminAuthenticated();
if (!authenticated) {
redirect("/");
@@ -38,7 +38,7 @@ export default async function RootMaintenancePage() {
async function logoutAction() {
"use server";
clearAdminSessionCookie();
await clearAdminSessionCookie();
redirect("/");
}
+5 -5
View File
@@ -2,7 +2,7 @@
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { isRedirectError } from "next/dist/client/components/redirect";
import { isRedirectError } from "next/dist/client/components/redirect-error";
import { toInternalAdminPath } from "@/lib/admin-routing";
import { clearAdminSessionCookie, isAdminAuthenticated } from "@/lib/admin-auth";
@@ -10,9 +10,9 @@ import { updateMarqueeSettings } from "@/lib/app-config";
import { routing } from "@/i18n/routing";
import { getLocalizedPath } from "@/lib/locale";
function ensureAdmin() {
if (!isAdminAuthenticated()) {
clearAdminSessionCookie();
async function ensureAdmin() {
if (!(await isAdminAuthenticated())) {
await clearAdminSessionCookie();
redirect("/");
}
}
@@ -35,7 +35,7 @@ async function revalidateMarqueePages() {
}
export async function saveMarqueeSettingsAction(formData: FormData) {
ensureAdmin();
await ensureAdmin();
try {
const germanSettings = {
+2 -2
View File
@@ -26,14 +26,14 @@ const copy = {
};
export default async function RootMarqueePage() {
if (!isAdminAuthenticated()) {
if (!(await isAdminAuthenticated())) {
redirect("/");
}
async function logoutAction() {
"use server";
clearAdminSessionCookie();
await clearAdminSessionCookie();
redirect("/");
}
+6 -6
View File
@@ -3,7 +3,7 @@
import { MediaKind } from "@prisma/client";
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { isRedirectError } from "next/dist/client/components/redirect";
import { isRedirectError } from "next/dist/client/components/redirect-error";
import { toInternalAdminPath } from "@/lib/admin-routing";
import { clearAdminSessionCookie, isAdminAuthenticated } from "@/lib/admin-auth";
@@ -12,9 +12,9 @@ import { createStandaloneMediaAsset, deleteMediaAssetAndFile } from "@/lib/media
import { isManagedMediaFilePath } from "@/lib/media-storage";
import { prisma } from "@/lib/prisma";
function ensureAdmin() {
if (!isAdminAuthenticated()) {
clearAdminSessionCookie();
async function ensureAdmin() {
if (!(await isAdminAuthenticated())) {
await clearAdminSessionCookie();
redirect("/");
}
}
@@ -34,7 +34,7 @@ function revalidateMediaPages() {
}
export async function createMediaAssetAction(formData: FormData) {
ensureAdmin();
await ensureAdmin();
try {
const kindValue = String(formData.get("kind") ?? "IMAGE");
@@ -59,7 +59,7 @@ export async function createMediaAssetAction(formData: FormData) {
}
export async function deleteMediaAssetAction(formData: FormData) {
ensureAdmin();
await ensureAdmin();
const assetId = String(formData.get("assetId") ?? "");
+2 -2
View File
@@ -21,14 +21,14 @@ const copy = {
};
export default async function RootMediaPage() {
if (!isAdminAuthenticated()) {
if (!(await isAdminAuthenticated())) {
redirect("/");
}
async function logoutAction() {
"use server";
clearAdminSessionCookie();
await clearAdminSessionCookie();
redirect("/");
}
+12 -11
View File
@@ -25,9 +25,9 @@ import { getAdminMediaAssets } from "@/lib/media";
import { getAdminPortfolioCategories, getAdminPortfolioProjects } from "@/lib/portfolio";
type RootPageProps = {
searchParams?: {
searchParams?: Promise<{
error?: string;
};
}>;
};
export const dynamic = "force-dynamic";
@@ -61,25 +61,26 @@ const copy = {
};
export default async function RootPage({ searchParams }: RootPageProps) {
const resolvedSearchParams = await searchParams;
const authConfigured = isAdminAuthConfigured();
const basicConfigured = Boolean(
process.env.ROOT_BASIC_AUTH_USER && process.env.ROOT_BASIC_AUTH_PASS,
);
const authenticated = isAdminAuthenticated();
const lockState = getAdminLockState();
const authenticated = await isAdminAuthenticated();
const lockState = await getAdminLockState();
async function loginAction(formData: FormData) {
"use server";
const password = String(formData.get("password") ?? "");
const currentLockState = getAdminLockState();
const currentLockState = await getAdminLockState();
if (currentLockState.locked) {
redirect("/?error=locked");
}
if (!isAdminAuthConfigured() || !isPasswordValid(password)) {
const failState = registerFailedAdminAttempt();
const failState = await registerFailedAdminAttempt();
if (failState.locked) {
redirect("/?error=locked");
}
@@ -87,15 +88,15 @@ export default async function RootPage({ searchParams }: RootPageProps) {
redirect("/?error=invalid");
}
resetAdminFailedAttempts();
setAdminSessionCookie();
await resetAdminFailedAttempts();
await setAdminSessionCookie();
redirect("/");
}
async function logoutAction() {
"use server";
clearAdminSessionCookie();
await clearAdminSessionCookie();
redirect("/");
}
@@ -124,13 +125,13 @@ export default async function RootPage({ searchParams }: RootPageProps) {
</p>
) : null}
{searchParams?.error === "invalid" ? (
{resolvedSearchParams?.error === "invalid" ? (
<p className="mb-4 rounded-nested border border-status-warning/30 bg-status-warning-soft px-3 py-2 text-sm text-status-warning">
{copy.invalidLogin}
</p>
) : null}
{searchParams?.error === "locked" || lockState.locked ? (
{resolvedSearchParams?.error === "locked" || lockState.locked ? (
<p className="mb-4 rounded-nested border border-status-warning/30 bg-status-warning-soft px-3 py-2 text-sm text-status-warning">
{copy.lockedLogin}
</p>
+8 -8
View File
@@ -3,7 +3,7 @@
import { MediaUsageType, Prisma } from "@prisma/client";
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { isRedirectError } from "next/dist/client/components/redirect";
import { isRedirectError } from "next/dist/client/components/redirect-error";
import { ZodError } from "zod";
import { routing } from "@/i18n/routing";
@@ -23,9 +23,9 @@ import {
sectionInputSchema,
} from "@/lib/portfolio-validation";
function ensureAdmin() {
if (!isAdminAuthenticated()) {
clearAdminSessionCookie();
async function ensureAdmin() {
if (!(await isAdminAuthenticated())) {
await clearAdminSessionCookie();
redirect("/");
}
}
@@ -105,7 +105,7 @@ async function removeManagedPaths(paths: string[]) {
}
export async function upsertCategoryAction(formData: FormData) {
ensureAdmin();
await ensureAdmin();
const redirectPath = getRedirectPath(formData, "/portfolio/categories");
@@ -155,7 +155,7 @@ export async function upsertCategoryAction(formData: FormData) {
}
export async function deleteCategoryAction(formData: FormData) {
ensureAdmin();
await ensureAdmin();
const redirectPath = getRedirectPath(formData, "/portfolio/categories");
const id = String(formData.get("id") ?? "");
@@ -189,7 +189,7 @@ export async function deleteCategoryAction(formData: FormData) {
}
export async function saveProjectAction(formData: FormData) {
ensureAdmin();
await ensureAdmin();
const fallbackRedirect = String(formData.get("id") ?? "").trim()
? `/portfolio/projects/${String(formData.get("id") ?? "").trim()}`
@@ -564,7 +564,7 @@ export async function saveProjectAction(formData: FormData) {
}
export async function deleteProjectAction(formData: FormData) {
ensureAdmin();
await ensureAdmin();
const id = String(formData.get("id") ?? "");
+2 -2
View File
@@ -23,14 +23,14 @@ const copy = {
};
export default async function RootPortfolioCategoriesPage() {
if (!isAdminAuthenticated()) {
if (!(await isAdminAuthenticated())) {
redirect("/");
}
async function logoutAction() {
"use server";
clearAdminSessionCookie();
await clearAdminSessionCookie();
redirect("/");
}
+10 -8
View File
@@ -21,31 +21,33 @@ const copy = {
};
type RootPortfolioPageProps = {
searchParams?: {
searchParams?: Promise<{
category?: string;
status?: "all" | "draft" | "published";
success?: string;
error?: string;
};
}>;
};
export default async function RootPortfolioPage({ searchParams }: RootPortfolioPageProps) {
if (!isAdminAuthenticated()) {
const resolvedSearchParams = await searchParams;
if (!(await isAdminAuthenticated())) {
redirect("/");
}
async function logoutAction() {
"use server";
clearAdminSessionCookie();
await clearAdminSessionCookie();
redirect("/");
}
const selectedCategory = searchParams?.category && searchParams.category !== "__all__"
? searchParams.category
const selectedCategory = resolvedSearchParams?.category && resolvedSearchParams.category !== "__all__"
? resolvedSearchParams.category
: "";
const selectedStatus = searchParams?.status === "draft" || searchParams?.status === "published"
? searchParams.status
const selectedStatus = resolvedSearchParams?.status === "draft" || resolvedSearchParams?.status === "published"
? resolvedSearchParams.status
: "all";
const [categories, projects] = await Promise.all([
getAdminPortfolioCategories(),
+7 -5
View File
@@ -44,29 +44,31 @@ const copy = {
};
type RootPortfolioProjectPageProps = {
params: {
params: Promise<{
id: string;
};
}>;
};
export default async function RootPortfolioProjectPage({
params,
}: RootPortfolioProjectPageProps) {
if (!isAdminAuthenticated()) {
if (!(await isAdminAuthenticated())) {
redirect("/");
}
async function logoutAction() {
"use server";
clearAdminSessionCookie();
await clearAdminSessionCookie();
redirect("/");
}
const { id } = await params;
const [categories, mediaOptions, project] = await Promise.all([
getActivePortfolioCategories(),
getMediaOptions(),
getAdminPortfolioProjectById(params.id),
getAdminPortfolioProjectById(id),
]);
if (!project) {
+2 -2
View File
@@ -25,14 +25,14 @@ const copy = {
};
export default async function RootNewPortfolioProjectPage() {
if (!isAdminAuthenticated()) {
if (!(await isAdminAuthenticated())) {
redirect("/");
}
async function logoutAction() {
"use server";
clearAdminSessionCookie();
await clearAdminSessionCookie();
redirect("/");
}
+10 -8
View File
@@ -21,31 +21,33 @@ const copy = {
};
type RootPortfolioProjectsPageProps = {
searchParams?: {
searchParams?: Promise<{
category?: string;
status?: "all" | "draft" | "published";
};
}>;
};
export default async function RootPortfolioProjectsPage({
searchParams,
}: RootPortfolioProjectsPageProps) {
if (!isAdminAuthenticated()) {
const resolvedSearchParams = await searchParams;
if (!(await isAdminAuthenticated())) {
redirect("/");
}
async function logoutAction() {
"use server";
clearAdminSessionCookie();
await clearAdminSessionCookie();
redirect("/");
}
const selectedCategory = searchParams?.category && searchParams.category !== "__all__"
? searchParams.category
const selectedCategory = resolvedSearchParams?.category && resolvedSearchParams.category !== "__all__"
? resolvedSearchParams.category
: "";
const selectedStatus = searchParams?.status === "draft" || searchParams?.status === "published"
? searchParams.status
const selectedStatus = resolvedSearchParams?.status === "draft" || resolvedSearchParams?.status === "published"
? resolvedSearchParams.status
: "all";
const [categories, projects] = await Promise.all([
getAdminPortfolioCategories(),
+5 -5
View File
@@ -3,7 +3,7 @@
import { MediaUsageType } from "@prisma/client";
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { isRedirectError } from "next/dist/client/components/redirect";
import { isRedirectError } from "next/dist/client/components/redirect-error";
import {
SITE_SETTINGS_DEFAULT_OG_IMAGE_FIELD_KEY,
@@ -25,9 +25,9 @@ import { removeManagedMediaFile } from "@/lib/media-storage";
import { mediaFieldInputSchema } from "@/lib/media-validation";
import { prisma } from "@/lib/prisma";
function ensureAdmin() {
if (!isAdminAuthenticated()) {
clearAdminSessionCookie();
async function ensureAdmin() {
if (!(await isAdminAuthenticated())) {
await clearAdminSessionCookie();
redirect("/");
}
}
@@ -91,7 +91,7 @@ async function revalidateSiteSettingsPages() {
}
export async function saveSiteSettingsAction(formData: FormData) {
ensureAdmin();
await ensureAdmin();
const createdMediaAssetIds: string[] = [];
const uploadedPaths: string[] = [];
+2 -2
View File
@@ -30,14 +30,14 @@ const copy = {
};
export default async function RootSiteSettingsPage() {
if (!isAdminAuthenticated()) {
if (!(await isAdminAuthenticated())) {
redirect("/");
}
async function logoutAction() {
"use server";
clearAdminSessionCookie();
await clearAdminSessionCookie();
redirect("/");
}
+6 -6
View File
@@ -2,7 +2,7 @@
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { isRedirectError } from "next/dist/client/components/redirect";
import { isRedirectError } from "next/dist/client/components/redirect-error";
import { toInternalAdminPath } from "@/lib/admin-routing";
import { clearAdminSessionCookie, isAdminAuthenticated } from "@/lib/admin-auth";
@@ -14,9 +14,9 @@ import {
import { sendTestEmail } from "@/lib/mail";
import type { MailSettings } from "@/lib/mail-settings";
function ensureAdmin() {
if (!isAdminAuthenticated()) {
clearAdminSessionCookie();
async function ensureAdmin() {
if (!(await isAdminAuthenticated())) {
await clearAdminSessionCookie();
redirect("/");
}
}
@@ -71,7 +71,7 @@ function parseMailSettingsFormData(
}
export async function saveMailSettingsAction(formData: FormData) {
ensureAdmin();
await ensureAdmin();
try {
const existingMailSettings = await getMailSettings();
@@ -95,7 +95,7 @@ export async function saveMailSettingsAction(formData: FormData) {
}
export async function sendTestEmailAction() {
ensureAdmin();
await ensureAdmin();
try {
await sendTestEmail();
+5 -5
View File
@@ -2,7 +2,7 @@
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { isRedirectError } from "next/dist/client/components/redirect";
import { isRedirectError } from "next/dist/client/components/redirect-error";
import { toInternalAdminPath } from "@/lib/admin-routing";
import { clearAdminSessionCookie, isAdminAuthenticated } from "@/lib/admin-auth";
@@ -13,9 +13,9 @@ import {
} from "@/lib/app-config";
import type { ContactProtectionSettings } from "@/lib/contact-protection";
function ensureAdmin() {
if (!isAdminAuthenticated()) {
clearAdminSessionCookie();
async function ensureAdmin() {
if (!(await isAdminAuthenticated())) {
await clearAdminSessionCookie();
redirect("/");
}
}
@@ -79,7 +79,7 @@ function parseContactProtectionFormData(
}
export async function saveContactProtectionSettingsAction(formData: FormData) {
ensureAdmin();
await ensureAdmin();
try {
const existingSettings = await getContactProtectionSettings();
+2 -2
View File
@@ -26,14 +26,14 @@ const copy = {
};
export default async function RootSMTPProtectionPage() {
if (!isAdminAuthenticated()) {
if (!(await isAdminAuthenticated())) {
redirect("/");
}
async function logoutAction() {
"use server";
clearAdminSessionCookie();
await clearAdminSessionCookie();
redirect("/");
}
+2 -2
View File
@@ -27,14 +27,14 @@ const copy = {
};
export default async function RootSMTPPage() {
if (!isAdminAuthenticated()) {
if (!(await isAdminAuthenticated())) {
redirect("/");
}
async function logoutAction() {
"use server";
clearAdminSessionCookie();
await clearAdminSessionCookie();
redirect("/");
}
+2 -2
View File
@@ -21,7 +21,7 @@ const copy = {
};
export default async function RootUiKitPage() {
const authenticated = isAdminAuthenticated();
const authenticated = await isAdminAuthenticated();
if (!authenticated) {
redirect("/");
@@ -30,7 +30,7 @@ export default async function RootUiKitPage() {
async function logoutAction() {
"use server";
clearAdminSessionCookie();
await clearAdminSessionCookie();
redirect("/");
}