feat: configureerbare itemnamen per vragenlijst
Voeg item_label en item_label_plural toe aan questionnaires (migratie), beheerformulier en dynamische teksten in UI en API-fouten. Standaard blijft Activiteit/Activiteiten. Negeer tsbuildinfo en geëmitteerde vite.config.js/.d.ts in .gitignore. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -5,7 +5,14 @@ import multer, { FileFilterCallback } from 'multer';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { userOps, questionnaireOps, activityOps, participantOps } from '../database.js';
|
||||
import {
|
||||
userOps,
|
||||
questionnaireOps,
|
||||
activityOps,
|
||||
participantOps,
|
||||
resolveItemLabels,
|
||||
DEFAULT_ITEM_LABEL,
|
||||
} from '../database.js';
|
||||
import { requireAuth } from '../middleware/auth.js';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
@@ -74,9 +81,17 @@ function isValidSlug(slug: string): boolean {
|
||||
return /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug);
|
||||
}
|
||||
|
||||
function parseItemLabelsFromBody(itemLabel: unknown, itemLabelPlural: unknown): { singular: string; plural: string } {
|
||||
return resolveItemLabels({
|
||||
item_label: typeof itemLabel === 'string' ? itemLabel : null,
|
||||
item_label_plural: typeof itemLabelPlural === 'string' ? itemLabelPlural : null,
|
||||
});
|
||||
}
|
||||
|
||||
// Create questionnaire
|
||||
router.post('/questionnaires', (req: Request, res: Response) => {
|
||||
const { title, description, slug, ogImage, isPrivate } = req.body;
|
||||
const { title, description, slug, ogImage, isPrivate, itemLabel, itemLabelPlural } = req.body;
|
||||
const { singular, plural } = parseItemLabelsFromBody(itemLabel, itemLabelPlural);
|
||||
|
||||
if (!title?.trim()) {
|
||||
res.status(400).json({ error: 'Titel is verplicht' });
|
||||
@@ -106,7 +121,17 @@ router.post('/questionnaires', (req: Request, res: Response) => {
|
||||
}
|
||||
|
||||
const uuid = uuidv4();
|
||||
const id = questionnaireOps.create(uuid, cleanSlug, title.trim(), description?.trim() || null, ogImage?.trim() || null, !!isPrivate, req.session.user!.id);
|
||||
const id = questionnaireOps.create(
|
||||
uuid,
|
||||
cleanSlug,
|
||||
title.trim(),
|
||||
description?.trim() || null,
|
||||
ogImage?.trim() || null,
|
||||
!!isPrivate,
|
||||
req.session.user!.id,
|
||||
singular,
|
||||
plural
|
||||
);
|
||||
const questionnaire = questionnaireOps.findById(id);
|
||||
|
||||
res.json({ success: true, questionnaire });
|
||||
@@ -127,7 +152,8 @@ router.get('/questionnaires/:id', (req: Request, res: Response) => {
|
||||
|
||||
// Update questionnaire
|
||||
router.put('/questionnaires/:id', (req: Request, res: Response) => {
|
||||
const { title, description, slug, ogImage, isPrivate } = req.body;
|
||||
const { title, description, slug, ogImage, isPrivate, itemLabel, itemLabelPlural } = req.body;
|
||||
const { singular, plural } = parseItemLabelsFromBody(itemLabel, itemLabelPlural);
|
||||
const questionnaire = questionnaireOps.findById(parseInt(req.params.id));
|
||||
|
||||
if (!questionnaire) {
|
||||
@@ -162,7 +188,16 @@ router.put('/questionnaires/:id', (req: Request, res: Response) => {
|
||||
return;
|
||||
}
|
||||
|
||||
questionnaireOps.update(questionnaire.id, cleanSlug, title.trim(), description?.trim() || null, ogImage?.trim() || null, !!isPrivate);
|
||||
questionnaireOps.update(
|
||||
questionnaire.id,
|
||||
cleanSlug,
|
||||
title.trim(),
|
||||
description?.trim() || null,
|
||||
ogImage?.trim() || null,
|
||||
!!isPrivate,
|
||||
singular,
|
||||
plural
|
||||
);
|
||||
res.json({ success: true });
|
||||
});
|
||||
|
||||
@@ -267,12 +302,15 @@ router.put('/activities/:id', (req: Request, res: Response) => {
|
||||
const activity = activityOps.findById(parseInt(req.params.id));
|
||||
|
||||
if (!activity) {
|
||||
res.status(404).json({ error: 'Activiteit niet gevonden' });
|
||||
res.status(404).json({ error: `${DEFAULT_ITEM_LABEL} niet gevonden` });
|
||||
return;
|
||||
}
|
||||
|
||||
const q = questionnaireOps.findById(activity.questionnaire_id);
|
||||
const itemSingular = q ? resolveItemLabels(q).singular : DEFAULT_ITEM_LABEL;
|
||||
|
||||
if (!name?.trim()) {
|
||||
res.status(400).json({ error: 'Naam activiteit is verplicht' });
|
||||
res.status(400).json({ error: `Naam ${itemSingular.toLowerCase()} is verplicht` });
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user