diff --git a/src/App/Routes/AppRoutes.tsx b/src/App/Routes/AppRoutes.tsx index 96b10439..283b66f9 100644 --- a/src/App/Routes/AppRoutes.tsx +++ b/src/App/Routes/AppRoutes.tsx @@ -16,6 +16,9 @@ import { ObjectDetail, ObjectEdit, ObjectWrite, + PublicationTemplateCreate, + PublicationTemplateEdit, + PublicationTemplateOverview, Regulations, UserDetail, UsersOverview, @@ -382,6 +385,47 @@ const AppRoutes = () => { }, ], }, + { + path: 'publicatietemplates', + children: [ + { + index: true, + element: ( + + + + ), + }, + { + path: ':uuid', + element: ( + + + + ), + }, + { + path: 'nieuw', + element: ( + + + + ), + }, + ], + }, ], }, { diff --git a/src/components/DynamicObject/DynamicObjectForm/DynamicField/DynamicField.tsx b/src/components/DynamicObject/DynamicObjectForm/DynamicField/DynamicField.tsx index a01e2155..d5405bc1 100644 --- a/src/components/DynamicObject/DynamicObjectForm/DynamicField/DynamicField.tsx +++ b/src/components/DynamicObject/DynamicObjectForm/DynamicField/DynamicField.tsx @@ -7,6 +7,7 @@ import { } from '@pzh-ui/components' import { useFormikContext } from 'formik' +import FieldArray from '@/components/Form/FieldArray' import FieldConnections from '@/components/Form/FieldConnections' import FieldSelectArea from '@/components/Form/FieldSelectArea' import { Model } from '@/config/objects/types' @@ -25,6 +26,7 @@ const inputFieldMap = { image: FormikFileUpload, connections: FieldConnections, search: DynamicObjectSearch, + array: FieldArray, } const DynamicField = ({ diff --git a/src/components/Form/FieldArray/FieldArray.tsx b/src/components/Form/FieldArray/FieldArray.tsx new file mode 100644 index 00000000..c4897d9b --- /dev/null +++ b/src/components/Form/FieldArray/FieldArray.tsx @@ -0,0 +1,90 @@ +import { Button, FieldLabel, Text } from '@pzh-ui/components' +import { Plus, Xmark } from '@pzh-ui/icons' +import { + ArrayHelpers, + FieldArray as FormikFieldArray, + FormikValues, + useFormikContext, +} from 'formik' + +import DynamicObjectField from '@/components/DynamicObject/DynamicObjectForm/DynamicField' +import { Model } from '@/config/objects/types' +import { DynamicField } from '@/config/types' + +const FieldArray = ({ + name, + label, + arrayLabel, + description, + required, + fields, + model, +}: Omit, 'type'> & { + model: Model +}) => { + const { values } = useFormikContext() + + const groupChildren: any[] = values?.[name] + + return ( + <> + {label && ( + + )} + + ( +
+ {groupChildren?.map((child, childIndex) => ( +
+
+ {!!arrayLabel && ( + {arrayLabel} + )} + +
+ {fields.map(field => ( + + ))} +
+ ))} + +
+ +
+
+ )} + /> + + ) +} + +export default FieldArray diff --git a/src/components/Form/FieldArray/index.ts b/src/components/Form/FieldArray/index.ts new file mode 100644 index 00000000..fc42e5c6 --- /dev/null +++ b/src/components/Form/FieldArray/index.ts @@ -0,0 +1 @@ +export { default } from './FieldArray' diff --git a/src/config/types.ts b/src/config/types.ts index 41891c82..6d753648 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -15,6 +15,7 @@ type DynamicFieldType = | 'image' | 'connections' | 'search' + | 'array' export type DynamicSection = { /** Title of section */ @@ -46,7 +47,8 @@ export type DynamicField = { ImageProps & WysiwygProps & ConnectionsProps & - SearchProps + SearchProps & + ArrayProps type SelectProps = | { type: 'select'; options: { label: string; value: string }[] } @@ -91,3 +93,9 @@ type SearchProps = | { type: Exclude } + +type ArrayProps = + | { type: 'array'; fields: DynamicField[]; arrayLabel?: string } + | { + type: Exclude + } diff --git a/src/pages/protected/PublicationTemplates/PublicationTemplateCreate/PublicationTemplateCreate.tsx b/src/pages/protected/PublicationTemplates/PublicationTemplateCreate/PublicationTemplateCreate.tsx new file mode 100644 index 00000000..81273e91 --- /dev/null +++ b/src/pages/protected/PublicationTemplates/PublicationTemplateCreate/PublicationTemplateCreate.tsx @@ -0,0 +1,64 @@ +import { Heading } from '@pzh-ui/components' +import { useMemo } from 'react' +import { useNavigate } from 'react-router-dom' + +import DynamicObjectForm from '@/components/DynamicObject/DynamicObjectForm' +import MutateLayout from '@/templates/MutateLayout' + +import { model } from '../model' + +const PublicationTemplateCreate = () => { + const navigate = useNavigate() + + const { plural, pluralCapitalize, singularCapitalize } = model.defaults + + /** + * Format initialData based on object fields + */ + const initialData = useMemo(() => { + const fields = model.dynamicSections.flatMap(section => + section.fields.map(field => field.name) + ) + + const objectData = {} as { [key in (typeof fields)[number]]: any } + + fields?.forEach(field => { + return (objectData[field] = null) + }) + + return objectData + }, []) + + const handleSubmit = () => {} + + const breadcrumbPaths = [ + { name: 'Dashboard', path: '/muteer' }, + { + name: pluralCapitalize, + path: `/muteer/${plural}`, + }, + { name: `${singularCapitalize} toevoegen`, isCurrent: true }, + ] + + return ( + +
+ + {singularCapitalize} toevoegen + + + navigate(`/muteer/${plural}`)} + isLoading={false} + /> +
+
+ ) +} + +export default PublicationTemplateCreate diff --git a/src/pages/protected/PublicationTemplates/PublicationTemplateCreate/index.ts b/src/pages/protected/PublicationTemplates/PublicationTemplateCreate/index.ts new file mode 100644 index 00000000..e878a328 --- /dev/null +++ b/src/pages/protected/PublicationTemplates/PublicationTemplateCreate/index.ts @@ -0,0 +1 @@ +export { default } from './PublicationTemplateCreate' diff --git a/src/pages/protected/PublicationTemplates/PublicationTemplateEdit/PublicationTemplateEdit.tsx b/src/pages/protected/PublicationTemplates/PublicationTemplateEdit/PublicationTemplateEdit.tsx new file mode 100644 index 00000000..6d690a76 --- /dev/null +++ b/src/pages/protected/PublicationTemplates/PublicationTemplateEdit/PublicationTemplateEdit.tsx @@ -0,0 +1,66 @@ +import { Heading } from '@pzh-ui/components' +import { useMemo } from 'react' +import { useNavigate } from 'react-router-dom' + +import DynamicObjectForm from '@/components/DynamicObject/DynamicObjectForm' +import MutateLayout from '@/templates/MutateLayout' + +import { model } from '../model' + +const PublicationTemplateEdit = () => { + const navigate = useNavigate() + + const { plural, pluralCapitalize, singularCapitalize } = model.defaults + + const data = useMemo(() => {}, []) + + /** + * Format initialData based on object fields + */ + const initialData = useMemo(() => { + const fields = model.dynamicSections.flatMap(section => + section.fields.map(field => field.name) + ) + + const objectData = {} as { [key in (typeof fields)[number]]: any } + + fields?.forEach(field => { + return (objectData[field] = data?.[field as keyof typeof data]) + }) + + return objectData + }, [data]) + + const handleSubmit = () => {} + + const breadcrumbPaths = [ + { name: 'Dashboard', path: '/muteer' }, + { + name: pluralCapitalize, + path: `/muteer/${plural}`, + }, + { name: `${singularCapitalize} bewerken`, isCurrent: true }, + ] + + return ( + +
+ + {singularCapitalize} bewerken + + + navigate(`/muteer/${plural}`)} + isLoading={false} + /> +
+
+ ) +} + +export default PublicationTemplateEdit diff --git a/src/pages/protected/PublicationTemplates/PublicationTemplateEdit/index.ts b/src/pages/protected/PublicationTemplates/PublicationTemplateEdit/index.ts new file mode 100644 index 00000000..01d0c5a1 --- /dev/null +++ b/src/pages/protected/PublicationTemplates/PublicationTemplateEdit/index.ts @@ -0,0 +1 @@ +export { default } from './PublicationTemplateEdit' diff --git a/src/pages/protected/PublicationTemplates/PublicationTemplateOverview/PublicationTemplateOverview.tsx b/src/pages/protected/PublicationTemplates/PublicationTemplateOverview/PublicationTemplateOverview.tsx new file mode 100644 index 00000000..1089c811 --- /dev/null +++ b/src/pages/protected/PublicationTemplates/PublicationTemplateOverview/PublicationTemplateOverview.tsx @@ -0,0 +1,123 @@ +import { Button, Heading, Table, formatDate } from '@pzh-ui/components' +import { AngleRight } from '@pzh-ui/icons' +import { useMemo } from 'react' +import { useNavigate } from 'react-router-dom' + +import { LoaderSpinner } from '@/components/Loader' +import MutateLayout from '@/templates/MutateLayout' + +import { model } from '../model' + +const PublicationTemplateOverview = () => { + const navigate = useNavigate() + + const { plural, pluralCapitalize, prefixNewObject, singularReadable } = + model.defaults + + const isFetching = false + + const data = useMemo( + () => [ + { + Title: 'Visie WWW', + UUID: '1', + Instrument: 'Visie', + Created_Date: '2021-08-09T05:32:29.417000', + }, + { + Title: 'Visie Herziening 2024', + UUID: '2', + Instrument: 'Visie', + Created_Date: '2021-08-09T05:32:29.417000', + }, + ], + [] + ) + + /** + * Setup Table columns + */ + const columns = useMemo( + () => [ + { + header: 'Titel', + accessorKey: 'Title', + }, + { + header: 'Instrument', + accessorKey: 'Instrument', + }, + { + header: 'Aanmaakdatum', + accessorKey: 'Created_Date', + }, + ], + [] + ) + + /** + * Format data before passing to Table + */ + const formattedData = useMemo( + () => + data?.map(({ Title, Instrument, Created_Date, UUID }) => ({ + Title, + Instrument, + Created_Date: ( + + {formatDate( + new Date(Created_Date + 'Z'), + 'cccccc d MMMM yyyy, p' + )} + + + ), + onClick: () => navigate(`/muteer/${plural}/${UUID}`), + })) || [], + [data, plural, navigate] + ) + + const breadcrumbPaths = [ + { name: 'Dashboard', path: '/muteer' }, + { name: pluralCapitalize, isCurrent: true }, + ] + + return ( + +
+
+ {pluralCapitalize} + + +
+ +
+ {!!formattedData?.length ? ( + + ) : !isFetching ? ( + + Er zijn geen {plural} gevonden + + ) : ( +
+ +
+ )} + + + + ) +} + +export default PublicationTemplateOverview diff --git a/src/pages/protected/PublicationTemplates/PublicationTemplateOverview/index.ts b/src/pages/protected/PublicationTemplates/PublicationTemplateOverview/index.ts new file mode 100644 index 00000000..c32faa63 --- /dev/null +++ b/src/pages/protected/PublicationTemplates/PublicationTemplateOverview/index.ts @@ -0,0 +1 @@ +export { default } from './PublicationTemplateOverview' diff --git a/src/pages/protected/PublicationTemplates/model.ts b/src/pages/protected/PublicationTemplates/model.ts new file mode 100644 index 00000000..7933c872 --- /dev/null +++ b/src/pages/protected/PublicationTemplates/model.ts @@ -0,0 +1,88 @@ +// @ts-nocheck +import { CalendarCheck } from '@pzh-ui/icons' + +import { Model } from '@/config/objects/types' +import { schemaDefaults } from '@/validation/zodSchema' + +export const model: Model = { + defaults: { + singular: 'publicatietemplate', + singularReadable: 'publicatietemplate', + singularCapitalize: 'Publicatietemplate', + plural: 'publicatietemplates', + pluralCapitalize: 'Publicatietemplates', + prefixSingular: 'de', + prefixPlural: 'de', + prefixNewObject: 'Nieuwe', + demonstrative: 'deze', + icon: CalendarCheck, + }, + dynamicSections: [ + { + title: 'Instrument, titel en omschrijving', + description: + 'Geef aan voor welk instrument dit template is, en geef er een titel en omschrijving aan', + fields: [ + { + name: 'Title', + label: 'Titel', + type: 'text', + required: true, + validation: schemaDefaults.title, + }, + { + type: 'select', + label: 'Instrument', + placeholder: 'Kies het instrument', + name: 'Instrument', + options: [ + { label: 'Visie', value: 'Visie' }, + { label: 'Programma', value: 'Programma' }, + ], + required: true, + }, + { + name: 'Description', + label: 'Omschrijving', + type: 'textarea', + }, + ], + }, + { + title: 'Text template', + description: + 'Geef aan hoe de template er uit moet komen te zien voor de export. Je kunt hier object templates gebruiken. Deze moet je hieronder definiƫren.', + fields: [ + { + name: 'Text_Template', + label: 'Text template', + type: 'textarea', + }, + ], + }, + { + title: 'Object template', + description: + 'Geef per gebruikt object aan hoe het moet worden getoond in de export.', + fields: [ + { + name: 'Object_Template', + arrayLabel: 'Object Template', + type: 'array', + fields: [ + { + type: 'text', + placeholder: 'key', + name: 'Key', + }, + { + type: 'textarea', + placeholder: 'value', + name: 'Value', + }, + ], + }, + ], + }, + ], +} diff --git a/src/pages/protected/index.ts b/src/pages/protected/index.ts index 4ffb3ecd..868661e0 100644 --- a/src/pages/protected/index.ts +++ b/src/pages/protected/index.ts @@ -7,21 +7,27 @@ import DynamicOverview from './DynamicOverview' import ModuleCreate from './Modules/ModuleCreate' import ModuleDetail from './Modules/ModuleDetail' import ModuleEdit from './Modules/ModuleEdit' +import PublicationTemplateCreate from './PublicationTemplates/PublicationTemplateCreate' +import PublicationTemplateEdit from './PublicationTemplates/PublicationTemplateEdit' +import PublicationTemplateOverview from './PublicationTemplates/PublicationTemplateOverview' import Regulations from './Regulations' import UserDetail from './Users/UserDetail' import UsersOverview from './Users/UsersOverview' export { Dashboard, - ObjectEdit, - ObjectDetail, - ObjectCreate, - ObjectWrite, DynamicOverview, ModuleCreate, ModuleDetail, ModuleEdit, + ObjectCreate, + ObjectDetail, + ObjectEdit, + ObjectWrite, + PublicationTemplateCreate, + PublicationTemplateEdit, + PublicationTemplateOverview, Regulations, - UsersOverview, UserDetail, + UsersOverview, }