Refactor portfolio admin and views

This commit is contained in:
MOH
2026-03-11 17:46:35 +01:00
parent 3c53430b12
commit 7956b073e9
27 changed files with 1972 additions and 1779 deletions
+4 -2
View File
@@ -1,4 +1,4 @@
import { PortfolioAssetKind, PortfolioSectionType } from "@prisma/client";
import { PortfolioSectionType } from "@prisma/client";
import { z } from "zod";
import { mediaFieldInputSchema } from "./media-validation";
@@ -10,6 +10,7 @@ const requiredText = (label: string) =>
.min(1, `${label} is required.`);
const optionalTrimmedText = z.string().trim().optional().transform((value) => value ?? "");
const portfolioProjectViewModes = ["GRID", "STORY", "CASE_STUDY"] as const;
export const categoryInputSchema = z.object({
id: z.string().trim().optional(),
@@ -83,7 +84,7 @@ export const sectionInputSchema = z
export const assetInputSchema = z.object({
id: z.string().trim().optional(),
kind: z.nativeEnum(PortfolioAssetKind),
kind: z.literal("IMAGE"),
filePath: optionalTrimmedText,
fileFieldName: optionalTrimmedText,
media: mediaFieldInputSchema.optional(),
@@ -98,6 +99,7 @@ export const projectInputSchema = z.object({
categoryId: requiredText("Project categoryId"),
slug: requiredText("Project slug")
.regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, "Project slug must be lowercase and hyphenated."),
viewMode: z.enum(portfolioProjectViewModes).default("GRID"),
titleAr: requiredText("Project titleAr"),
titleEn: requiredText("Project titleEn"),
titleDe: requiredText("Project titleDe"),
+24 -1
View File
@@ -1,4 +1,10 @@
import type { Category, PortfolioAsset, PortfolioProject, PortfolioSection } from "@prisma/client";
import type {
Category,
PortfolioAsset,
PortfolioProject,
PortfolioProjectViewMode,
PortfolioSection,
} from "@prisma/client";
import { getPortfolioMediaBindings } from "@/lib/media";
import type { AppLocale } from "@/lib/locale";
@@ -42,6 +48,7 @@ type ProjectRecord = Pick<
PortfolioProject,
| "id"
| "slug"
| "viewMode"
| "titleAr"
| "titleEn"
| "titleDe"
@@ -99,6 +106,7 @@ export type PortfolioAssetView = {
export type PortfolioProjectView = {
id: string;
slug: string;
viewMode: PortfolioProjectViewMode;
title: LocalizedContent;
summary: LocalizedContent;
clientName: string;
@@ -116,6 +124,20 @@ export type PortfolioProjectView = {
assets: PortfolioAssetView[];
};
export function resolvePortfolioProjectViewMode(
value: string | null | undefined,
): PortfolioProjectViewMode {
switch (value) {
case "STORY":
return "STORY";
case "CASE_STUDY":
return "CASE_STUDY";
case "GRID":
default:
return "GRID";
}
}
function mapLocalizedContent(record: Record<string, unknown>, prefix: string): LocalizedContent {
return {
ar: String(record[`${prefix}Ar`] ?? ""),
@@ -174,6 +196,7 @@ function mapProject(
return {
id: record.id,
slug: record.slug,
viewMode: resolvePortfolioProjectViewMode(record.viewMode),
title: mapLocalizedContent(record, "title"),
summary: mapLocalizedContent(record, "summary"),
clientName: record.clientName,