Skip to content

Commit

Permalink
Events v2: Use the same UI components in new event selector that were…
Browse files Browse the repository at this point in the history
… used in the old one (#8131)
  • Loading branch information
rikukissa authored Dec 3, 2024
1 parent 1a289cc commit 041940d
Show file tree
Hide file tree
Showing 11 changed files with 174 additions and 101 deletions.
4 changes: 2 additions & 2 deletions packages/client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ import {
import { Workqueues } from './v2-events/features/workqueues'
import { EventFormWizardIndex } from './v2-events/features/events/EventFormWizard'
import { TRPCProvider } from './v2-events/trcp'
import { Events } from './v2-events/features/events/EventSelection'
import { EventSelection } from './v2-events/features/events/EventSelection'

interface IAppProps {
client?: ApolloClient<NormalizedCacheObject>
Expand Down Expand Up @@ -538,7 +538,7 @@ export function App(props: IAppProps) {
<ProtectedRoute
exact
path={V2_EVENTS_ROUTE}
component={Events}
component={EventSelection}
/>
<ProtectedRoute
exact
Expand Down
3 changes: 2 additions & 1 deletion packages/client/src/v2-events/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ module.exports = {
'@client/*',
'!@client/v2-events',
'!@client/components',
'!@client/utils'
'!@client/utils',
'!@client/navigation'
]
}
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
FormWizard
} from '@opencrvs/components'
import React from 'react'
import { useEvent } from './useEvent'
import { useEventConfiguration } from './useEventConfiguration'
import { useParams } from 'react-router-dom'
import { useEventForm } from './useEventForm'
import { EventConfig } from '@opencrvs/commons/client'
Expand All @@ -33,7 +33,7 @@ import {
export function EventFormWizardIndex() {
const { eventType } = useParams<{ eventType: string }>()

const { event, isLoading } = useEvent(eventType)
const { event, isLoading } = useEventConfiguration(eventType)

if (isLoading) {
return <div>Loading...</div>
Expand Down
208 changes: 136 additions & 72 deletions packages/client/src/v2-events/features/events/EventSelection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,98 +9,162 @@
* Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS.
*/

import React from 'react'

import { EventType } from '@client/utils/gateway'
import { AppBar } from '@opencrvs/components/lib/AppBar'
import { Button } from '@opencrvs/components/lib/Button'
import { Content, ContentSize } from '@opencrvs/components/lib/Content'
import { ErrorText } from '@opencrvs/components/lib/ErrorText'
import { Frame } from '@opencrvs/components/lib/Frame'
import { Icon } from '@opencrvs/components/lib/Icon'
import { RadioButton } from '@opencrvs/components/lib/Radio'
import { Stack } from '@opencrvs/components/lib/Stack'
import React, { useState } from 'react'
import {
Frame,
AppBar,
Button,
Icon,
Content,
ContentSize,
FormWizard,
Values,
Spinner
} from '@opencrvs/components'
import { V2_EVENT_ROUTE } from '@client/v2-events/routes'

import { trpc } from '@client/v2-events/trcp'
import { formatUrl } from './utils'
WrappedComponentProps as IntlShapeProps,
defineMessages,
injectIntl,
useIntl
} from 'react-intl'
import { connect } from 'react-redux'
import { useEventConfigurations } from './useEventConfiguration'
import { V2_EVENT_ROUTE, V2_ROOT_ROUTE } from '@client/v2-events/routes'
import { useHistory } from 'react-router-dom'
import { RadioGroup } from './registered-fields/RadioGroup'
import { formatUrl } from '@client/navigation'

const messages = defineMessages({
registerNewEventTitle: {
id: 'register.selectVitalEvent.registerNewEventTitle',
defaultMessage: 'New declaration',
description: 'The title that appears on the select vital event page'
},
registerNewEventHeading: {
id: 'register.selectVitalEvent.registerNewEventHeading',
defaultMessage: 'What type of event do you want to declare?',
description: 'The section heading on the page'
},
continueButton: {
defaultMessage: 'Continue',
description: 'Continue Button Text',
id: 'buttons.continue'
},
errorMessage: {
id: 'register.selectVitalEvent.errorMessage',
defaultMessage: 'Please select the type of event',
description: 'Error Message to show when no event is being selected'
},
exitButton: {
defaultMessage: 'EXIT',
description: 'Label for Exit button on EventTopBar',
id: 'buttons.exit'
}
})

const constantsMessages = defineMessages({
skipToMainContent: {
defaultMessage: 'Skip to main content',
description:
'Label for a keyboard accessibility link which skips to the main content',
id: 'constants.skipToMainContent'
}
})

export const Events = () => {
export const EventSelection = (props: IntlShapeProps) => {
const intl = useIntl()
const history = useHistory()
const { data, isLoading } = trpc.config.get.useQuery()
const events = useEventConfigurations()
const [eventType, setEventType] = useState('')
const [noEventSelectedError, setNoEventSelectedError] = useState(false)

const events = data ?? []
const goToHome = () => {
history.push(V2_ROOT_ROUTE)
}

const onSubmit = ({ eventType }: Values) => {
if (eventType) {
history.push(
formatUrl(V2_EVENT_ROUTE, {
eventType
})
)
const handleContinue = () => {
if (eventType === '') {
return setNoEventSelectedError(true)
}

history.push(
formatUrl(V2_EVENT_ROUTE, {
eventType
})
)
}

return (
<Frame
header={
<AppBar
title="OpenCRVS"
desktopLeft="Declaration"
desktopLeft={<Icon name="Draft" size="large" />}
desktopTitle={intl.formatMessage(messages.registerNewEventTitle)}
desktopRight={
<Button type="secondary" onClick={() => {}}>
<Button
id="goBack"
type="secondary"
size="small"
onClick={goToHome}
>
<Icon name="X" />
{intl.formatMessage(messages.exitButton)}
</Button>
}
mobileLeft={<Icon name="Draft" size="large" />}
mobileTitle={intl.formatMessage(messages.registerNewEventTitle)}
mobileRight={
<Button type="icon" size="medium" onClick={goToHome}>
<Icon name="X" />
Exit
</Button>
}
/>
}
skipToContentText="Skip to main content"
skipToContentText={intl.formatMessage(
constantsMessages.skipToMainContent
)}
>
<Frame.Layout>
<Frame.Section>
<Content size={ContentSize.SMALL} title="Event type">
{isLoading ? (
<Spinner id="event-type-spinner" />
) : (
<FormWizard
currentPage={0}
pages={[
{
fields: [
{
name: 'eventType',
type: 'RADIO_GROUP',
required: true,
label: {
defaultMessage: 'Select an event',
description: 'Select an event',
id: 'event.select.label'
},
options: events.map((event) => ({
value: event.id,
label: event.label.defaultMessage
}))
}
]
}
]}
components={{
RADIO_GROUP: RadioGroup
}}
defaultValues={{
eventType: events[0]?.id
}}
onSubmit={onSubmit}
/>
)}
</Content>
</Frame.Section>
</Frame.Layout>
<Content
size={ContentSize.SMALL}
title={intl.formatMessage(messages.registerNewEventHeading)}
bottomActionButtons={[
<Button
key="select-vital-event-continue"
id="continue"
type="primary"
size="large"
fullWidth
onClick={handleContinue}
>
{intl.formatMessage(messages.continueButton)}
</Button>
]}
>
{noEventSelectedError && (
<ErrorText id="require-error">
{intl.formatMessage(messages.errorMessage)}
</ErrorText>
)}
<Stack
id="select_vital_event_view"
direction="column"
alignItems="left"
gap={0}
>
{events.data?.map((event) => (
<RadioButton
size="large"
key={`${event.id}event`}
name={`${event.id}event`}
label={intl.formatMessage(event.label)}
value={event.id}
id="select_birth_event"
selected={eventType === event.id ? event.id : ''}
onChange={() => {
setEventType(event.id)
setNoEventSelectedError(false)
}}
/>
))}
</Stack>
</Content>
</Frame>
)
}
8 changes: 0 additions & 8 deletions packages/client/src/v2-events/features/events/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,6 @@ 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
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
import { FieldProps } from '@opencrvs/commons'
import { useIntl } from 'react-intl'

export const DateField = ({ id, options }: FieldProps<'DATE'>) => {
export const DateField = ({ id, options = {} }: FieldProps<'DATE'>) => {
const intl = useIntl()
const { setValue, watch } = useFormContext()
const value = watch(id)
Expand All @@ -26,7 +26,7 @@ export const DateField = ({ id, options }: FieldProps<'DATE'>) => {
<InputField id={id} touched={false}>
<DateFieldComponent
id={id}
notice={intl.formatMessage(options.notice)}
notice={options.notice && intl.formatMessage(options.notice)}
onChange={(val) => setValue(id, val)}
value={value}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,27 @@
import { trpc } from '@client/v2-events/trcp'

/**
* Fetches configures events and finds a matching event
* Fetches configured events and finds a matching event
* @returns a list of event configurations
*/
export function useEventConfigurations() {
const res = trpc.config.get.useQuery()
const { failureReason } = res
if (failureReason) {
// eslint-disable-next-line no-console
console.error(failureReason?.data?.stack)
}

return res
}

/**
* Fetches configured events and finds a matching event
* @param eventIdentifier e.g. 'birth', 'death', 'marriage' or any configured event
* @returns event configuration
*/
export function useEvent(eventIdentifier: string) {
const hook = trpc.config.get.useQuery()
export function useEventConfiguration(eventIdentifier: string) {
const hook = useEventConfigurations()
const { error, data, isFetching } = hook

const event = data?.find((event) => event.id === eventIdentifier)
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/v2-events/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@

export const V2_ROOT_ROUTE = '/v2'
export const V2_EVENTS_ROUTE = `${V2_ROOT_ROUTE}/event`
export const V2_EVENT_ROUTE = `${V2_EVENTS_ROUTE}/event/:eventType`
export const V2_EVENT_ROUTE = `${V2_EVENTS_ROUTE}/:eventType`
10 changes: 7 additions & 3 deletions packages/commons/src/events/FieldConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,13 @@ const DateField = z
id: z.string(),
required: z.boolean(),
label: TranslationConfig,
options: z.object({
notice: TranslationConfig.describe('Text to display above the date input')
})
options: z
.object({
notice: TranslationConfig.describe(
'Text to display above the date input'
).optional()
})
.optional()
})
.describe('A single date input (dd-mm-YYYY)')

Expand Down
7 changes: 0 additions & 7 deletions packages/commons/src/fixtures/tennis-club-membership-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,6 @@ 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
4 changes: 4 additions & 0 deletions packages/events/nodemon.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"watch": ["src/**", "../commons/build/**"],
"ext": "js,ts"
}

0 comments on commit 041940d

Please sign in to comment.