Skip to content

Commit f2e2b31

Browse files
authored
Merge branch 'develop' into ocrvs-10132
2 parents 46d3d86 + 11c0b17 commit f2e2b31

File tree

12 files changed

+502
-40
lines changed

12 files changed

+502
-40
lines changed

.github/workflows/build-images-from-branch.yml

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,7 @@ jobs:
6060
strategy:
6161
fail-fast: false
6262
matrix:
63-
runner: ${{
64-
((github.ref_type == 'tag' || inputs.build_arm == true) && fromJSON('["ubuntu-24.04", "ubuntu-24.04-arm"]')) ||
65-
fromJSON('["ubuntu-24.04"]')
66-
}}
63+
runner: ${{ (inputs.build_arm == true && fromJSON('["ubuntu-24.04", "ubuntu-24.04-arm"]')) || fromJSON('["ubuntu-24.04"]') }}
6764
runs-on: ${{ matrix.runner }}
6865
steps:
6966
- uses: actions/checkout@v5
@@ -143,7 +140,7 @@ jobs:
143140
password: ${{ secrets.GHCR_PUBLISH_TOKEN }}
144141
- name: Create and push multi-arch manifest
145142
env:
146-
BUILD_ARM: ${{ github.ref_type == 'tag' || inputs.build_arm == true }}
143+
BUILD_ARM: ${{ inputs.build_arm == true }}
147144
run: |
148145
REPO="ghcr.io/opencrvs/ocrvs-base"
149146
for TAG in ${{ needs.base.outputs.branch }} ${{ needs.base.outputs.version }}; do
@@ -162,7 +159,7 @@ jobs:
162159
fail-fast: false
163160
matrix:
164161
runner: ${{
165-
((github.ref_type == 'tag' || inputs.build_arm == true) && fromJSON('["ubuntu-24.04", "ubuntu-24.04-arm"]')) ||
162+
(inputs.build_arm == true && fromJSON('["ubuntu-24.04", "ubuntu-24.04-arm"]')) ||
166163
fromJSON('["ubuntu-24.04"]')
167164
}}
168165
service: ${{ fromJSON(needs.base.outputs.services) }}
@@ -230,7 +227,7 @@ jobs:
230227

231228
- name: Create and push multi-arch manifest
232229
env:
233-
BUILD_ARM: ${{ github.ref_type == 'tag' || inputs.build_arm == true }}
230+
BUILD_ARM: ${{ inputs.build_arm == true }}
234231
run: |
235232
REPO_PREFIX="ghcr.io/opencrvs/ocrvs"
236233

packages/client/src/v2-events/features/events/actions/print-certificate/PrintCertificate.interaction.stories.tsx

Lines changed: 109 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,19 @@ import superjson from 'superjson'
1515

1616
import { within, userEvent, expect, waitFor } from '@storybook/test'
1717
import { Outlet } from 'react-router-dom'
18+
import { http, HttpResponse } from 'msw'
1819
import {
1920
ActionType,
2021
generateEventDocument,
2122
generateWorkqueues,
22-
tennisClubMembershipEvent
23+
tennisClubMembershipEvent,
24+
field
2325
} from '@opencrvs/commons/client'
24-
import {
25-
tennisClubMembershipEventIndex,
26-
tennisClubMembershipEventDocument
27-
} from '@client/v2-events/features/events/fixtures'
26+
import { tennisClubMembershipEventDocument } from '@client/v2-events/features/events/fixtures'
2827
import { ROUTES, routesConfig } from '@client/v2-events/routes'
2928
import { AppRouter } from '@client/v2-events/trpc'
3029
import { testDataGenerator } from '@client/tests/test-data-generators'
30+
import { mockOfflineData } from '@client/tests/mock-offline-data'
3131
import { CERT_TEMPLATE_ID } from '../../useCertificateTemplateSelectorFieldConfig'
3232
import * as PrintCertificate from './index'
3333

