Skip to content

Commit

Permalink
tennis club membership svg certificate added
Browse files Browse the repository at this point in the history
  • Loading branch information
tareq89 committed Jan 15, 2025
1 parent f5083b4 commit 8566d57
Show file tree
Hide file tree
Showing 12 changed files with 1,108 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { DATE, PARAGRAPH, TEXT } from '@client/forms'
import { DateField } from '@opencrvs/components/lib/DateField'
import { Text } from '@opencrvs/components/lib/Text'
import { TextInput } from '@opencrvs/components/lib/TextInput'
import { RadioGroup } from '@opencrvs/components/lib/Radio'
import * as React from 'react'

import styled, { keyframes } from 'styled-components'
Expand Down Expand Up @@ -196,7 +197,22 @@ const GeneratedInputField = React.memo(
</InputField>
)
}
return <div>Unsupported field type {fieldDefinition.type}</div>
if (fieldDefinition.type === 'RADIO_GROUP') {
return (
<InputField {...inputFieldProps}>
<RadioGroup
{...inputProps}
onChange={(val: string) => setFieldValue(fieldDefinition.id, val)}
options={fieldDefinition.options.map((x) => ({
label: intl.formatMessage(x.label),
value: x.value
}))}
value={inputProps.value as string}
/>
</InputField>
)
}
// return <div>Unsupported field type {fieldDefinition.type}</div>
}
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import React, { useEffect } from 'react'
import { defineMessages } from 'react-intl'
import { useNavigate } from 'react-router-dom'
import { v4 as uuid } from 'uuid'
import styled from 'styled-components'
import { useIntl } from 'react-intl'
import { useTypedParams } from 'react-router-typesafe-routes/dom'
import { getCurrentEventState, ActionType } from '@opencrvs/commons/client'
import { ROUTES } from '@client/v2-events/routes'
Expand All @@ -23,7 +25,25 @@ import { useEventFormNavigation } from '@client/v2-events/features/events/useEve
import { useEventConfiguration } from '@client/v2-events/features/events/useEventConfiguration'
import { useEventFormData } from '@client/v2-events/features/events/useEventFormData'
import { FormLayout } from '@client/v2-events/layouts/form'
import { usePrintableCertificate } from '@client/v2-events/hooks/usePrintableCertificate'
import {
Box,
Button,
Content,
Frame,
Icon,
ResponsiveModal,
Spinner,
Stack
} from '@opencrvs/components'
import { api } from '@client/v2-events/trpc'

