feat(pages): add pages and navigation builder baseline
This commit is contained in:
@@ -16,6 +16,18 @@ export {
|
||||
listMediaFoundationGroups,
|
||||
updateMediaAsset,
|
||||
} from "./media-foundation"
|
||||
export {
|
||||
createNavigationItem,
|
||||
createNavigationMenu,
|
||||
createPage,
|
||||
deleteNavigationItem,
|
||||
deletePage,
|
||||
getPageById,
|
||||
listNavigationMenus,
|
||||
listPages,
|
||||
updateNavigationItem,
|
||||
updatePage,
|
||||
} from "./pages-navigation"
|
||||
export {
|
||||
createPost,
|
||||
deletePost,
|
||||
|
||||
92
packages/db/src/pages-navigation.test.ts
Normal file
92
packages/db/src/pages-navigation.test.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest"
|
||||
|
||||
const { mockDb } = vi.hoisted(() => ({
|
||||
mockDb: {
|
||||
page: {
|
||||
create: vi.fn(),
|
||||
update: vi.fn(),
|
||||
delete: vi.fn(),
|
||||
findUnique: vi.fn(),
|
||||
findMany: vi.fn(),
|
||||
},
|
||||
navigationMenu: {
|
||||
create: vi.fn(),
|
||||
findMany: vi.fn(),
|
||||
},
|
||||
navigationItem: {
|
||||
create: vi.fn(),
|
||||
update: vi.fn(),
|
||||
delete: vi.fn(),
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock("./client", () => ({
|
||||
db: mockDb,
|
||||
}))
|
||||
|
||||
import {
|
||||
createNavigationItem,
|
||||
createNavigationMenu,
|
||||
createPage,
|
||||
updatePage,
|
||||
} from "./pages-navigation"
|
||||
|
||||
describe("pages-navigation service", () => {
|
||||
beforeEach(() => {
|
||||
for (const value of Object.values(mockDb)) {
|
||||
for (const fn of Object.values(value)) {
|
||||
if (typeof fn === "function") {
|
||||
fn.mockReset()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it("creates published pages with publishedAt", async () => {
|
||||
mockDb.page.create.mockResolvedValue({ id: "page-1" })
|
||||
|
||||
await createPage({
|
||||
title: "About",
|
||||
slug: "about",
|
||||
status: "published",
|
||||
content: "hello",
|
||||
})
|
||||
|
||||
expect(mockDb.page.create).toHaveBeenCalledTimes(1)
|
||||
expect(mockDb.page.create.mock.calls[0]?.[0].data.publishedAt).toBeInstanceOf(Date)
|
||||
})
|
||||
|
||||
it("updates page status publication timestamp", async () => {
|
||||
mockDb.page.update.mockResolvedValue({ id: "page-1" })
|
||||
|
||||
await updatePage({
|
||||
id: "550e8400-e29b-41d4-a716-446655440000",
|
||||
status: "draft",
|
||||
})
|
||||
|
||||
expect(mockDb.page.update).toHaveBeenCalledTimes(1)
|
||||
expect(mockDb.page.update.mock.calls[0]?.[0].data.publishedAt).toBeNull()
|
||||
})
|
||||
|
||||
it("creates menus and items with schema parsing", async () => {
|
||||
mockDb.navigationMenu.create.mockResolvedValue({ id: "menu-1" })
|
||||
mockDb.navigationItem.create.mockResolvedValue({ id: "item-1" })
|
||||
|
||||
await createNavigationMenu({
|
||||
name: "Primary",
|
||||
slug: "primary",
|
||||
location: "header",
|
||||
})
|
||||
|
||||
await createNavigationItem({
|
||||
menuId: "550e8400-e29b-41d4-a716-446655440001",
|
||||
label: "Home",
|
||||
href: "/",
|
||||
sortOrder: 0,
|
||||
})
|
||||
|
||||
expect(mockDb.navigationMenu.create).toHaveBeenCalledTimes(1)
|
||||
expect(mockDb.navigationItem.create).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
109
packages/db/src/pages-navigation.ts
Normal file
109
packages/db/src/pages-navigation.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import {
|
||||
createNavigationItemInputSchema,
|
||||
createNavigationMenuInputSchema,
|
||||
createPageInputSchema,
|
||||
updateNavigationItemInputSchema,
|
||||
updatePageInputSchema,
|
||||
} from "@cms/content"
|
||||
|
||||
import { db } from "./client"
|
||||
|
||||
function resolvePublishedAt(status: string): Date | null {
|
||||
return status === "published" ? new Date() : null
|
||||
}
|
||||
|
||||
export async function listPages(limit = 50) {
|
||||
return db.page.findMany({
|
||||
orderBy: [{ updatedAt: "desc" }],
|
||||
take: limit,
|
||||
})
|
||||
}
|
||||
|
||||
export async function getPageById(id: string) {
|
||||
return db.page.findUnique({
|
||||
where: { id },
|
||||
})
|
||||
}
|
||||
|
||||
export async function createPage(input: unknown) {
|
||||
const payload = createPageInputSchema.parse(input)
|
||||
|
||||
return db.page.create({
|
||||
data: {
|
||||
...payload,
|
||||
publishedAt: resolvePublishedAt(payload.status),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export async function updatePage(input: unknown) {
|
||||
const payload = updatePageInputSchema.parse(input)
|
||||
const { id, ...data } = payload
|
||||
|
||||
return db.page.update({
|
||||
where: { id },
|
||||
data: {
|
||||
...data,
|
||||
publishedAt:
|
||||
data.status === undefined ? undefined : data.status === "published" ? new Date() : null,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export async function deletePage(id: string) {
|
||||
return db.page.delete({
|
||||
where: { id },
|
||||
})
|
||||
}
|
||||
|
||||
export async function listNavigationMenus() {
|
||||
return db.navigationMenu.findMany({
|
||||
orderBy: [{ location: "asc" }, { name: "asc" }],
|
||||
include: {
|
||||
items: {
|
||||
orderBy: [{ sortOrder: "asc" }, { label: "asc" }],
|
||||
include: {
|
||||
page: {
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
slug: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export async function createNavigationMenu(input: unknown) {
|
||||
const payload = createNavigationMenuInputSchema.parse(input)
|
||||
|
||||
return db.navigationMenu.create({
|
||||
data: payload,
|
||||
})
|
||||
}
|
||||
|
||||
export async function createNavigationItem(input: unknown) {
|
||||
const payload = createNavigationItemInputSchema.parse(input)
|
||||
|
||||
return db.navigationItem.create({
|
||||
data: payload,
|
||||
})
|
||||
}
|
||||
|
||||
export async function updateNavigationItem(input: unknown) {
|
||||
const payload = updateNavigationItemInputSchema.parse(input)
|
||||
const { id, ...data } = payload
|
||||
|
||||
return db.navigationItem.update({
|
||||
where: { id },
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
export async function deleteNavigationItem(id: string) {
|
||||
return db.navigationItem.delete({
|
||||
where: { id },
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user