Phase 1-14 complete: - Unified Express.js API (TypeScript, Prisma ORM, PostgreSQL 16) - React Admin GUI (Vite + Ant Design + Zustand) - JWT auth with refresh tokens - Influence: Campaigns, Representatives, Responses, Email Queue - Map: Locations, Cuts, Shifts, Canvassing System - NAR data import infrastructure (2025 format) - Listmonk newsletter integration - Landing page builder (GrapesJS) - MkDocs + Code Server integration - Volunteer portal with GPS tracking - Monitoring stack (Prometheus, Grafana, Alertmanager) - Pangolin tunnel integration Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
89 lines
2.3 KiB
TypeScript
89 lines
2.3 KiB
TypeScript
import { Prisma } from '@prisma/client';
|
|
import { prisma } from '../../config/database';
|
|
import { AppError } from '../../middleware/error-handler';
|
|
import type { CreatePageBlockInput, UpdatePageBlockInput, ListPageBlocksInput } from './pages.schemas';
|
|
|
|
const blockSelect = {
|
|
id: true,
|
|
type: true,
|
|
label: true,
|
|
schema: true,
|
|
defaults: true,
|
|
thumbnail: true,
|
|
category: true,
|
|
sortOrder: true,
|
|
createdAt: true,
|
|
updatedAt: true,
|
|
} satisfies Prisma.PageBlockSelect;
|
|
|
|
export const blocksService = {
|
|
async findAll(filters: ListPageBlocksInput) {
|
|
const where: Prisma.PageBlockWhereInput = {};
|
|
|
|
if (filters.category) {
|
|
where.category = filters.category;
|
|
}
|
|
|
|
return prisma.pageBlock.findMany({
|
|
where,
|
|
select: blockSelect,
|
|
orderBy: { sortOrder: 'asc' },
|
|
});
|
|
},
|
|
|
|
async findById(id: string) {
|
|
const block = await prisma.pageBlock.findUnique({
|
|
where: { id },
|
|
select: blockSelect,
|
|
});
|
|
|
|
if (!block) {
|
|
throw new AppError(404, 'Page block not found', 'BLOCK_NOT_FOUND');
|
|
}
|
|
|
|
return block;
|
|
},
|
|
|
|
async create(data: CreatePageBlockInput) {
|
|
return prisma.pageBlock.create({
|
|
data: {
|
|
...data,
|
|
schema: data.schema as unknown as Prisma.InputJsonValue,
|
|
defaults: data.defaults as unknown as Prisma.InputJsonValue,
|
|
},
|
|
select: blockSelect,
|
|
});
|
|
},
|
|
|
|
async update(id: string, data: UpdatePageBlockInput) {
|
|
const existing = await prisma.pageBlock.findUnique({ where: { id } });
|
|
if (!existing) {
|
|
throw new AppError(404, 'Page block not found', 'BLOCK_NOT_FOUND');
|
|
}
|
|
|
|
const updateData: Prisma.PageBlockUncheckedUpdateInput = { ...data };
|
|
|
|
if (data.schema !== undefined) {
|
|
updateData.schema = data.schema as unknown as Prisma.InputJsonValue;
|
|
}
|
|
if (data.defaults !== undefined) {
|
|
updateData.defaults = data.defaults as unknown as Prisma.InputJsonValue;
|
|
}
|
|
|
|
return prisma.pageBlock.update({
|
|
where: { id },
|
|
data: updateData,
|
|
select: blockSelect,
|
|
});
|
|
},
|
|
|
|
async delete(id: string) {
|
|
const existing = await prisma.pageBlock.findUnique({ where: { id } });
|
|
if (!existing) {
|
|
throw new AppError(404, 'Page block not found', 'BLOCK_NOT_FOUND');
|
|
}
|
|
|
|
await prisma.pageBlock.delete({ where: { id } });
|
|
},
|
|
};
|