ADDED - Save an unfinished project as a draft
- Add a Save as draft button that bypasses the completeness gate: the user can save partial work and finish later - projectDraftInputSchema makes the user-facing copy (title, summary, service label, client) optional; the action auto-generates a slug from the title (or draft-<timestamp>), defaults the year to the current year, and forces the project unpublished - Drafts drop not-yet-valid sections/assets instead of failing the save - Pass intent via a hidden field set on click so the server reliably sees it - Tests: draft schema accepts empty copy a strict save rejects, and still requires a slug and a valid year
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
||||
import {
|
||||
assetInputSchema,
|
||||
categoryInputSchema,
|
||||
projectDraftInputSchema,
|
||||
projectInputSchema,
|
||||
sectionInputSchema,
|
||||
} from "../lib/portfolio-validation";
|
||||
@@ -65,6 +66,64 @@ describe("portfolio validation", () => {
|
||||
).toThrow(/slug/i);
|
||||
});
|
||||
|
||||
it("draft schema accepts empty user-facing copy that a strict save rejects", () => {
|
||||
const draftPayload = {
|
||||
categoryId: "cat_1",
|
||||
slug: "draft-123",
|
||||
viewMode: "GRID" as const,
|
||||
titleAr: "",
|
||||
titleEn: "",
|
||||
titleDe: "",
|
||||
summaryAr: "",
|
||||
summaryEn: "",
|
||||
summaryDe: "",
|
||||
clientName: "",
|
||||
projectYear: 2026,
|
||||
serviceLabelAr: "",
|
||||
serviceLabelEn: "",
|
||||
serviceLabelDe: "",
|
||||
previewUrl: "",
|
||||
currentCoverImagePath: "",
|
||||
sortOrder: 0,
|
||||
isFeatured: false,
|
||||
isPublished: false,
|
||||
sections: [],
|
||||
assets: [],
|
||||
};
|
||||
|
||||
expect(projectDraftInputSchema.parse(draftPayload).slug).toBe("draft-123");
|
||||
expect(() => projectInputSchema.parse(draftPayload)).toThrow();
|
||||
});
|
||||
|
||||
it("draft schema still requires a slug and a valid year", () => {
|
||||
const base = {
|
||||
categoryId: "cat_1",
|
||||
slug: "draft-1",
|
||||
viewMode: "GRID" as const,
|
||||
titleAr: "",
|
||||
titleEn: "",
|
||||
titleDe: "",
|
||||
summaryAr: "",
|
||||
summaryEn: "",
|
||||
summaryDe: "",
|
||||
clientName: "",
|
||||
projectYear: 2026,
|
||||
serviceLabelAr: "",
|
||||
serviceLabelEn: "",
|
||||
serviceLabelDe: "",
|
||||
previewUrl: "",
|
||||
currentCoverImagePath: "",
|
||||
sortOrder: 0,
|
||||
isFeatured: false,
|
||||
isPublished: false,
|
||||
sections: [],
|
||||
assets: [],
|
||||
};
|
||||
|
||||
expect(() => projectDraftInputSchema.parse({ ...base, slug: "" })).toThrow(/slug/i);
|
||||
expect(() => projectDraftInputSchema.parse({ ...base, projectYear: 1999 })).toThrow();
|
||||
});
|
||||
|
||||
it("accepts valid section and asset payloads", () => {
|
||||
expect(
|
||||
sectionInputSchema.parse({
|
||||
|
||||
Reference in New Issue
Block a user