Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 51 additions & 76 deletions next/src/components/questionnaires/form/QuestionnaireForm.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { zodResolver } from '@hookform/resolvers/zod'
import { useNavigate } from '@tanstack/react-router'
import { Controller, type SubmitHandler, useForm } from 'react-hook-form'
import { type SubmitHandler, useForm } from 'react-hook-form'
import { useTranslation } from 'react-i18next'

import Checkbox from '@/components/ui/form/Checkbox'
import Field from '@/components/ui/form/Field'
import Form from '@/components/ui/form/Form'
import FormField from '@/components/ui/form/FormField'
import Input from '@/components/ui/form/Input'
import Label from '@/components/ui/form/Label'
import RadioGroup from '@/components/ui/form/RadioGroup'
Expand Down Expand Up @@ -76,31 +76,24 @@ export default function QuestionnaireForm({
isSubmitted={isSubmitted}
validateLabel={submitLabel}
>
<Controller
name="title"
<FormField
control={control}
render={({
field: { name, value, onChange },
fieldState: { invalid, isTouched, isDirty, error },
}) => (
<Field
dirty={isDirty}
error={error}
invalid={invalid}
label={t('common.title')}
name={name}
required
touched={isTouched}
>
<Input autoFocus value={value} onValueChange={onChange} />
</Field>
name="title"
label={t('common.title')}
required
>
{({ field: { value, onChange } }) => (
<Input autoFocus value={value} onValueChange={onChange} />
)}
/>
<Controller
name="targetModes"
</FormField>

<FormField
control={control}
name="targetModes"
rules={{ required: true }}
render={({ field, fieldState: { error } }) => (
noField
>
{({ field, fieldState: { error } }) => (
<>
<Label required>{t('questionnaire.common.targetMode')}</Label>
<div className="flex gap-x-4">
Expand Down Expand Up @@ -150,68 +143,50 @@ export default function QuestionnaireForm({
) : null}
</>
)}
/>
</FormField>

<div>
<Controller
name="flowLogic"
<FormField
control={control}
name="flowLogic"
label={t('questionnaire.common.dynamicField')}
required
rules={{ required: true }}
render={({
field: { name, value, onBlur, onChange },
fieldState: { invalid, isTouched, isDirty, error },
}) => (
<Field
dirty={isDirty}
error={error}
invalid={invalid}
label={t('questionnaire.common.dynamicField')}
name={name}
required
touched={isTouched}
>
<RadioGroup
options={[
{ label: 'Filtre', value: FlowLogics.Filter },
{ label: 'Redirection', value: FlowLogics.Redirection },
]}
value={value}
onBlur={onBlur}
onValueChange={onChange}
/>
</Field>
>
{({ field: { value, onBlur, onChange } }) => (
<RadioGroup
options={[
{ label: 'Filtre', value: FlowLogics.Filter },
{ label: 'Redirection', value: FlowLogics.Redirection },
]}
value={value}
onBlur={onBlur}
onValueChange={onChange}
/>
)}
/>
</FormField>
</div>

<div>
<Controller
name="formulasLanguage"
<FormField
control={control}
name="formulasLanguage"
label={t('questionnaire.common.formulaField')}
required
rules={{ required: true }}
render={({
field: { name, value, onBlur, onChange },
fieldState: { invalid, isTouched, isDirty, error },
}) => (
<Field
dirty={isDirty}
error={error}
invalid={invalid}
label={t('questionnaire.common.formulaField')}
name={name}
required
touched={isTouched}
>
<RadioGroup
options={[
{ label: 'VTL', value: FormulasLanguages.VTL },
{ label: 'XPath', value: FormulasLanguages.XPath },
]}
value={value}
onBlur={onBlur}
onValueChange={onChange}
/>
</Field>
>
{({ field: { value, onBlur, onChange } }) => (
<RadioGroup
options={[
{ label: 'VTL', value: FormulasLanguages.VTL },
{ label: 'XPath', value: FormulasLanguages.XPath },
]}
value={value}
onBlur={onBlur}
onValueChange={onChange}
/>
)}
/>
</FormField>
</div>
</Form>
)
Expand Down
94 changes: 94 additions & 0 deletions next/src/components/ui/form/FormField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import {
type Control,
Controller,
type ControllerRenderProps,
type FieldPath,
type FieldPathValue,
type FieldValues,
type RegisterOptions,
} from 'react-hook-form'

import Field, { type Props as FieldProps } from './Field'

type RenderProps<T extends FieldValues, N extends FieldPath<T>> = {
field: ControllerRenderProps<T, N>
fieldState: {
invalid: boolean
isDirty: boolean
isTouched: boolean
error?: FieldProps['error']
}
}

type FormFieldProps<T extends FieldValues, N extends FieldPath<T>> = {
control: Control<T>
name: N
defaultValue?: FieldPathValue<T, N>
label?: FieldProps['label']
description?: FieldProps['description']

Check warning on line 28 in next/src/components/ui/form/FormField.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Consider removing 'undefined' type or '?' specifier, one of them is redundant.

See more on https://sonarcloud.io/project/issues?id=inseefr_pogues-next&issues=AZ-FKK_hkIHhbILjiz8f&open=AZ-FKK_hkIHhbILjiz8f&pullRequest=1184
required?: boolean
disabled?: boolean
rules?: Omit<
RegisterOptions<T, N>,
'valueAsNumber' | 'valueAsDate' | 'setValueAs' | 'disabled'
>
noField?: boolean
/** Input component such as Select, NumberFieldm etc.. */
children: (props: RenderProps<T, N>) => React.ReactNode
}

/**
* A component that encapsulate both form and controller layout
*/
export default function FormField<
T extends FieldValues,
N extends FieldPath<T>,
>({
control,
name,
defaultValue,
label,
description,
required = false,
disabled = false,
rules,
noField = false,
children,
}: Readonly<FormFieldProps<T, N>>) {
return (
<Controller
control={control}
name={name}
defaultValue={defaultValue}
rules={rules}
render={({
field,
fieldState: { invalid, isTouched, isDirty, error },
}) => {
const renderProps: RenderProps<T, N> = {
field,
fieldState: { invalid, isTouched, isDirty, error },
}
// VTL editor field do not have <Field>
if (noField) {
return <>{children(renderProps)}</>
}
return (
<Field
dirty={isDirty}
error={error}
invalid={invalid}
label={label}
name={field.name}
required={required}
touched={isTouched}
description={description}
disabled={disabled}
>
{children(renderProps)}
</Field>
)
}}
/>
)
}
Loading
Loading