const CertificateContainer = styled.div`
svg {
/* limits the certificate overflowing on small screens */
max-width: 100%;
}
`
const messages = defineMessages({
registerActionTitle: {
id: 'registerAction.title',
Expand All @@ -40,6 +60,54 @@ const messages = defineMessages({
id: 'registerAction.Declare',
defaultMessage: 'Register',
description: 'The label for declare button of register action'
},
printModalTitle: {
id: 'print.certificate.review.printModalTitle',
defaultMessage: 'Print certificate?',
description: 'Print certificate modal title text'
},
printAndIssueModalTitle: {
id: 'print.certificate.review.printAndIssueModalTitle',
defaultMessage: 'Print and issue certificate?',
description: 'Print and issue certificate modal title text'
},
printModalBody: {
id: 'print.certificate.review.modal.body.print',
defaultMessage:
'A PDF of the certificate will open in a new tab for you to print. This record will then be moved to your ready to issue work-queue',
description: 'Print certificate modal body text'
},
printAndIssueModalBody: {
id: 'print.certificate.review.modal.body.printAndIssue',
defaultMessage:
'A PDF of the certificate will open in a new tab for you to print and issue',
description: 'Print certificate modal body text'
},
confirmAndPrint: {
defaultMessage: 'Yes, print certificate',
description: 'The text for print button',
id: 'print.certificate.button.confirmPrint'
},
reviewTitle: {
defaultMessage: 'Ready to certify?',
description: 'Certificate review title',
id: 'print.certificate.review.title'
},
reviewDescription: {
defaultMessage:
'Please confirm that the informant has reviewed that the information on the certificate is correct and that it is ready to print.',
description: 'Certificate review description',
id: 'print.certificate.review.description'
},
cancel: {
defaultMessage: 'Cancel',
description: 'Cancel button text in the modal',
id: 'buttons.cancel'
},
print: {
defaultMessage: 'Print',
description: 'Print button text',
id: 'buttons.print'
}
})

Expand All @@ -49,14 +117,14 @@ const messages = defineMessages({
*/
export function Review() {
const { eventId } = useTypedParams(ROUTES.V2.EVENTS.COLLECT_CERTIFICATE)
const intl = useIntl()
const events = useEvents()
const [modal, openModal] = useModal()
const navigate = useNavigate()
const { goToHome } = useEventFormNavigation()
const collectCertificateMutation = events.actions.collectCertificate

const [event] = events.getEvent.useSuspenseQuery(eventId)

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

if (!config) {
Expand All @@ -70,11 +138,20 @@ export function Review() {
const setFormValues = useEventFormData((state) => state.setFormValues)
const getFormValues = useEventFormData((state) => state.getFormValues)

useEffect(() => {
setFormValues(eventId, getCurrentEventState(event).data)
}, [event, eventId, setFormValues])
// useEffect(() => {
// setFormValues(eventId, getCurrentEventState(event).data)
// }, [event, eventId, setFormValues])

const form = getFormValues(eventId)
console.trace(form)

const {
isLoadingInProgress,
svgCode,
handleCertify,
isPrintInAdvance,
canUserEditRecord
} = usePrintableCertificate(form)

async function handleEdit({
pageId,
Expand Down Expand Up @@ -115,6 +192,53 @@ export function Review() {
goToHome()
}
}
const confirmAndPrint = async () => {
const saveAndExitConfirm = await openModal<boolean>((close) => (
<ResponsiveModal
id="confirm-print-modal"
title={
isPrintInAdvance
? intl.formatMessage(messages.printModalTitle)
: intl.formatMessage(messages.printAndIssueModalTitle)
}
actions={[
<Button
type="tertiary"
key="close-modal"
onClick={() => {
close(false)
}}
id="close-modal"
>
{intl.formatMessage(messages.cancel)}
</Button>,
<Button
type="primary"
key="print-certificate"
onClick={() => close(true)}
id="print-certificate"
>
{intl.formatMessage(messages.print)}
</Button>
]}
show={true}
handleClose={() => close(false)}
contentHeight={100}
>
{isPrintInAdvance
? intl.formatMessage(messages.printModalBody)
: intl.formatMessage(messages.printAndIssueModalBody)}
</ResponsiveModal>
))

if (saveAndExitConfirm) {
handleCertify()
}
}

if (!isLoadingInProgress) {
return <Spinner id="review-certificate-loading" />
}

return (
<FormLayout
Expand All @@ -129,7 +253,56 @@ export function Review() {
goToHome()
}}
>
<ReviewComponent.Body
<Frame.LayoutCentered>
<Stack direction="column">
<Box>
<CertificateContainer
id="print"
dangerouslySetInnerHTML={{ __html: svgCode }}
/>
</Box>
<Content
title={intl.formatMessage(messages.registerActionTitle)}
bottomActionDirection="row"
bottomActionButtons={[
canUserEditRecord ? (
<Button
key="edit-record"
type="negative"
onClick={() =>
handleEdit({
pageId: formConfigs[0].pages[0].id,
fieldId: undefined
})
}
size="large"
fullWidth
>
<Icon name="X" size="medium" />
{intl.formatMessage(messages.registerActionDeclare)}
</Button>
) : (
<></>
),

<Button
key="confirm-and-print"
type="positive"
id="confirm-print"
onClick={confirmAndPrint}
size="large"
fullWidth
>
<Icon name="Check" size="medium" />
{intl.formatMessage(messages.confirmAndPrint)}
</Button>
]}
>
{intl.formatMessage(messages.reviewDescription)}
</Content>
</Stack>
</Frame.LayoutCentered>
{/* <ReviewComponent.Body
eventConfig={config}
form={form}
formConfig={formConfigs[0]}
Expand All @@ -145,7 +318,8 @@ export function Review() {
onConfirm={handleRegistration}
/>
{modal}
</ReviewComponent.Body>
</ReviewComponent.Body> */}
{/* <ReviewCertificate /> */}
</FormLayout>
)
}
30 changes: 30 additions & 0 deletions packages/client/src/v2-events/hooks/useAppConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* 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 { create } from 'zustand'
import { api } from '@client/v2-events/trpc'
import { ApplicationConfigResponseSchema } from '@opencrvs/commons/events'
import { UseTRPCQueryResult } from '@trpc/react-query/shared'
import { TRPCClientErrorLike } from '@trpc/client'
import { DefaultErrorShape } from '@trpc/server/unstable-core-do-not-import'

interface IApplicationConfig {
appConfig: ApplicationConfigResponseSchema
initiateAppConfig: () => Promise<void>
}

export const useAppConfig = create<IApplicationConfig>((set, get) => ({
appConfig: { config: undefined, certificates: [] },
initiateAppConfig: async () => {
const { data: appConfig } = api.appConfig.get.useQuery()
set({ appConfig })
}
}))
76 changes: 76 additions & 0 deletions packages/client/src/v2-events/hooks/usePrintableCertificate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* 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 { formatLongDate } from '@client/utils/date-formatting'
import { EventType } from '@client/utils/gateway'
import { getLocationHierarchy } from '@client/utils/locationUtils'
import { getUserName, UserDetails } from '@client/utils/userUtils'
import { cloneDeep } from 'lodash'
import { useDispatch, useSelector } from 'react-redux'
import { useNavigate } from 'react-router-dom'
import { addFontsToSvg, compileSvg, svgToPdfTemplate } from './utils/PDFUtils'
import {
calculatePrice,
getEventDate,
getRegisteredDate,
isCertificateForPrintInAdvance
} from './utils/certificateUtils'
import { CertificateDataSchema } from '@opencrvs/commons/events'
import { ActionFormData, isMinioUrl } from '@opencrvs/commons/client'
import { fetchImageAsBase64 } from '@client/utils/imageUtils'
import { useAppConfig } from '@client/v2-events/hooks/useAppConfig'
import { useEffect } from 'react'
import { api } from '../trpc'

async function replaceMinioUrlWithBase64(template: Record<string, any>) {
async function recursiveTransform(obj: any) {
if (typeof obj !== 'object' || obj === null) {
return obj
}

const transformedObject = Array.isArray(obj) ? [...obj] : { ...obj }

for (const key in obj) {
const value = obj[key]
if (typeof value === 'string' && isMinioUrl(value)) {
transformedObject[key] = await fetchImageAsBase64(value)
} else if (typeof value === 'object') {
transformedObject[key] = await recursiveTransform(value)
} else {
transformedObject[key] = value
}
}

return transformedObject
}
return recursiveTransform(template)
}

export const usePrintableCertificate = (form: ActionFormData) => {
const handleCertify = () => {}

const isPrintInAdvance = false
const canUserEditRecord = false
const handleEdit = () => {}
const { data: svgCode, isFetched } =
api.appConfig.getCertificateTemplateSVGById.useQuery({
id: form['collector.certificateTemplateId'] as string
})

return {
isLoadingInProgress: isFetched,
svgCode,
handleCertify,
isPrintInAdvance,
canUserEditRecord,
handleEdit
}
}
Loading

0 comments on commit 8566d57

Please sign in to comment.