Skip to content

Commit

Permalink
Merge pull request #8252 from opencrvs/chore/update-events-structure
Browse files Browse the repository at this point in the history
Chore/update events structure
  • Loading branch information
makelicious authored Dec 20, 2024
2 parents fdd142e + b31657e commit e22eb27
Show file tree
Hide file tree
Showing 13 changed files with 259 additions and 136 deletions.
29 changes: 29 additions & 0 deletions packages/client/src/v2-events/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# V2 Events

Client for managing custom events.

## Directory structure

```
# Reusable components used by features.
/components
# Features used by routes
/features
# Reusable layouts used between features
/layouts
# Route definitions and application structure
/routes
# Route definitions
routes.ts
# Structured route configuration
config.tsx
```

We will be iterating over the structure during the project. Treat it as a starting point. Many times the important thing is to have any structure.

## Development practices

- Do not import components outside v2-events. If you need a component, copy it in and refactor it.
- When building new features, aim to have a separate component that handles interaction with router and data fetching when it makes sense. Features should be route independent, and necessary information (ids and such) should be passed in as props or similar. See (`features/events/actions/register/Register.tsx`)
- Use constants through object pattern. e.g.`ActionType.CREATE` over `'CREATE'`. In most situations, it does not matter. However, changing the names will get much easier.
- When building new features, prefer to import them through `index.ts`. Managing imports will be cleaner and easier that way. See (`/layouts`)
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,14 @@
import React, { useEffect } from 'react'
import { useIntl } from 'react-intl'
import { useLocation, useNavigate, useParams } from 'react-router-dom'
import { FormWizard, Frame, Spinner } from '@opencrvs/components'
import { FormWizard, Spinner } from '@opencrvs/components'
import { FormFieldGenerator } from '@client/v2-events/components/forms/FormFieldGenerator'
import { usePagination } from '@client/v2-events/hooks/usePagination'

