Skip to content

Commit

Permalink
AB#19680
Browse files Browse the repository at this point in the history
  • Loading branch information
Stefwint committed Jul 22, 2024
1 parent ec84a69 commit ea4b6d2
Show file tree
Hide file tree
Showing 9 changed files with 331 additions and 26 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"type": "module",
"dependencies": {
"@headlessui/react": "^1.7.17",
"@pzh-ui/components": "^0.0.546",
"@pzh-ui/components": "^0.0.548",
"@pzh-ui/config": "^0.0.70",
"@pzh-ui/css": "^0.0.97",
"@pzh-ui/icons": "^0.0.61",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,21 @@ import {
FormikRte,
FormikSelect,
FormikTextArea,
RteMenuButton,
} from '@pzh-ui/components'
import { DrawPolygon } from '@pzh-ui/icons'
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'
import { DynamicField as DynamicFieldProps } from '@/config/types'
import useModalStore from '@/store/modalStore'
import { fileToBase64 } from '@/utils/file'

import DynamicObjectSearch from '../../DynamicObjectSearch'
import { Area } from './extensions/area'

const inputFieldMap = {
text: FormikInput,
Expand All @@ -40,6 +44,7 @@ const DynamicField = ({
model?: Model
}) => {
const { setFieldValue, values } = useFormikContext()
const setActiveModal = useModalStore(state => state.setActiveModal)

const InputField = inputFieldMap[type]
if (!InputField) {
Expand Down Expand Up @@ -85,6 +90,24 @@ const DynamicField = ({
{...(type === 'select' && {
blurInputOnSelect: true,
})}
{...(type === 'wysiwyg' && {
customExtensions: [Area],
customMenuButtons: editor => (
<RteMenuButton
isActive={editor.isActive('area')}
onClick={() =>
setActiveModal('objectAreaAnnotate', {
editor,
})
}
aria-label="Gebiedsaanwijzing"
title="Gebiedsaanwijzing">
<DrawPolygon />
</RteMenuButton>
),
className:
'[&_[data-gebiedengroep]]:text-pzh-blue-900 [&_[data-gebiedengroep]]:bg-pzh-blue-10 [&_[data-gebiedengroep]]:inline-block',
})}
{...field}
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { Mark, mergeAttributes } from '@tiptap/core'

declare module '@tiptap/core' {
interface Commands<ReturnType> {
area: {
setArea: (attributes: {
'data-gebiedengroep': string
'data-type': string
'data-gebiedsaanwijzing': string
text?: string
}) => ReturnType
}
}
}

/**
* This extension allows you to insert areas.
*/
export const Area = Mark.create({
name: 'area',

addOptions() {
return {
HTMLAttributes: {
href: '#',
'data-gebiedengroep': null,
'data-type': null,
'data-gebiedsaanwijzing': null,
},
}
},

addAttributes() {
return {
href: {
default: this.options.HTMLAttributes.href,
},
'data-gebiedengroep': {
default: this.options.HTMLAttributes['data-gebiedengroep'],
},
'data-type': {
default: this.options.HTMLAttributes['data-type'],
},
'data-gebiedsaanwijzing': {
default: this.options.HTMLAttributes['data-gebiedsaanwijzing'],
},
}
},

renderHTML({ HTMLAttributes }) {
return [
'a',
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),
0,
]
},

addCommands() {
return {
setArea:
attributes =>
({ chain, state }) => {
const { empty } = state.selection

if (empty) {
const { text = 'default text', ...rest } = attributes
return chain()
.insertContentAt(state.selection.anchor, [
{
type: 'text',
text,
marks: [
{
type: this.name,
attrs: rest,
},
],
},
])
.run()
} else {
return chain().setMark(this.name, attributes).run()
}
},
}
},
})
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { FieldSelectProps } from '@pzh-ui/components'
import { Form, Formik, FormikHelpers, FormikProps, FormikValues } from 'formik'
import { useMemo } from 'react'
import { toFormikValidationSchema } from 'zod-formik-adapter'

import ButtonSubmitFixed from '@/components/ButtonSubmitFixed'
import { LoaderSpinner } from '@/components/Loader'
import ObjectAreaAnnotateModal from '@/components/Modals/ObjectModals/ObjectAreaAnnotateModal'
import ScrollToFieldError from '@/components/ScrollToFieldError'
import { Model } from '@/config/objects/types'
import { usePrompt } from '@/hooks/usePrompt'
Expand Down Expand Up @@ -72,6 +74,14 @@ const ObjectForm = <TData extends FormikValues>({
FormikProps<TData>) => {
const sections = model.dynamicSections

const containsRteField = useMemo(
() =>
sections.some(section =>
section.fields.some(field => field.type === 'wysiwyg')
),
[sections]
)

/**
* Show prompt message when leaving the page without saving changes
*/
Expand All @@ -81,28 +91,32 @@ const ObjectForm = <TData extends FormikValues>({
)

return (
<Form>
<div className="grid grid-cols-6 gap-x-10 gap-y-0">
{sections?.map((section, index) => (
<DynamicSection
key={`section-${index}`}
isLast={index + 1 === sections.length}
isLocked={isLocked}
model={model}
defaultValues={defaultValues}
{...section}
/>
))}
</div>
<>
<Form>
<div className="grid grid-cols-6 gap-x-10 gap-y-0">
{sections?.map((section, index) => (
<DynamicSection
key={`section-${index}`}
isLast={index + 1 === sections.length}
isLocked={isLocked}
model={model}
defaultValues={defaultValues}
{...section}
/>
))}
</div>

<ButtonSubmitFixed
onCancel={onCancel}
disabled={isSubmitting || isLoading || isLocked || !canEdit}
isLoading={isSubmitting}
/>

<ButtonSubmitFixed
onCancel={onCancel}
disabled={isSubmitting || isLoading || isLocked || !canEdit}
isLoading={isSubmitting}
/>
<ScrollToFieldError />
</Form>

<ScrollToFieldError />
</Form>
{containsRteField && <ObjectAreaAnnotateModal />}
</>
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
import { Button, FormikSelect } from '@pzh-ui/components'
import { Form, Formik } from 'formik'
import { useMemo } from 'react'
import { z } from 'zod'
import { toFormikValidationSchema } from 'zod-formik-adapter'

import Modal from '@/components/Modal'
import useModalStore from '@/store/modalStore'
import { SCHEMA_OBJECT_ANNOTATE_AREA } from '@/validation/objectAnnotate'

import { ModalStateMap } from '../../types'

type Values = z.infer<typeof SCHEMA_OBJECT_ANNOTATE_AREA>

const ObjectAreaAnnotateModal = () => {
const setActiveModal = useModalStore(state => state.setActiveModal)
const modalState = useModalStore(
state => state.modalStates['objectAreaAnnotate']
) as ModalStateMap['objectAreaAnnotate']

const groupOptions = [
{
label: 'Gebiedengroep 1',
value: 'group-1',
},
]

const areaTypeOptions = [{ label: 'Type 1', value: 'type-1' }]

const areaGroupOptions = [
{
label: 'Gebiedengroep 1',
value: 'group-1',
},
]

const isEmptySelection = useMemo(
() => modalState?.editor.state.selection.empty,
[modalState?.editor.state.selection.empty]
)

const hasValues = useMemo(
() => {
const values = modalState?.editor?.getAttributes('area')

return !!values && !!Object.keys(values).length
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[modalState?.editor, modalState?.editor?.state.selection]
)

const initialValues: Values = useMemo(() => {
const previousValues = modalState?.editor?.getAttributes('area')

return {
group: previousValues?.['data-gebiedengroep'] ?? '',
areaType: previousValues?.['data-type'] ?? '',
areaGroup: previousValues?.['data-gebiedsaanwijzing'] ?? '',
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [modalState?.editor, modalState?.editor?.state.selection])

const handleSubmit = (payload: Values) => {
const groupName = groupOptions.find(
option => option.value === payload.group
)?.label

modalState?.editor
?.chain()
.focus()
.extendMarkRange('area')
.setArea({
'data-gebiedengroep': payload.group,
'data-type': payload.areaType,
'data-gebiedsaanwijzing': payload.areaGroup,
text: isEmptySelection ? groupName : undefined,
})
.run()

setActiveModal(null)
}

return (
<Modal
id="objectAreaAnnotate"
title="Gebiedsaanwijzing toevoegen"
size="m">
<Formik
onSubmit={handleSubmit}
initialValues={initialValues}
enableReinitialize
validationSchema={toFormikValidationSchema(
SCHEMA_OBJECT_ANNOTATE_AREA
)}>
{({ isValid, isSubmitting, dirty }) => (
<Form>
<div className="space-y-4">
<div>
<FormikSelect
name="group"
label="Gebiedengroep"
placeholder="Selecteer een gebiedengroep"
options={groupOptions}
required
/>
</div>
<div>
<FormikSelect
name="areaType"
label="Type gebiedsaanwijzing"
placeholder="Selecteer een type gebiedsaanwijzing"
options={areaTypeOptions}
required
/>
</div>
<div>
<FormikSelect
name="areaGroup"
label="Gebiedsaanwijzinggroep"
placeholder="Selecteer een gebiedsaanwijzinggroep"
options={areaGroupOptions}
required
/>
</div>
</div>

<div className="mt-6 flex items-center justify-between">
{!hasValues ? (
<Button
variant="link"
onPress={() => setActiveModal(null)}>
Annuleren
</Button>
) : (
<Button
variant="link"
onPress={() => {
modalState?.editor
?.chain()
.focus()
.extendMarkRange('area')
.unsetMark('area')
.run()
setActiveModal(null)
}}
className="text-pzh-red-500">
Gebiedsaanwijzing verwijderen
</Button>
)}
<Button
variant="cta"
type="submit"
isDisabled={!isValid || isSubmitting || !dirty}
isLoading={isSubmitting}>
Opslaan
</Button>
</div>
</Form>
)}
</Formik>
</Modal>
)
}

export default ObjectAreaAnnotateModal
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './ObjectAreaAnnotateModal'
Loading

0 comments on commit ea4b6d2

Please sign in to comment.