@@ -289,3 +289,107 @@ export const RedirectAfterPrint: Story = {
289289
})
290290
}
291291
}
292+
293+
export const NoTemplateAvailable: Story = {
294+
parameters: {
295+
chromatic: { disableSnapshot: true },
296+
reactRouter: {
297+
router: routesConfig,
298+
initialPath: ROUTES.V2.EVENTS.PRINT_CERTIFICATE.PAGES.buildPath({
299+
eventId: tennisClubMembershipEventDocument.id,
300+
pageId: 'collector'
301+
})
302+
},
303+
test: {
304+
// Ignoring the failed font request
305+
dangerouslyIgnoreUnhandledErrors: true
306+
},
307+
msw: {
308+
handlers: {
309+
events: [
310+
tRPCMsw.event.config.get.query(() => {
311+
return [tennisClubMembershipEvent]
312+
}),
313+
tRPCMsw.event.get.query(() => {
314+
return tennisClubMembershipEventDocument
315+
})
316+
],
317+
config: [
318+
http.get(
319+
'/api/countryconfig/certificates/simple-certificate.svg',
320+
() => {
321+
return HttpResponse.text(
322+
`<svg xmlns="http://www.w3.org/2000/svg" width="200" height="100"><text x="10" y="20">Simple Certificate</text></svg>`
323+
)
324+
}
325+
),
326+
http.get('http://localhost:2021/config', () => {
327+
return HttpResponse.json({
328+
systems: [],
329+
config: mockOfflineData.config,
330+
certificates: [
331+
{
332+
id: 'simple-certificate',
333+
isV2Template: true,
334+
event: 'tennis-club-membership',
335+
label: {
336+
id: 'certificates.simple.certificate.copy',
337+
defaultMessage: 'Simple Certificate copy',
338+
description: 'The label for a simple certificate'
339+
},
340+
conditionals: [
341+
{
342+
type: 'SHOW',
343+
conditional: field('applicant.dob')
344+
.isBefore()
345+
.date('2007-01-01')
346+
}
347+
],
348+
isDefault: false,
349+
fee: {
350+
onTime: 7,
351+
late: 10.6,
352+
delayed: 18
353+
},
354+
svgUrl:
355+
'/api/countryconfig/certificates/simple-certificate.svg'
356+
}
357+
]
358+
})
359+
})
360+
]
361+
}
362+
}
363+
},
364+
play: async ({ canvasElement, step }) => {
365+
const canvas = within(canvasElement)
366+
367+
await step('Try continuing without filling the form', async () => {
368+
await expect(
369+
await canvas.findByText('Print certified copy')
370+
).toBeInTheDocument()
371+
372+
const continueButton = await canvas.findByRole('button', {
373+
name: 'Continue'
374+
})
375+
await userEvent.click(continueButton)
376+
const requiredErrors = await canvas.findAllByText('Required')
377+
378+
await expect(requiredErrors.length).toBe(2)
379+
})
380+
381+
await step(
382+
'Click Certification Type and find no options message',
383+
async () => {
384+
await userEvent.click(
385+
await canvas.findByTestId('select__certificateTemplateId')
386+
)
387+
await expect(
388+
await canvas.findByText(
389+
'No template available for this event, contact Admin'
390+
)
391+
).toBeVisible()
392+
}
393+
)
394+
}
395+
}

