Skip to content

Commit

Permalink
Merge pull request #8101 from opencrvs/render-fields
Browse files Browse the repository at this point in the history
feat: FormWizard
  • Loading branch information
makelicious authored Nov 28, 2024
2 parents 1f26eed + 8d055ba commit 935abed
Show file tree
Hide file tree
Showing 23 changed files with 361 additions and 257 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ class RejectRegistrationView extends React.Component<IFullProps, IState> {
key="submit_archive"
id="submit_archive"
size="medium"
type="secondary_negative"
type="secondaryNegative"
onClick={() => {
this.props.archiveDeclaration(
payload.id,
Expand Down
33 changes: 16 additions & 17 deletions packages/client/src/v2-events/features/events/PublishEvent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,17 @@ import {
Stack,
Button,
Icon,
Content
Content,
FormWizard
} from '@opencrvs/components'
import React from 'react'
import { useEvent } from './useEvent'
import { useParams } from 'react-router-dom'
import { TextField, Paragraph, DateField } from './registered-fields'

export function PublishEvent() {
const { eventType } = useParams<{ eventType: string }>()
const { title, exit, saveAndExit, previous, next, finish } =
const { title, event, exit, saveAndExit, previous, next, page } =
useEvent(eventType)

return (
Expand Down Expand Up @@ -59,21 +61,18 @@ export function PublishEvent() {
</Frame.SectionFormBackAction>

<Frame.Section>
<Content
title={title}
bottomActionButtons={[
<Button
key="continue"
fullWidth
type="primary"
size="large"
onClick={next ?? finish}
>
Continue
</Button>
]}
>
<b>This is where the form will be rendered</b>
<Content title={title}>
<FormWizard
currentPage={page}
pages={event.actions[0].forms[0].pages}
components={{
TEXT: TextField,
PARAGRAPH: Paragraph,
DATE: DateField
}}
onNextPage={next}
onSubmit={(values) => console.log(values)}
/>
</Content>
</Frame.Section>
</Frame.LayoutForm>
Expand Down
12 changes: 11 additions & 1 deletion packages/client/src/v2-events/features/events/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
*
* Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS.
*/
import { EventConfig } from '@opencrvs/commons/client'

export const tennisClubMembershipEvent = {
id: 'TENNIS_CLUB_MEMBERSHIP',
label: {
Expand Down Expand Up @@ -77,6 +79,14 @@ export const tennisClubMembershipEvent = {
defaultMessage: "Applicant's date of birth",
description: 'This is the label for the field',
id: 'event.tennis-club-membership.action.declare.form.section.who.field.dob.label'
},
options: {
notice: {
id: 'event.tennis-club-membership.action.declare.form.section.who.field.dob.notice',
defaultMessage:
'This is the notice for the date of birth field',
description: 'This is the description for the notice'
}
}
}
]
Expand Down Expand Up @@ -126,4 +136,4 @@ export const tennisClubMembershipEvent = {
]
}
]
}
} satisfies EventConfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* OpenCRVS is also distributed under the terms of the Civil Registration
* & Healthcare Disclaimer located at http://opencrvs.org/license.
*
* Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS.
*/
import React from 'react'
import {
InputField,
useFormContext,
DateField as DateFieldComponent
} from '@opencrvs/components'
import { FieldProps } from '@opencrvs/commons'
import { useIntl } from 'react-intl'

export const DateField = ({ id, options }: FieldProps<'DATE'>) => {
const intl = useIntl()
const { setValue, watch } = useFormContext()
const value = watch(id)

return (
<InputField id={id} touched={false}>
<DateFieldComponent
id={id}
notice={intl.formatMessage(options.notice)}
onChange={(val) => setValue(id, val)}
value={value}
/>
</InputField>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* OpenCRVS is also distributed under the terms of the Civil Registration
* & Healthcare Disclaimer located at http://opencrvs.org/license.
*
* Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS.
*/
import { FieldProps } from '@opencrvs/commons'
import React from 'react'
import { useIntl } from 'react-intl'

export const Paragraph = ({ label }: FieldProps<'PARAGRAPH'>) => {
const intl = useIntl()

return <p>{intl.formatMessage(label)}</p>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* OpenCRVS is also distributed under the terms of the Civil Registration
* & Healthcare Disclaimer located at http://opencrvs.org/license.
*
* Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS.
*/
import React from 'react'
import { InputField, TextInput, useFormContext } from '@opencrvs/components'
import { FieldProps } from '@opencrvs/commons'
import { useIntl } from 'react-intl'

export const TextField = ({ id, label }: FieldProps<'TEXT'>) => {
const intl = useIntl()
const { register } = useFormContext()

return (
<InputField id={id} touched={false} label={intl.formatMessage(label)}>
<TextInput type="text" {...register(id)} />
</InputField>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@
*
* Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS.
*/
declare module 'css-animation'
export * from './TextField'
export * from './DateField'
export * from './Paragraph'
8 changes: 6 additions & 2 deletions packages/client/src/v2-events/features/events/useEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ import { useIntl } from 'react-intl'
import { usePagination } from './usePagination'
import { FieldConfig } from '@opencrvs/commons/client'

const eventTypes = { 'tennis-club-membership': tennisClubMembershipEvent }
const eventTypes = {
'tennis-club-membership': tennisClubMembershipEvent
}

export function useEvent(anyEventType: string) {
const intl = useIntl()
Expand All @@ -24,6 +26,7 @@ export function useEvent(anyEventType: string) {
}

const type = anyEventType as keyof typeof eventTypes
const event = eventTypes[type]
const { pages, label } = eventTypes[type].actions[0].forms[0]

const { next, previous, page } = usePagination(pages.length)
Expand All @@ -42,7 +45,8 @@ export function useEvent(anyEventType: string) {
previous,
next,
finish,
page,
form: pages,
fields: pages[page].fields as FieldConfig[]
event
}
}
42 changes: 20 additions & 22 deletions packages/commons/src/events/FieldConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,39 +11,35 @@
import { z } from 'zod'
import { TranslationConfig } from './TranslationConfig'

const BaseField = z.object({
id: z.string(),
required: z.boolean(),
label: TranslationConfig
})

const TextField = BaseField.describe('Text input').merge(
z.object({
const TextField = z
.object({
type: z.literal('TEXT'),
id: z.string(),
required: z.boolean(),
label: TranslationConfig,
options: z
.object({
maxLength: z.number().describe('Maximum length of the text')
})
.optional()
})
)
.describe('Text input')

const DateField = BaseField.describe('A single date input (dd-mm-YYYY)').merge(
z.object({
const DateField = z
.object({
type: z.literal('DATE'),
options: z
.object({
notice: TranslationConfig.describe(
'Text to display above the date input'
)
})
.optional()
id: z.string(),
required: z.boolean(),
label: TranslationConfig,
options: z.object({
notice: TranslationConfig.describe('Text to display above the date input')
})
})
)
.describe('A single date input (dd-mm-YYYY)')

const Paragraph = BaseField.describe('A read-only HTML <p> paragraph').merge(
z.object({ type: z.literal('PARAGRAPH') })
)
const Paragraph = z
.object({ type: z.literal('PARAGRAPH'), label: TranslationConfig })
.describe('A read-only HTML <p> paragraph')

export const FieldConfig = z.discriminatedUnion('type', [
TextField,
Expand All @@ -52,3 +48,5 @@ export const FieldConfig = z.discriminatedUnion('type', [
])

export type FieldConfig = z.infer<typeof FieldConfig>
export type FieldType = FieldConfig['type']
export type FieldProps<T extends FieldType> = Extract<FieldConfig, { type: T }>
7 changes: 7 additions & 0 deletions packages/commons/src/fixtures/tennis-club-membership-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ export const tennisClubMembershipEvent = defineConfig({
defaultMessage: "Applicant's date of birth",
description: 'This is the label for the field',
id: 'event.tennis-club-membership.action.declare.form.section.who.field.dob.label'
},
options: {
notice: {
id: 'event.tennis-club-membership.action.declare.form.section.who.field.dob.notice',
defaultMessage: 'This is the notice for the field',
description: 'This is the description for the notice'
}
}
}
]
Expand Down
5 changes: 1 addition & 4 deletions packages/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,13 @@
"private": true,
"dependencies": {
"@storybook/core-server": "^7.6.17",
"css-animation": "^2.0.4",
"jest": "29.7.0",
"patch-package": "^6.1.2",
"phosphor-react": "^1.4.1",
"polished": "^4.2.2",
"postinstall-postinstall": "^2.0.0",
"rc-menu": "^7.4.13",
"rc-progress": "^2.5.2",
"react": "18.3.1",
"react-dom": "18.3.1",
"react-hook-form": "^7.53.2",
"react-select": "^2.0.0",
"react-stickynode": "^2.1.1",
"react-tooltip": "^4.2.21",
Expand Down
2 changes: 1 addition & 1 deletion packages/components/src/Button/Button.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export const secondary = css`
}
`

export const secondary_negative = css`
export const secondaryNegative = css`
border: 2px solid ${({ theme }) => theme.colors.negative};
color: ${({ theme }) => theme.colors.negative};
Expand Down
4 changes: 2 additions & 2 deletions packages/components/src/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type ButtonType =
| 'tertiary'
| 'positive'
| 'negative'
| 'secondary_negative'
| 'secondaryNegative'
| 'icon'
| 'iconPrimary'

Expand Down Expand Up @@ -60,7 +60,7 @@ const StyledButton = styled.button.withConfig({
${(props) => props.variant === 'primary' && styles.primary(props)}
${(props) => props.variant === 'secondary' && styles.secondary}
${(props) =>
props.variant === 'secondary_negative' && styles.secondary_negative}
props.variant === 'secondaryNegative' && styles.secondaryNegative}
${(props) => props.variant === 'tertiary' && styles.tertiary}
${(props) => props.variant === 'positive' && styles.positive}
Expand Down
12 changes: 6 additions & 6 deletions packages/components/src/DateField/DateField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*/
import React, { useState, useRef, useEffect } from 'react'
import styled from 'styled-components'
import { ITextInputProps, TextInput, IRef } from '../TextInput/TextInput'
import { ITextInputProps, TextInput } from '../TextInput/TextInput'
import { InputLabel } from '../InputField/InputLabel'

const DateWrapper = styled.div`
Expand Down Expand Up @@ -55,9 +55,9 @@ export const DateField = ({
...props
}: IDateFieldProps) => {
const [date, setDate] = useState<IState>({ yyyy: '', mm: '', dd: '' })
const ddRef = useRef<IRef>(null)
const mmRef = useRef<IRef>(null)
const yyyyRef = useRef<IRef>(null)
const ddRef = useRef<HTMLInputElement>(null)
const mmRef = useRef<HTMLInputElement>(null)
const yyyyRef = useRef<HTMLInputElement>(null)
const { dd, mm, yyyy } = date

useEffect(() => {
Expand All @@ -82,15 +82,15 @@ export const DateField = ({
return
}
if (val.length > 1 && mmRef.current) {
mmRef.current.focusField()
mmRef.current.focus()
}
break
case 'mm':
if (val.length > 2 || Number(val) > MAX_MONTH_NUMBER) {
return
}
if (val.length > 1 && yyyyRef.current) {
yyyyRef.current.focusField()
yyyyRef.current.focus()
}
break
case 'yyyy':
Expand Down
Loading

0 comments on commit 935abed

Please sign in to comment.