import { useEventConfiguration } from '@client/v2-events//features/events/useEventConfiguration'
import { useEventFormData } from '@client/v2-events//features/events/useEventFormData'
import { useEventFormNavigation } from '@client/v2-events//features/events/useEventFormNavigation'
import { useEvents } from '@client/v2-events//features/events/useEvents/useEvents'
import { FormHeader } from '@client/v2-events/features/events/components/FormHeader'
import { ROUTES } from '@client/v2-events/routes'
export function DeclareIndex() {
return (
Expand Down Expand Up @@ -120,10 +119,7 @@ function Declare() {
const page = pages[currentPage]

return (
<Frame
header={<FormHeader label={configuration.label} />}
skipToContentText="Skip to form"
>
<>
{modal}
<FormWizard
currentPage={currentPage}
Expand All @@ -148,6 +144,6 @@ function Declare() {
}}
/>
</FormWizard>
</Frame>
</>
)
}
163 changes: 78 additions & 85 deletions packages/client/src/v2-events/features/events/components/Preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import { FormConfig } from '@opencrvs/commons/client'
import {
Accordion,
Button,
Frame,
Icon,
Link,
ResponsiveModal,
Expand All @@ -26,7 +25,6 @@ import {
Stack
} from '@opencrvs/components'
import { EventConfig } from '@opencrvs/commons'
import { FormHeader } from '@client/v2-events/features/events/components/FormHeader'

const Row = styled.div<{
position?: 'left' | 'center'
Expand Down Expand Up @@ -179,91 +177,86 @@ function PreviewComponent({
const intl = useIntl()

return (
<Frame
header={<FormHeader label={eventConfig.label} />}
skipToContentText="Skip to form"
>
<Row>
<LeftColumn>
<Card>
<HeaderContainer>
<HeaderContent>
<Stack
alignItems="flex-start"
direction="column"
gap={6}
justify-content="flex-start"
>
<TitleContainer id={`header_title`}>
{eventConfig.label.defaultMessage}
</TitleContainer>
<SubjectContainer id={`header_subject`}>
{title}
</SubjectContainer>
</Stack>
</HeaderContent>
</HeaderContainer>
<FormData>
<ReviewContainter>
{formConfig.pages.map((page) => {
return (
<DeclarationDataContainer
key={'Section_' + page.title.defaultMessage}
<Row>
<LeftColumn>
<Card>
<HeaderContainer>
<HeaderContent>
<Stack
alignItems="flex-start"
direction="column"
gap={6}
justify-content="flex-start"
>
<TitleContainer id={`header_title`}>
{eventConfig.label.defaultMessage}
</TitleContainer>
<SubjectContainer id={`header_subject`}>
{title}
</SubjectContainer>
</Stack>
</HeaderContent>
</HeaderContainer>
<FormData>
<ReviewContainter>
{formConfig.pages.map((page) => {
return (
<DeclarationDataContainer
key={'Section_' + page.title.defaultMessage}
>
<Accordion
action={
<Link
onClick={(e) => {
e.stopPropagation()
onEdit({ pageId: page.id })
}}
>
{intl.formatMessage(previewMessages.changeButton)}
</Link>
}
expand={true}
label={intl.formatMessage(page.title)}
labelForHideAction="Hide"
labelForShowAction="Show"
name={'Accordion_' + page.id}
>
<Accordion
action={
<Link
onClick={(e) => {
e.stopPropagation()
onEdit({ pageId: page.id })
}}
>
{intl.formatMessage(previewMessages.changeButton)}
</Link>
}
expand={true}
label={intl.formatMessage(page.title)}
labelForHideAction="Hide"
labelForShowAction="Show"
name={'Accordion_' + page.id}
>
<ListReview id={'Section_' + page.id}>
{page.fields.map((field) => (
<ListReview.Row
key={field.id}
actions={
<Link
onClick={(e) => {
e.stopPropagation()
<ListReview id={'Section_' + page.id}>
{page.fields.map((field) => (
<ListReview.Row
key={field.id}
actions={
<Link
onClick={(e) => {
e.stopPropagation()

onEdit({
pageId: page.id,
fieldId: field.id
})
}}
>
{intl.formatMessage(
previewMessages.changeButton
)}
</Link>
}
id={field.id}
label={intl.formatMessage(field.label)}
value={form[field.id] || ''}
/>
))}
</ListReview>
</Accordion>
</DeclarationDataContainer>
)
})}
</ReviewContainter>
</FormData>
</Card>
{children}
</LeftColumn>
</Row>
</Frame>
onEdit({
pageId: page.id,
fieldId: field.id
})
}}
>
{intl.formatMessage(
previewMessages.changeButton
)}
</Link>
}
id={field.id}
label={intl.formatMessage(field.label)}
value={form[field.id] || ''}
/>
))}
</ListReview>
</Accordion>
</DeclarationDataContainer>
)
})}
</ReviewContainter>
</FormData>
</Card>
{children}
</LeftColumn>
</Row>
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,10 +249,6 @@ utils.event.create.setMutationDefaults(({ canonicalMutationFn }) => ({
]
}

await queryClient.cancelQueries({
queryKey: EVENTS_PERSISTENT_STORE_STORAGE_KEY
})

// Do this as very first synchronous operation so UI can trust
// that the event is created when changing view for instance
queryClient.setQueryData(
Expand All @@ -262,6 +258,10 @@ utils.event.create.setMutationDefaults(({ canonicalMutationFn }) => ({
}
)

await queryClient.cancelQueries({
queryKey: EVENTS_PERSISTENT_STORE_STORAGE_KEY
})

const events = await readEventsFromStorage()

await writeEventsToStorage([...events, optimisticEvent])
Expand Down Expand Up @@ -301,12 +301,15 @@ const observer = new QueryObserver<EventDocument[]>(queryClient, {
queryKey: EVENTS_PERSISTENT_STORE_STORAGE_KEY
})

observer.subscribe((event) => {
event.data?.forEach((e) => {
queryClient.setQueryData(getQueryKey(api.event.get, e.id, 'query'), event)
observer.subscribe((observerEvent) => {
observerEvent.data?.forEach((event) => {
queryClient.setQueryData(
getQueryKey(api.event.get, event.id, 'query'),
event
)

queryClient.setQueryData(
getQueryKey(api.event.get, e.transactionId, 'query'),
getQueryKey(api.event.get, event.transactionId, 'query'),
event
)
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import { ActionMenu } from './components/ActionMenu'
*/

export function EventOverviewIndex() {
const params = useTypedParams(ROUTES.V2.EVENTS.EVENT)
const params = useTypedParams(ROUTES.V2.EVENTS.OVERVIEW)
const { getEvents, getEventById } = useEvents()
const user = useSelector(getUserDetails)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,11 @@ export function WorkqueueIndex() {
)
}

type EventWithSyncStatus = EventIndex & { inOutbox?: boolean }

/**
* A Workqueue that displays a table of events based on search criteria.
*/

type EventWithSyncStatus = EventIndex & { inOutbox?: boolean }

function Workqueue({
events,
config,
Expand Down Expand Up @@ -163,7 +162,7 @@ function Workqueue({
/>
) : (
<NondecoratedLink
to={ROUTES.V2.EVENTS.EVENT.buildPath({
to={ROUTES.V2.EVENTS.OVERVIEW.buildPath({
eventId: event.id
})}
>
Expand Down
59 changes: 59 additions & 0 deletions packages/client/src/v2-events/layouts/form/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* 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 { useTypedParams } from 'react-router-typesafe-routes/dom'

import { Frame, Spinner } from '@opencrvs/components'
import { useEventConfiguration } from '@client/v2-events/features/events/useEventConfiguration'
import { useEvents } from '@client/v2-events/features/events/useEvents/useEvents'
import { ROUTES } from '@client/v2-events/routes'
import { FormHeader } from './FormHeader'

type AllowedRoute =
| typeof ROUTES.V2.EVENTS.REGISTER
| typeof ROUTES.V2.EVENTS.DECLARE

/**
* Layout for form and review pages.
*
*/
export function FormLayout({
route,
children
}: {
route: AllowedRoute
children: React.ReactNode
}) {
const { eventId } = useTypedParams(route)
const events = useEvents()

const [event] = events.getEvent(eventId)

const { eventConfiguration: configuration } = useEventConfiguration(
event.type
)

if (!configuration) {
throw new Error('Event configuration not found')
}

return (
<Frame
header={<FormHeader label={configuration.label} />}
skipToContentText="Skip to form"
>
<React.Suspense fallback={<Spinner id="event-form-spinner" />}>
{children}
</React.Suspense>
</Frame>
)
}
Loading

0 comments on commit e22eb27

Please sign in to comment.