packages/client/src/v2-events/features/events/actions/print-certificate/pdfUtils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ export function compileSvg({
339339
return getMixedPath(resolvedMetadata, propertyPath)
340340
}
341341

342-
if (isEqual(resolvedDeclaration, obj)) {
342+
if (isEqual($declaration, obj)) {
343343
return getMixedPath(resolvedDeclaration, propertyPath)
344344
}
345345

@@ -564,7 +564,7 @@ export function compileSvg({
564564
const template = Handlebars.compile(templateString)
565565

566566
const data = {
567-
$declaration: resolvedDeclaration,
567+
$declaration,
568568
$metadata,
569569
$review: review,
570570
$references: {

packages/client/src/v2-events/features/events/registered-fields/Address.interaction.stories.tsx

Lines changed: 186 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,24 @@ import { userEvent, waitFor, within } from '@storybook/testing-library'
1616
import React from 'react'
1717
import * as selectEvent from 'react-select-event'
1818
import styled from 'styled-components'
19+
import { useIntl } from 'react-intl'
20+
import { useSelector } from 'react-redux'
1921
import {
2022
AddressType,
2123
FieldType,
2224
and,
2325
not,
2426
field as createFieldCondition,
25-
ConditionalType
27+
ConditionalType,
28+
FieldValue,
29+
AddressFieldValue
2630
} from '@opencrvs/commons/client'
2731
import { FormFieldGenerator } from '@client/v2-events/components/forms/FormFieldGenerator'
2832
import { TRPCProvider } from '@client/v2-events/trpc'
33+
import { useLocations } from '@client/v2-events/hooks/useLocations'
34+
import { getOfflineData } from '@client/offline/selectors'
2935
import { withValidatorContext } from '../../../../../.storybook/decorators'
36+
import { Address } from './Address'
3037

3138
const meta: Meta<typeof FormFieldGenerator> = {
3239
title: 'Inputs/Address/Interaction',
@@ -607,3 +614,181 @@ export const AddressFieldInteractionDomesticToInternational: StoryObj<
607614
)
608615
}
609616
}
617+
618+
interface ResolvedAddress {
619+
country?: string
620+
addressType?: string
621+
province?: string
622+
district?: string
623+
streetLevelDetails?: {
624+
state?: string
625+
district2?: string
626+
town?: string
627+
cityOrTown?: string
628+
}
629+
}
630+
631+
export const ToCertificateVariables: StoryObj<typeof FormFieldGenerator> = {
632+
name: 'Certificate Variables',
633+
parameters: {
634+
layout: 'centered'
635+
},
636+
render: function Component(args) {
637+
const intl = useIntl()
638+
const [formData, setFormData] = React.useState<Record<string, FieldValue>>({
639+
'storybook.address': {
640+
country: 'FAR',
641+
addressType: 'DOMESTIC'
642+
}
643+
})
644+
const [resolvedAddress, setResolvedAddress] =
645+
React.useState<ResolvedAddress>()
646+
const { getLocations } = useLocations()
647+
const [locations] = getLocations.useSuspenseQuery()
648+
const { config: appConfig } = useSelector(getOfflineData)
649+
650+
const adminLevels = appConfig.ADMIN_STRUCTURE
651+
return (
652+
<>
653+
<StyledFormFieldGenerator
654+
{...args}
655+
fields={[
656+
{
657+
id: 'storybook.address',
658+
type: FieldType.ADDRESS,
659+
label: {
660+
id: 'storybook.address.label',
661+
defaultMessage: 'Address',
662+
description: 'The title for the address input'
663+
},
664+
configuration: {
665+
streetAddressForm: streetAddressConfigs
666+
}
667+
}
668+
]}
669+
id="my-form"
670+
initialValues={formData}
671+
onChange={(data) => {
672+
setFormData((prev) => ({ ...prev, ...data }))
673+
const address = AddressFieldValue.safeParse(
674+
data['storybook.address']
675+
)
676+
if (address.success) {
677+
const resolved = Address.toCertificateVariables(address.data, {
678+
intl,
679+
locations,
680+
adminLevels
681+
})
682+
setResolvedAddress((prev) => ({
683+
...prev,
684+
...(resolved satisfies ResolvedAddress)
685+
}))
686+
}
687+
}}
688+
/>
689+
{resolvedAddress && (
690+
<div>
691+
<div data-testid="country">
692+
{'Country:'} {resolvedAddress.country}
693+
</div>
694+
<div data-testid="addressType">
695+
{'Address Type:'} {resolvedAddress.addressType}
696+
</div>
697+
{resolvedAddress.province && (
698+
<div data-testid="province">
699+
{'Province:'} {resolvedAddress.province}
700+
</div>
701+
)}
702+
{resolvedAddress.district && (
703+
<div data-testid="district">
704+
{'District:'} {resolvedAddress.district}
705+
</div>
706+
)}
707+
{resolvedAddress.streetLevelDetails?.state && (
708+
<div data-testid="state">
709+
{'State:'} {resolvedAddress.streetLevelDetails.state}
710+
</div>
711+
)}
712+
{resolvedAddress.streetLevelDetails?.district2 && (
713+
<div data-testid="district2">
714+
{'District:'} {resolvedAddress.streetLevelDetails.district2}
715+
</div>
716+
)}
717+
718+
{resolvedAddress.streetLevelDetails?.town && (
719+
<div data-testid="town">
720+
{resolvedAddress.streetLevelDetails.town}
721+
</div>
722+
)}
723+
{resolvedAddress.streetLevelDetails?.cityOrTown && (
724+
<div data-testid="cityOrTown">
725+
{resolvedAddress.streetLevelDetails.cityOrTown}
726+
</div>
727+
)}
728+
</div>
729+
)}
730+
</>
731+
)
732+
},
733+
play: async ({ canvasElement, step }) => {
734+
const canvas = within(canvasElement)
735+
736+
await step('Fill up Domestic Address', async () => {
737+
const province = await canvas.findByTestId('location__province')
738+
await userEvent.click(province)
739+
await selectEvent.select(province, 'Central')
740+
741+
const district = await canvas.findByTestId('location__district')
742+
await userEvent.click(district)
743+
await selectEvent.select(district, 'Ibombo')
744+
745+
const town = await canvas.findByTestId('text__town')
746+
await userEvent.type(town, 'Dhaka')
747+
748+
const residentialArea = await canvas.findByTestId('text__residentialArea')
749+
await userEvent.type(residentialArea, 'Mirpur')
750+
751+
await expect(canvas.queryByTestId('country')).toHaveTextContent(
752+
'Farajaland'
753+
)
754+
await expect(canvas.queryByTestId('addressType')).toHaveTextContent(
755+
'DOMESTIC'
756+
)
757+
await expect(canvas.queryByTestId('province')).toHaveTextContent(
758+
'Central'
759+
)
760+
await expect(canvas.queryByTestId('district')).toHaveTextContent('Ibombo')
761+
await expect(canvas.queryByTestId('town')).toHaveTextContent('Dhaka')
762+
})
763+
764+
await step('Fill up International Address', async () => {
765+
const country = await canvas.findByTestId('location__country')
766+
await userEvent.click(country)
767+
await selectEvent.select(country, 'Estonia')
768+
769+
const province = await canvas.findByTestId('text__state')
770+
await userEvent.type(province, 'State')
771+
772+
const district2 = await canvas.findByTestId('text__district2')
773+
await userEvent.type(district2, 'District')
774+
775+
const town = await canvas.findByTestId('text__cityOrTown')
776+
await userEvent.type(town, 'Dhaka')
777+
778+
const residentialArea = await canvas.findByTestId('text__addressLine1')
779+
await userEvent.type(residentialArea, 'Mirpur')
780+
781+
await expect(canvas.queryByTestId('country')).toHaveTextContent('Estonia')
782+
await expect(canvas.queryByTestId('addressType')).toHaveTextContent(
783+
'INTERNATIONAL'
784+
)
785+
await expect(canvas.queryByTestId('state')).toHaveTextContent('State')
786+
await expect(canvas.queryByTestId('district2')).toHaveTextContent(
787+
'District'
788+
)
789+
await expect(canvas.queryByTestId('cityOrTown')).toHaveTextContent(
790+
'Dhaka'
791+
)
792+
})
793+
}
794+
}

0 commit comments

Comments
 (0)