From b32d5d3a76b3b9e43195183ad0e86b421c47aeea Mon Sep 17 00:00:00 2001 From: Alex Lipovka Date: Sat, 1 Feb 2025 18:46:12 +0400 Subject: [PATCH 01/21] Auto hide clear filters button in SearchBar for only one filter --- src/components/SearchBar/index.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/components/SearchBar/index.tsx b/src/components/SearchBar/index.tsx index ef63bb04..b0430aad 100644 --- a/src/components/SearchBar/index.tsx +++ b/src/components/SearchBar/index.tsx @@ -1,12 +1,12 @@ import { Trans } from '@lingui/macro'; import { Button } from 'antd'; +import { useMemo } from 'react'; import { SearchBarColumn } from './SearchBarColumn'; +import { SearchBarMobile } from './SearchBarMobile'; import { S } from './styles'; import { SearchBarData } from './types'; -import { SearchBarMobile } from './SearchBarMobile'; import { isSearchBarFilter } from './utils'; -import { useMemo } from 'react'; interface SearchBarProps extends SearchBarData { showInDrawerOnMobile?: boolean; @@ -32,9 +32,11 @@ export function SearchBar(props: SearchBarProps) { ))} - + {searchBarFilterValues.length > 1 ? ( + + ) : null} From 5e7ca9d09f5ec65df6de5efe1b14c59c2d120ca4 Mon Sep 17 00:00:00 2001 From: Madeleyne Silva <52809647+MadeleyneSilva@users.noreply.github.com> Date: Mon, 3 Feb 2025 05:43:21 -0300 Subject: [PATCH 02/21] add new translations (#442) * add new translations * issue-74 add new translations --- .../BaseLayout/Footer/Footer.styles.ts | 6 ++ src/components/BaseLayout/Footer/index.tsx | 5 +- .../widgets/QuestionDateTime.stories.tsx | 9 +- .../EncounterDetails/AIScribe/index.tsx | 2 +- .../HealthcareServiceList/index.tsx | 4 +- .../components/InvoiceListSearchBar/hooks.ts | 11 ++- src/locale/en/messages.po | 47 +++++++++ src/locale/es/messages.po | 97 ++++++++++++++----- src/locale/ru/messages.po | 47 +++++++++ src/utils/relative-date.ts | 7 +- 10 files changed, 194 insertions(+), 41 deletions(-) diff --git a/src/components/BaseLayout/Footer/Footer.styles.ts b/src/components/BaseLayout/Footer/Footer.styles.ts index d7ab0967..5a1f7a72 100644 --- a/src/components/BaseLayout/Footer/Footer.styles.ts +++ b/src/components/BaseLayout/Footer/Footer.styles.ts @@ -1,4 +1,5 @@ import styled from 'styled-components'; +import { Text } from 'src/components/Typography'; export const S = { Footer: styled.footer` @@ -34,4 +35,9 @@ export const S = { text-decoration: underline; } `, + Text: styled(Text)` + color: var(--footer-text); + font-size: 14px; + line-height: 22px; + `, }; diff --git a/src/components/BaseLayout/Footer/index.tsx b/src/components/BaseLayout/Footer/index.tsx index 43bc610d..1f694d15 100644 --- a/src/components/BaseLayout/Footer/index.tsx +++ b/src/components/BaseLayout/Footer/index.tsx @@ -1,4 +1,5 @@ import { S } from './Footer.styles'; +import { t } from '@lingui/macro'; interface Props { type?: 'default' | 'light'; @@ -10,7 +11,9 @@ export function AppFooter(props: Props) { return ( - Made with ❤️ by{' '} + + {t`Made with`} ❤️ {t`by`}{' '} + Beda Software diff --git a/src/components/BaseQuestionnaireResponseForm/widgets/QuestionDateTime.stories.tsx b/src/components/BaseQuestionnaireResponseForm/widgets/QuestionDateTime.stories.tsx index 5b6f39df..36250ca9 100644 --- a/src/components/BaseQuestionnaireResponseForm/widgets/QuestionDateTime.stories.tsx +++ b/src/components/BaseQuestionnaireResponseForm/widgets/QuestionDateTime.stories.tsx @@ -1,5 +1,6 @@ import { Meta, StoryObj } from '@storybook/react'; import { ItemContext } from 'sdc-qrf/lib/types'; +import { t } from '@lingui/macro'; import { WithQuestionFormProviderDecorator, withColorSchemeDecorator } from 'src/storybook/decorators'; @@ -19,7 +20,7 @@ export const DateTime: Story = { Loading...} + renderLoading={() => ${t`Loading...`}} renderFailure={(error) => {formatError(error)}} > {() => <>} diff --git a/src/containers/HealthcareServiceList/index.tsx b/src/containers/HealthcareServiceList/index.tsx index c4c4feb5..bc9d895b 100644 --- a/src/containers/HealthcareServiceList/index.tsx +++ b/src/containers/HealthcareServiceList/index.tsx @@ -1,4 +1,4 @@ -import { Trans } from '@lingui/macro'; +import { t, Trans } from '@lingui/macro'; import { Col, Empty, Row } from 'antd'; import { isLoading, isSuccess } from '@beda.software/remote-data'; @@ -71,7 +71,7 @@ export function HealthcareServiceList() { dataIndex: 'active', key: 'active', width: '20%', - render: (_text, resource) => (resource.active ? 'Active' : 'Inactive'), + render: (_text, resource) => (resource.active ? t`Active` : t`Inactive`), }, { title: Actions, diff --git a/src/containers/InvoiceList/components/InvoiceListSearchBar/hooks.ts b/src/containers/InvoiceList/components/InvoiceListSearchBar/hooks.ts index 55849e53..8f4ebcf8 100644 --- a/src/containers/InvoiceList/components/InvoiceListSearchBar/hooks.ts +++ b/src/containers/InvoiceList/components/InvoiceListSearchBar/hooks.ts @@ -1,5 +1,6 @@ import { Patient, Practitioner, PractitionerRole } from 'fhir/r4b'; import { useCallback, useState } from 'react'; +import { t } from '@lingui/macro'; import { extractBundleResources, getReference } from '@beda.software/fhir-react'; import { isSuccess, mapSuccess } from '@beda.software/remote-data'; @@ -93,23 +94,23 @@ export function useInvoiceSearchBarSelect() { const statusOptions = useCallback(async (search: string) => { const invoiceStatusOptions = [ { - label: 'Balanced', + label: t`Balanced`, value: 'balanced', }, { - label: 'Cancelled', + label: t`Cancelled`, value: 'cancelled', }, { - label: 'Issued', + label: t`Issued`, value: 'issued', }, { - label: 'Draft', + label: t`Draft`, value: 'draft', }, { - label: 'Entered in error', + label: t`Entered in error`, value: 'entered-in-error', }, ]; diff --git a/src/locale/en/messages.po b/src/locale/en/messages.po index 878d14f9..dd42132a 100644 --- a/src/locale/en/messages.po +++ b/src/locale/en/messages.po @@ -43,6 +43,7 @@ msgstr "" msgid "Activate healthcare service" msgstr "" +#: src/containers/HealthcareServiceList/index.tsx:74 #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:97 #: src/containers/Prescriptions/index.tsx:185 #: src/containers/QuestionnaireBuilder/QuestionnaireSaveForm/index.tsx:82 @@ -198,6 +199,7 @@ msgstr "" msgid "Available units" msgstr "" +#: src/containers/InvoiceList/components/InvoiceListSearchBar/hooks.ts:97 #: src/containers/InvoiceList/tableUtils.tsx:27 msgid "Balanced" msgstr "" @@ -211,6 +213,7 @@ msgstr "" msgid "Batch Number" msgstr "" +#: src/components/BaseQuestionnaireResponseForm/widgets/QuestionDateTime.stories.tsx:37 #: src/containers/PatientDetails/PatientOverviewDynamic/containers/GeneralIInformationDashboardContainer/hooks.ts:31 #: src/containers/PatientList/index.tsx:85 #: src/containers/PatientResourceListExample/index.tsx:48 @@ -230,6 +233,10 @@ msgstr "" msgid "Build your form" msgstr "" +#: src/components/BaseLayout/Footer/index.tsx:15 +msgid "by" +msgstr "" + #: src/containers/PatientDetails/PatientWearables/index.tsx:46 msgid "Calories" msgstr "" @@ -250,6 +257,7 @@ msgstr "" msgid "Cancel Medication Request" msgstr "" +#: src/containers/InvoiceList/components/InvoiceListSearchBar/hooks.ts:101 #: src/containers/InvoiceList/tableUtils.tsx:28 #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:101 #: src/containers/Prescriptions/index.tsx:187 @@ -386,6 +394,10 @@ msgstr "" msgid "CRP" msgstr "" +#: src/utils/relative-date.ts:25 +msgid "d.o." +msgstr "" + #: src/components/PatientEncounter/index.tsx:39 #: src/containers/EncounterList/index.tsx:63 #: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:23 @@ -491,6 +503,7 @@ msgstr "" msgid "Download audio" msgstr "" +#: src/containers/InvoiceList/components/InvoiceListSearchBar/hooks.ts:109 #: src/containers/InvoiceList/tableUtils.tsx:30 #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:121 #: src/containers/Prescriptions/index.tsx:191 @@ -582,6 +595,7 @@ msgstr "" msgid "End date" msgstr "" +#: src/containers/InvoiceList/components/InvoiceListSearchBar/hooks.ts:113 #: src/containers/InvoiceList/tableUtils.tsx:31 #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:113 #: src/containers/Prescriptions/index.tsx:189 @@ -726,6 +740,10 @@ msgstr "" msgid "in progress" msgstr "" +#: src/containers/HealthcareServiceList/index.tsx:74 +msgid "Inactive" +msgstr "" + #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/controls.tsx:40 msgid "Inline choice" msgstr "" @@ -753,6 +771,7 @@ msgstr "" msgid "Invoices" msgstr "" +#: src/containers/InvoiceList/components/InvoiceListSearchBar/hooks.ts:105 #: src/containers/InvoiceList/tableUtils.tsx:29 msgid "Issued" msgstr "" @@ -781,6 +800,10 @@ msgstr "" msgid "Listen to the audio" msgstr "" +#: src/containers/EncounterDetails/AIScribe/index.tsx:312 +msgid "Loading..." +msgstr "" + #: src/containers/SignIn/index.tsx:89 msgid "Log in" msgstr "" @@ -797,10 +820,18 @@ msgstr "" msgid "Log out" msgstr "" +#: src/utils/relative-date.ts:22 +msgid "m.o." +msgstr "" + #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/controls.tsx:101 msgid "Macro text" msgstr "" +#: src/components/BaseLayout/Footer/index.tsx:15 +msgid "Made with" +msgstr "" + #: src/components/DashboardCard/creatinine.tsx:91 msgid "Max" msgstr "" @@ -1236,6 +1267,14 @@ msgstr "" msgid "Select all" msgstr "" +#: src/components/BaseQuestionnaireResponseForm/widgets/QuestionDateTime.stories.tsx:23 +msgid "Select date" +msgstr "" + +#: src/components/BaseQuestionnaireResponseForm/widgets/QuestionDateTime.stories.tsx:51 +msgid "Select time" +msgstr "" + #: src/components/BaseQuestionnaireResponseForm/widgets/choice/index.tsx:30 #: src/components/BaseQuestionnaireResponseForm/widgets/choice/index.tsx:55 msgid "Select..." @@ -1455,6 +1494,10 @@ msgstr "" msgid "Time" msgstr "" +#: src/components/BaseQuestionnaireResponseForm/widgets/QuestionDateTime.stories.tsx:65 +msgid "Time with no seconds" +msgstr "" + #: src/containers/PatientDetails/PatientOrders/index.tsx:27 #: src/containers/PatientDetails/PatientOverviewDynamic/components/PatientNoteListCard/NoteList/index.tsx:33 #: src/containers/PatientDetails/PatientResources/utils.tsx:246 @@ -1562,6 +1605,10 @@ msgstr "" msgid "Welcome to" msgstr "" +#: src/utils/relative-date.ts:18 +msgid "y.o." +msgstr "" + #: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:147 #: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:172 #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/index.tsx:136 diff --git a/src/locale/es/messages.po b/src/locale/es/messages.po index f9ae02ef..5f1b4080 100644 --- a/src/locale/es/messages.po +++ b/src/locale/es/messages.po @@ -43,6 +43,7 @@ msgstr "Activar" msgid "Activate healthcare service" msgstr "Activar servicio clínico" +#: src/containers/HealthcareServiceList/index.tsx:74 #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:97 #: src/containers/Prescriptions/index.tsx:185 #: src/containers/QuestionnaireBuilder/QuestionnaireSaveForm/index.tsx:82 @@ -198,9 +199,10 @@ msgstr "Servicios disponibles" msgid "Available units" msgstr "Unidades disponibles" +#: src/containers/InvoiceList/components/InvoiceListSearchBar/hooks.ts:97 #: src/containers/InvoiceList/tableUtils.tsx:27 msgid "Balanced" -msgstr "Balanceado" +msgstr "Saldada" #: src/containers/MedicationManagement/index.tsx:118 #: src/containers/MedicationManagement/ModalNewMedicationBatch.tsx:23 @@ -211,6 +213,7 @@ msgstr "Lote" msgid "Batch Number" msgstr "Número de lote" +#: src/components/BaseQuestionnaireResponseForm/widgets/QuestionDateTime.stories.tsx:37 #: src/containers/PatientDetails/PatientOverviewDynamic/containers/GeneralIInformationDashboardContainer/hooks.ts:31 #: src/containers/PatientList/index.tsx:85 #: src/containers/PatientResourceListExample/index.tsx:48 @@ -230,6 +233,10 @@ msgstr "Pausa" msgid "Build your form" msgstr "Construye tu formulario" +#: src/components/BaseLayout/Footer/index.tsx:15 +msgid "by" +msgstr "por" + #: src/containers/PatientDetails/PatientWearables/index.tsx:46 msgid "Calories" msgstr "Calorías" @@ -250,11 +257,12 @@ msgstr "Cancelar recibo" msgid "Cancel Medication Request" msgstr "Cancelar solicitud de medicamento" +#: src/containers/InvoiceList/components/InvoiceListSearchBar/hooks.ts:101 #: src/containers/InvoiceList/tableUtils.tsx:28 #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:101 #: src/containers/Prescriptions/index.tsx:187 msgid "Cancelled" -msgstr "Cancelado" +msgstr "Cancelada" #: src/components/AudioRecorder/index.tsx:39 #: src/containers/EncounterDetails/AIScribe/index.tsx:93 @@ -267,16 +275,16 @@ msgstr "Características" #: src/containers/PatientResourceListExample/index.tsx:89 msgid "Choose gender" -msgstr "" +msgstr "Elegir género" #: src/components/SearchBar/index.tsx:36 #: src/components/SearchBar/SearchBarMobile/index.tsx:51 msgid "Clear filters" -msgstr "" +msgstr "Limpiar filtros" #: src/components/BaseQuestionnaireResponseForm/widgets/UploadFileControl/index.tsx:29 msgid "Click or drag file to this area to upload" -msgstr "" +msgstr "Haz click o arrastra el archivo hasta esta área para cargar" #: src/containers/PractitionerDetails/PractitionerOverview/index.tsx:92 msgid "Clinician successfully updated" @@ -384,7 +392,11 @@ msgstr "Fecha de creación" #: src/containers/PatientDetails/PatientOrders/index.tsx:156 msgid "CRP" -msgstr "" +msgstr "PCR" + +#: src/utils/relative-date.ts:25 +msgid "d.o." +msgstr "días" #: src/components/PatientEncounter/index.tsx:39 #: src/containers/EncounterList/index.tsx:63 @@ -443,7 +455,7 @@ msgstr "Eliminar" #: src/containers/PatientResourceListExample/index.tsx:119 msgid "Delete patients" -msgstr "" +msgstr "Eliminar pacientes" #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/index.tsx:133 msgid "Delete Questionnaire Item" @@ -485,8 +497,9 @@ msgstr "Forma de dosificación" #: src/components/AudioRecorder/index.tsx:124 msgid "Download audio" -msgstr "" +msgstr "Descargar audio" +#: src/containers/InvoiceList/components/InvoiceListSearchBar/hooks.ts:109 #: src/containers/InvoiceList/tableUtils.tsx:30 #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:121 #: src/containers/Prescriptions/index.tsx:191 @@ -578,6 +591,7 @@ msgstr "Fin" msgid "End date" msgstr "Fecha de finalización" +#: src/containers/InvoiceList/components/InvoiceListSearchBar/hooks.ts:113 #: src/containers/InvoiceList/tableUtils.tsx:31 #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:113 #: src/containers/Prescriptions/index.tsx:189 @@ -627,7 +641,7 @@ msgstr "Rellenar" #: src/components/SearchBar/SearchBarMobile/index.tsx:33 msgid "Filters" -msgstr "" +msgstr "Filtros" #: src/containers/PatientList/searchBarUtils.ts:10 #: src/containers/PatientResourceListExample/index.tsx:75 @@ -652,7 +666,7 @@ msgstr "Viernes" #: src/containers/PatientResourceListExample/index.tsx:55 msgid "Gender" -msgstr "" +msgstr "Género" #: src/containers/PatientDetails/PatientOverviewDynamic/components/GeneralInformationDashboard/index.tsx:20 #: src/containers/PractitionerDetails/PractitionerOverview/index.tsx:61 @@ -722,6 +736,10 @@ msgstr "Inmunización" msgid "in progress" msgstr "En progreso" +#: src/containers/HealthcareServiceList/index.tsx:74 +msgid "Inactive" +msgstr "Inactivo" + #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/controls.tsx:40 msgid "Inline choice" msgstr "Elección en línea" @@ -749,6 +767,7 @@ msgstr "La factura fue pagada con éxito" msgid "Invoices" msgstr "Facturas" +#: src/containers/InvoiceList/components/InvoiceListSearchBar/hooks.ts:105 #: src/containers/InvoiceList/tableUtils.tsx:29 msgid "Issued" msgstr "Agendado" @@ -775,7 +794,11 @@ msgstr "Apellido" #: src/components/AudioRecorder/index.tsx:68 msgid "Listen to the audio" -msgstr "" +msgstr "Escuchar el audio" + +#: src/containers/EncounterDetails/AIScribe/index.tsx:312 +msgid "Loading..." +msgstr "Cargando..." #: src/containers/SignIn/index.tsx:89 msgid "Log in" @@ -789,10 +812,18 @@ msgstr "Iniciar sesión como paciente demo" msgid "Log out" msgstr "Cerrar sesión" +#: src/utils/relative-date.ts:22 +msgid "m.o." +msgstr "meses" + #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/controls.tsx:101 msgid "Macro text" msgstr "Texto macro" +#: src/components/BaseLayout/Footer/index.tsx:15 +msgid "Made with" +msgstr "Hecho con" + #: src/components/DashboardCard/creatinine.tsx:91 msgid "Max" msgstr "Máximo" @@ -909,7 +940,7 @@ msgstr "Número (predeterminado)" #: src/containers/PatientResourceListExample/index.tsx:122 msgid "Number of Patients" -msgstr "" +msgstr "Número de pacientes" #: src/containers/PatientDetails/PatientResources/utils.tsx:230 msgid "Observations" @@ -1017,7 +1048,7 @@ msgstr "Pago" #: src/containers/PatientDetails/PatientOrders/index.tsx:164 msgid "PCT" -msgstr "" +msgstr "PCT" #: src/containers/App/DefaultUserWithNoRoles.tsx:31 #: src/containers/PatientDetails/PatientOverviewDynamic/containers/GeneralIInformationDashboardContainer/hooks.ts:45 @@ -1030,7 +1061,7 @@ msgstr "Widget de teléfono" #: src/containers/App/DefaultUserWithNoRoles.tsx:20 msgid "Please ask administrator to add a role for your user" -msgstr "" +msgstr "Por favor contactarse con el administrador para agregar un rol a su usuario" #: src/components/PatientEncounter/index.tsx:25 #: src/containers/EncounterList/index.tsx:51 @@ -1122,7 +1153,7 @@ msgstr "Restablecer" #: src/uberComponents/ResourceListPage/BatchActions.tsx:48 msgid "Reset selection" -msgstr "" +msgstr "Limpiar selección" #: src/containers/PatientDetails/PatientDetailsTabs/index.tsx:24 #: src/containers/PatientDetails/PatientHeader/index.tsx:96 @@ -1148,7 +1179,7 @@ msgstr "Guardar" #: src/components/BaseQuestionnaireResponseForm/FormFooter.tsx:77 msgid "Save as draft" -msgstr "" +msgstr "Guardar borrador" #: src/containers/QuestionnaireBuilder/index.tsx:49 #: src/containers/QuestionnaireBuilder/index.tsx:50 @@ -1157,11 +1188,11 @@ msgstr "Guardar cuestionario" #: src/components/BaseQuestionnaireResponseForm/FormFooter.tsx:94 msgid "Saved as draft" -msgstr "" +msgstr "Guardado como borrador" #: src/components/BaseQuestionnaireResponseForm/FormFooter.tsx:85 msgid "Saving draft" -msgstr "" +msgstr "Guardando borrador" #: src/containers/Scheduling/ScheduleCalendar/index.tsx:41 msgid "Schedule calendar" @@ -1214,7 +1245,15 @@ msgstr "Seleccionar (predeterminado)" #: src/uberComponents/ResourceListPage/BatchActions.tsx:69 msgid "Select all" -msgstr "" +msgstr "Seleccionar todos" + +#: src/components/BaseQuestionnaireResponseForm/widgets/QuestionDateTime.stories.tsx:23 +msgid "Select date" +msgstr "Seleccionar fecha" + +#: src/components/BaseQuestionnaireResponseForm/widgets/QuestionDateTime.stories.tsx:51 +msgid "Select time" +msgstr "Selecciona hora" #: src/components/BaseQuestionnaireResponseForm/widgets/choice/index.tsx:30 #: src/components/BaseQuestionnaireResponseForm/widgets/choice/index.tsx:55 @@ -1251,7 +1290,7 @@ msgstr "Compartir enlace" #: src/components/SearchBar/SearchBarMobile/index.tsx:48 msgid "Show results" -msgstr "" +msgstr "Mostrar resultados" #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/controls.tsx:53 msgid "Slider" @@ -1352,13 +1391,13 @@ msgstr "Enviar" #: src/uberComponents/ResourceListPage/actions.tsx:105 #: src/uberComponents/ResourceListPage/actions.tsx:146 #~ msgid "Successfully saved" -#~ msgstr "" +#~ msgstr "Guardado exitosamente" #: src/uberComponents/ResourceListPage/actions.tsx:91 #: src/uberComponents/ResourceListPage/actions.tsx:126 #: src/uberComponents/ResourceListPage/actions.tsx:173 msgid "Successfully submitted" -msgstr "" +msgstr "Enviado exitosamente" #: src/containers/Scheduling/Availability/index.tsx:43 msgid "Successfully updated" @@ -1424,7 +1463,7 @@ msgstr "Aún no hay documentos" #: src/components/AudioRecorder/index.tsx:94 msgid "This audio cannot be played in Safari, please download the audio or use the Chrome browser" -msgstr "" +msgstr "Este audio no se puede reproducir en Safari, por favor descarga el audio o usa el navegador Chrome" #: src/containers/Scheduling/available-time.ts:16 msgid "Thursday" @@ -1435,6 +1474,10 @@ msgstr "Jueves" msgid "Time" msgstr "Hora" +#: src/components/BaseQuestionnaireResponseForm/widgets/QuestionDateTime.stories.tsx:65 +msgid "Time with no seconds" +msgstr "Hora sin segundos" + #: src/containers/PatientDetails/PatientOrders/index.tsx:27 #: src/containers/PatientDetails/PatientOverviewDynamic/components/PatientNoteListCard/NoteList/index.tsx:33 #: src/containers/PatientDetails/PatientResources/utils.tsx:246 @@ -1499,7 +1542,7 @@ msgstr "URL:" #: src/containers/App/DefaultUserWithNoRoles.tsx:15 msgid "User with no roles in the system" -msgstr "" +msgstr "Usuario sin rol en el sistema" #: src/containers/SignIn/index.tsx:49 #: src/containers/SignIn/index.tsx:98 @@ -1542,6 +1585,10 @@ msgstr "Semana" msgid "Welcome to" msgstr "Bienvenido a" +#: src/utils/relative-date.ts:18 +msgid "y.o." +msgstr "años" + #: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:147 #: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:172 #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/index.tsx:136 @@ -1555,4 +1602,4 @@ msgstr "Actualmente no tienes acceso a los datos del paciente. Para obtenerlos, #: src/components/AudioRecorder/index.tsx:102 msgid "Your browser does not support the audio element" -msgstr "" +msgstr "Tu navegador no sorporta reproducción de audio" diff --git a/src/locale/ru/messages.po b/src/locale/ru/messages.po index 535e8bf0..ea3f2680 100644 --- a/src/locale/ru/messages.po +++ b/src/locale/ru/messages.po @@ -43,6 +43,7 @@ msgstr "" msgid "Activate healthcare service" msgstr "" +#: src/containers/HealthcareServiceList/index.tsx:74 #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:97 #: src/containers/Prescriptions/index.tsx:185 #: src/containers/QuestionnaireBuilder/QuestionnaireSaveForm/index.tsx:82 @@ -198,6 +199,7 @@ msgstr "" msgid "Available units" msgstr "" +#: src/containers/InvoiceList/components/InvoiceListSearchBar/hooks.ts:97 #: src/containers/InvoiceList/tableUtils.tsx:27 msgid "Balanced" msgstr "" @@ -211,6 +213,7 @@ msgstr "" msgid "Batch Number" msgstr "" +#: src/components/BaseQuestionnaireResponseForm/widgets/QuestionDateTime.stories.tsx:37 #: src/containers/PatientDetails/PatientOverviewDynamic/containers/GeneralIInformationDashboardContainer/hooks.ts:31 #: src/containers/PatientList/index.tsx:85 #: src/containers/PatientResourceListExample/index.tsx:48 @@ -230,6 +233,10 @@ msgstr "" msgid "Build your form" msgstr "" +#: src/components/BaseLayout/Footer/index.tsx:15 +msgid "by" +msgstr "" + #: src/containers/PatientDetails/PatientWearables/index.tsx:46 msgid "Calories" msgstr "" @@ -250,6 +257,7 @@ msgstr "" msgid "Cancel Medication Request" msgstr "" +#: src/containers/InvoiceList/components/InvoiceListSearchBar/hooks.ts:101 #: src/containers/InvoiceList/tableUtils.tsx:28 #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:101 #: src/containers/Prescriptions/index.tsx:187 @@ -386,6 +394,10 @@ msgstr "" msgid "CRP" msgstr "" +#: src/utils/relative-date.ts:25 +msgid "d.o." +msgstr "" + #: src/components/PatientEncounter/index.tsx:39 #: src/containers/EncounterList/index.tsx:63 #: src/containers/InvoiceDetails/components/InvoiceDetailsHeader/index.tsx:23 @@ -491,6 +503,7 @@ msgstr "" msgid "Download audio" msgstr "" +#: src/containers/InvoiceList/components/InvoiceListSearchBar/hooks.ts:109 #: src/containers/InvoiceList/tableUtils.tsx:30 #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:121 #: src/containers/Prescriptions/index.tsx:191 @@ -582,6 +595,7 @@ msgstr "" msgid "End date" msgstr "Конец периода" +#: src/containers/InvoiceList/components/InvoiceListSearchBar/hooks.ts:113 #: src/containers/InvoiceList/tableUtils.tsx:31 #: src/containers/Prescriptions/components/PrescriptionsSearchBar/hooks.ts:113 #: src/containers/Prescriptions/index.tsx:189 @@ -726,6 +740,10 @@ msgstr "" msgid "in progress" msgstr "" +#: src/containers/HealthcareServiceList/index.tsx:74 +msgid "Inactive" +msgstr "" + #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/controls.tsx:40 msgid "Inline choice" msgstr "" @@ -753,6 +771,7 @@ msgstr "" msgid "Invoices" msgstr "" +#: src/containers/InvoiceList/components/InvoiceListSearchBar/hooks.ts:105 #: src/containers/InvoiceList/tableUtils.tsx:29 msgid "Issued" msgstr "" @@ -781,6 +800,10 @@ msgstr "" msgid "Listen to the audio" msgstr "" +#: src/containers/EncounterDetails/AIScribe/index.tsx:312 +msgid "Loading..." +msgstr "" + #: src/containers/SignIn/index.tsx:89 msgid "Log in" msgstr "" @@ -797,10 +820,18 @@ msgstr "" msgid "Log out" msgstr "Выйти" +#: src/utils/relative-date.ts:22 +msgid "m.o." +msgstr "" + #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/controls.tsx:101 msgid "Macro text" msgstr "" +#: src/components/BaseLayout/Footer/index.tsx:15 +msgid "Made with" +msgstr "" + #: src/components/DashboardCard/creatinine.tsx:91 msgid "Max" msgstr "" @@ -1236,6 +1267,14 @@ msgstr "" msgid "Select all" msgstr "" +#: src/components/BaseQuestionnaireResponseForm/widgets/QuestionDateTime.stories.tsx:23 +msgid "Select date" +msgstr "" + +#: src/components/BaseQuestionnaireResponseForm/widgets/QuestionDateTime.stories.tsx:51 +msgid "Select time" +msgstr "" + #: src/components/BaseQuestionnaireResponseForm/widgets/choice/index.tsx:30 #: src/components/BaseQuestionnaireResponseForm/widgets/choice/index.tsx:55 msgid "Select..." @@ -1455,6 +1494,10 @@ msgstr "" msgid "Time" msgstr "" +#: src/components/BaseQuestionnaireResponseForm/widgets/QuestionDateTime.stories.tsx:65 +msgid "Time with no seconds" +msgstr "" + #: src/containers/PatientDetails/PatientOrders/index.tsx:27 #: src/containers/PatientDetails/PatientOverviewDynamic/components/PatientNoteListCard/NoteList/index.tsx:33 #: src/containers/PatientDetails/PatientResources/utils.tsx:246 @@ -1562,6 +1605,10 @@ msgstr "" msgid "Welcome to" msgstr "" +#: src/utils/relative-date.ts:18 +msgid "y.o." +msgstr "" + #: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:147 #: src/containers/PatientDetails/PatientDocumentDetails/index.tsx:172 #: src/containers/QuestionnaireBuilder/QuestionnaireItemSettings/index.tsx:136 diff --git a/src/utils/relative-date.ts b/src/utils/relative-date.ts index d93aa9a6..1dc01474 100644 --- a/src/utils/relative-date.ts +++ b/src/utils/relative-date.ts @@ -1,4 +1,5 @@ import { differenceInDays, differenceInMonths, differenceInYears, parseISO } from 'date-fns'; +import { t } from '@lingui/macro'; export function getYears(date: string) { return differenceInYears(new Date(), parseISO(date)); @@ -14,12 +15,12 @@ export function getDays(date: string) { export function getPersonAge(date: string) { if (getYears(date) > 0) { - return `${getYears(date)} y.o.`; + return `${getYears(date)} ${t`y.o.`}`; } if (getMonths(date) > 0) { - return `${getMonths(date)} m.o.`; + return `${getMonths(date)} ${t`m.o.`}`; } - return `${getDays(date)} d.o.`; + return `${getDays(date)} ${t`d.o.`}`; } From 98f543a0f5170079f9b44ad5a47601d3edf4198c Mon Sep 17 00:00:00 2001 From: Alex Lipovka Date: Thu, 6 Feb 2025 14:00:42 +0400 Subject: [PATCH 03/21] PATCH: fix validation schema for repeatable group items --- src/utils/questionnaire.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/utils/questionnaire.ts b/src/utils/questionnaire.ts index c4e69044..5b151c07 100644 --- a/src/utils/questionnaire.ts +++ b/src/utils/questionnaire.ts @@ -72,7 +72,10 @@ export function getDisplay( return ''; } -export function getArrayDisplay(options?: QuestionnaireResponseItemAnswer[], choiceColumn?: QuestionnaireItemChoiceColumn[]): string | null { +export function getArrayDisplay( + options?: QuestionnaireResponseItemAnswer[], + choiceColumn?: QuestionnaireItemChoiceColumn[], +): string | null { if (!options) { return null; } @@ -110,10 +113,13 @@ export function questionnaireItemsToValidationSchema(questionnaireItems: Questio }); } else { validationSchema[item.linkId] = schema; - - if (item.item && !item.repeats) { + if (item.item) { validationSchema[item.linkId] = yup - .object({ items: questionnaireItemsToValidationSchema(item.item) }) + .object({ + items: item.repeats + ? yup.array().of(questionnaireItemsToValidationSchema(item.item)) + : questionnaireItemsToValidationSchema(item.item), + }) .required(); } } From 476d813b607322345e21802fb15def1717cc93a1 Mon Sep 17 00:00:00 2001 From: Alex Lipovka Date: Thu, 6 Feb 2025 18:46:29 +0400 Subject: [PATCH 04/21] PATCH: update validation enableWhen rule for repeatable groups --- src/utils/questionnaire.ts | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/utils/questionnaire.ts b/src/utils/questionnaire.ts index 5b151c07..e21e81cd 100644 --- a/src/utils/questionnaire.ts +++ b/src/utils/questionnaire.ts @@ -101,6 +101,14 @@ export function questionnaireItemsToValidationSchema(questionnaireItems: Questio schema = yup.date(); if (item.required) schema = schema.required(); schema = createSchemaArrayOfValues(yup.object({ date: schema })).required(); + } else if (item.item) { + schema = yup + .object({ + items: item.repeats + ? yup.array().of(questionnaireItemsToValidationSchema(item.item)) + : questionnaireItemsToValidationSchema(item.item), + }) + .required(); } else { schema = item.required ? yup.array().of(yup.mixed()).min(1).required() : yup.mixed().nullable(); } @@ -113,15 +121,6 @@ export function questionnaireItemsToValidationSchema(questionnaireItems: Questio }); } else { validationSchema[item.linkId] = schema; - if (item.item) { - validationSchema[item.linkId] = yup - .object({ - items: item.repeats - ? yup.array().of(questionnaireItemsToValidationSchema(item.item)) - : questionnaireItemsToValidationSchema(item.item), - }) - .required(); - } } }); From d6c05aaec4d3ae257887d4fce420d1aae81f5f18 Mon Sep 17 00:00:00 2001 From: Dmitry Shutov Date: Fri, 7 Feb 2025 20:47:48 +0700 Subject: [PATCH 05/21] Pass locale property to ANTD config provider component --- src/services/i18n.ts | 11 +++++++++++ src/theme/ThemeProvider.tsx | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/services/i18n.ts b/src/services/i18n.ts index 67d168e1..3094806f 100644 --- a/src/services/i18n.ts +++ b/src/services/i18n.ts @@ -1,4 +1,9 @@ import { i18n } from '@lingui/core'; +import { Locale } from 'antd/es/locale'; +import enAntdLocale from 'antd/es/locale/en_US'; +import esAntdLocale from 'antd/es/locale/es_ES'; +import ruAntdLocale from 'antd/es/locale/ru_RU'; + import { en, es, ru } from 'make-plural/plurals'; import { messages as enMessages } from 'src/locale/en/messages'; @@ -42,3 +47,9 @@ export function dynamicActivate(locale: LocaleCode) { i18n.activate(locale); } + +export const antdLocaleMap: { [localeCode in LocaleCode]: Locale } = { + en: enAntdLocale, + es: esAntdLocale, + ru: ruAntdLocale, +}; diff --git a/src/theme/ThemeProvider.tsx b/src/theme/ThemeProvider.tsx index 7be1ff61..c149e8f4 100644 --- a/src/theme/ThemeProvider.tsx +++ b/src/theme/ThemeProvider.tsx @@ -4,6 +4,7 @@ import { ThemeProvider as StyledComponentsThemeProvider, createGlobalStyle } fro import { getAppTheme, getANTDTheme } from './'; import { useTheme } from '../utils/theme'; +import { antdLocaleMap, getCurrentLocale } from 'src/services/i18n'; interface Props { theme?: 'dark' | 'light'; @@ -36,7 +37,7 @@ export function ThemeProvider(props: Props) { }; return ( - + {children} From c11e179df41dbf23d92304473c086eabc6743ad1 Mon Sep 17 00:00:00 2001 From: Dmitry Shutov Date: Sat, 8 Feb 2025 14:02:52 +0700 Subject: [PATCH 06/21] Fix ESLint import sorting warning --- src/services/i18n.ts | 1 - src/theme/ThemeProvider.tsx | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/i18n.ts b/src/services/i18n.ts index 3094806f..da994af1 100644 --- a/src/services/i18n.ts +++ b/src/services/i18n.ts @@ -3,7 +3,6 @@ import { Locale } from 'antd/es/locale'; import enAntdLocale from 'antd/es/locale/en_US'; import esAntdLocale from 'antd/es/locale/es_ES'; import ruAntdLocale from 'antd/es/locale/ru_RU'; - import { en, es, ru } from 'make-plural/plurals'; import { messages as enMessages } from 'src/locale/en/messages'; diff --git a/src/theme/ThemeProvider.tsx b/src/theme/ThemeProvider.tsx index c149e8f4..86453ebc 100644 --- a/src/theme/ThemeProvider.tsx +++ b/src/theme/ThemeProvider.tsx @@ -2,9 +2,10 @@ import { ConfigProvider as ANTDConfigProvider } from 'antd'; import { ReactNode } from 'react'; import { ThemeProvider as StyledComponentsThemeProvider, createGlobalStyle } from 'styled-components'; +import { antdLocaleMap, getCurrentLocale } from 'src/services/i18n'; + import { getAppTheme, getANTDTheme } from './'; import { useTheme } from '../utils/theme'; -import { antdLocaleMap, getCurrentLocale } from 'src/services/i18n'; interface Props { theme?: 'dark' | 'light'; From 0557ebf129359d9e093621905269708ef85c0a27 Mon Sep 17 00:00:00 2001 From: Dmitry Shutov Date: Mon, 10 Feb 2025 13:04:26 +0700 Subject: [PATCH 07/21] Import antd Locale type explicitly --- src/services/i18n.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/i18n.ts b/src/services/i18n.ts index da994af1..d325b6e5 100644 --- a/src/services/i18n.ts +++ b/src/services/i18n.ts @@ -1,5 +1,5 @@ import { i18n } from '@lingui/core'; -import { Locale } from 'antd/es/locale'; +import type { Locale } from 'antd/es/locale'; import enAntdLocale from 'antd/es/locale/en_US'; import esAntdLocale from 'antd/es/locale/es_ES'; import ruAntdLocale from 'antd/es/locale/ru_RU'; From 906aa4a532c7403a6fef748870e403177e7e3c4d Mon Sep 17 00:00:00 2001 From: Vladimir <90250006+Vlpros@users.noreply.github.com> Date: Mon, 10 Feb 2025 12:44:32 +0100 Subject: [PATCH 08/21] Delete useless form container (#446) --- src/containers/PatientQuestionnaire/index.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/containers/PatientQuestionnaire/index.tsx b/src/containers/PatientQuestionnaire/index.tsx index c79a32e5..8ecfe425 100644 --- a/src/containers/PatientQuestionnaire/index.tsx +++ b/src/containers/PatientQuestionnaire/index.tsx @@ -68,9 +68,7 @@ export function PatientQuestionnaire({ onSuccess }: { onSuccess?: () => void }) return ( Questionnaire}> -
- {isLoading ? : } -
+ {isLoading ? : }
); } From 2416e694211f2634360af2a65d1f8642a5f2c222 Mon Sep 17 00:00:00 2001 From: Ilya Beda Date: Wed, 12 Feb 2025 12:01:19 +1100 Subject: [PATCH 09/21] Show text if code is missing --- .../components/StandardCard/prepare.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx b/src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx index 58ca0bcd..0d4890d9 100644 --- a/src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx +++ b/src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx @@ -44,7 +44,7 @@ export function prepareAllergies( key: 'name', render: (resource: AllergyIntolerance) => ( ( ( Date: Mon, 24 Feb 2025 15:29:11 +1100 Subject: [PATCH 10/21] Fix useDebounce deps --- src/utils/debounce.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/debounce.ts b/src/utils/debounce.ts index f2c315e3..6a176cb7 100644 --- a/src/utils/debounce.ts +++ b/src/utils/debounce.ts @@ -11,7 +11,7 @@ export function useDebounce(value: T, delay: number) { return () => { clearTimeout(timeoutId); }; - }, [value, delay]); + }, [JSON.stringify(value), delay]); return debouncedValue; } From 26979f920f65692fa191f21bd42206584b0fe2e3 Mon Sep 17 00:00:00 2001 From: Alex Lipovka Date: Mon, 24 Feb 2025 20:40:14 +0400 Subject: [PATCH 11/21] Update QuestionInteger to support Integer validation Ref https://github.com/beda-software/fhir-emr/issues/454 --- src/components/BaseQuestionnaireResponseForm/widgets/number.tsx | 2 ++ src/utils/questionnaire.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/BaseQuestionnaireResponseForm/widgets/number.tsx b/src/components/BaseQuestionnaireResponseForm/widgets/number.tsx index 397e3237..561d5905 100644 --- a/src/components/BaseQuestionnaireResponseForm/widgets/number.tsx +++ b/src/components/BaseQuestionnaireResponseForm/widgets/number.tsx @@ -4,6 +4,7 @@ import { useState } from 'react'; import { QuestionItemProps } from 'sdc-qrf'; import { useFieldController } from '../hooks'; +import _ from 'lodash'; const inputStyle = { width: '100%' }; @@ -27,6 +28,7 @@ export function QuestionInteger({ parentPath, questionItem }: QuestionItemProps) value={value} required={required} placeholder={placeholder} + parser={(displayValue) => _.toInteger(displayValue)} /> ); diff --git a/src/utils/questionnaire.ts b/src/utils/questionnaire.ts index e21e81cd..c1d16ae2 100644 --- a/src/utils/questionnaire.ts +++ b/src/utils/questionnaire.ts @@ -94,7 +94,7 @@ export function questionnaireItemsToValidationSchema(questionnaireItems: Questio if (item.maxLength && item.maxLength > 0) schema = (schema as yup.StringSchema).max(item.maxLength); schema = createSchemaArrayOfValues(yup.object({ string: schema })).required(); } else if (item.type === 'integer') { - schema = yup.number(); + schema = yup.number().integer(); if (item.required) schema = schema.required(); schema = createSchemaArrayOfValues(yup.object({ integer: schema })).required(); } else if (item.type === 'date') { From 2d467cfe455ed10c69923d2b0e70dd8e0823156d Mon Sep 17 00:00:00 2001 From: Alex Lipovka Date: Mon, 24 Feb 2025 21:01:32 +0400 Subject: [PATCH 12/21] Bump fhir-react version to 1.8.7 Brings `usePager` with `set` function to update response without reloading --- package.json | 2 +- src/containers/InvoiceList/tableUtils.tsx | 2 +- src/containers/InvoiceList/types.ts | 4 ++-- yarn.lock | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 966adb1d..d5e65a0b 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "@ant-design/colors": "^7.0.0", "@ant-design/icons": "^5.1.4", "@beda.software/emr-config": "*", - "@beda.software/fhir-react": "^1.8.6", + "@beda.software/fhir-react": "^1.8.7", "@beda.software/remote-data": "^1.1.3", "@fullcalendar/core": "^6.1.15", "@fullcalendar/daygrid": "^6.1.8", diff --git a/src/containers/InvoiceList/tableUtils.tsx b/src/containers/InvoiceList/tableUtils.tsx index d428f8a8..3c12806c 100644 --- a/src/containers/InvoiceList/tableUtils.tsx +++ b/src/containers/InvoiceList/tableUtils.tsx @@ -100,7 +100,7 @@ export function getInvoiceTableColumns( practitioners: Practitioner[], practitionerRoles: PractitionerRole[], patients: Patient[], - pagerManager: PagerManager, + pagerManager: PagerManager, ) { const excludeColumnKeys = matchCurrentUserRole({ [Role.Admin]: () => ['patientActions'], diff --git a/src/containers/InvoiceList/types.ts b/src/containers/InvoiceList/types.ts index cc9605d5..3d8092b7 100644 --- a/src/containers/InvoiceList/types.ts +++ b/src/containers/InvoiceList/types.ts @@ -1,4 +1,4 @@ -import { Invoice } from 'fhir/r4b'; +import { Invoice, Patient, Practitioner, PractitionerRole } from 'fhir/r4b'; import { PagerManager } from '@beda.software/fhir-react'; @@ -22,7 +22,7 @@ export interface InvoiceListSearchBarSelectProps { } export interface InvoiceActionsProps { - manager: PagerManager; + manager: PagerManager; invoice: Invoice; simplified?: boolean; } diff --git a/yarn.lock b/yarn.lock index 8e470978..0796ba0f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -772,10 +772,10 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@beda.software/fhir-react@^1.8.6": - version "1.8.6" - resolved "https://registry.yarnpkg.com/@beda.software/fhir-react/-/fhir-react-1.8.6.tgz#d996c28a47edb776786fa033f415b22d90e00f21" - integrity sha512-ip+TLFp1BN2/NlxPMzIsVisGhb8GM5EvZXm6o/9+06tggBetIgaYk/Ye+nLmAc1l83DtdqQMfJkyhBnSCJ9Avw== +"@beda.software/fhir-react@^1.8.7": + version "1.8.7" + resolved "https://registry.yarnpkg.com/@beda.software/fhir-react/-/fhir-react-1.8.7.tgz#5f15d2baf770245fcc5c7faca6dd78b3b1cea4e4" + integrity sha512-j2JfdgYGCK2MuIqEurM8j3MMkOYtOEqkaHrBLZfZYgGQv2WJno+nG9PCsey17hVFC4MZ8kbm5IG4u7QRAZqdGQ== dependencies: "@beda.software/remote-data" "^1.1.3" axios "^1.6.2" From 31d353071f6818f8f2e981ac27ccb5a332928308 Mon Sep 17 00:00:00 2001 From: Alex Lipovka Date: Tue, 18 Feb 2025 21:57:43 +0400 Subject: [PATCH 13/21] Refactor LinkToEdit - Uses context to get custom path extraction - Searches through all targets within provenance - Always uses latest provenance --- .../LinkToEdit/__tests__/LinkToEdit.test.ts | 66 +++++++++++++++++++ src/components/LinkToEdit/context.ts | 11 ++++ src/components/LinkToEdit/index.tsx | 38 +++++++++++ src/components/LinkToEdit/utils.ts | 30 +++++++++ src/components/ResourceTable/index.tsx | 21 ------ src/components/index.ts | 1 + .../PatientDetails/PatientOrders/index.tsx | 3 +- .../components/LinkToEdit/index.tsx | 32 --------- .../components/StandardCard/prepare.tsx | 2 +- .../PatientDetails/PatientResources/utils.tsx | 3 +- 10 files changed, 151 insertions(+), 56 deletions(-) create mode 100644 src/components/LinkToEdit/__tests__/LinkToEdit.test.ts create mode 100644 src/components/LinkToEdit/context.ts create mode 100644 src/components/LinkToEdit/index.tsx create mode 100644 src/components/LinkToEdit/utils.ts delete mode 100644 src/containers/PatientDetails/PatientOverviewDynamic/components/LinkToEdit/index.tsx diff --git a/src/components/LinkToEdit/__tests__/LinkToEdit.test.ts b/src/components/LinkToEdit/__tests__/LinkToEdit.test.ts new file mode 100644 index 00000000..22fd3efe --- /dev/null +++ b/src/components/LinkToEdit/__tests__/LinkToEdit.test.ts @@ -0,0 +1,66 @@ +import { Provenance } from 'fhir/r4b'; +import { describe } from 'vitest'; + +import { getLinkToEditUrl } from 'src/components/LinkToEdit/utils'; + +describe('getSourceFromProvenance', () => { + test('getSourceFromProvenance for empty Provenance', () => { + const provenance = {} as Provenance; + const pathname = '/patients/patient1/resources'; + + expect(getLinkToEditUrl({ provenance, pathname })).toBeUndefined(); + }); + + test('getSourceFromProvenance for undefined Provenance', () => { + expect(getLinkToEditUrl({})).toBeUndefined(); + }); + + test('getSourceFromProvenance for Provenance with source reference', () => { + const provenance: Provenance = { + resourceType: 'Provenance', + entity: [ + { + role: 'source', + what: { + reference: 'QuestionnaireResponse/getme', + }, + }, + ], + agent: [ + { + who: {}, + }, + ], + target: [{}], + recorded: '', + }; + const pathname = '/patients/patient1/resources'; + + expect(getLinkToEditUrl({ provenance, pathname })).toEqual('/patients/patient1/documents/getme'); + }); + + test('getSourceFromProvenance for Provenance with source reference and custom to', () => { + const provenance: Provenance = { + resourceType: 'Provenance', + entity: [ + { + role: 'source', + what: { + reference: 'QuestionnaireResponse/getme', + }, + }, + ], + agent: [ + { + who: {}, + }, + ], + target: [{}], + recorded: '', + }; + const pathname = '/patients/patient1/resources'; + const to = '/custom'; + + expect(getLinkToEditUrl({ provenance, pathname, to })).toEqual('/custom/getme'); + }); +}); diff --git a/src/components/LinkToEdit/context.ts b/src/components/LinkToEdit/context.ts new file mode 100644 index 00000000..1e1dbefe --- /dev/null +++ b/src/components/LinkToEdit/context.ts @@ -0,0 +1,11 @@ +import { createContext } from 'react'; + +import { getLinkToEditUrl, GetLinkToEditUrlProps } from 'src/components/LinkToEdit/utils'; + +export type LinkToEditContextType = { + getLinkToEditUrl: (props: GetLinkToEditUrlProps) => string | undefined; +}; + +export const LinkToEditContext = createContext({ + getLinkToEditUrl, +}); diff --git a/src/components/LinkToEdit/index.tsx b/src/components/LinkToEdit/index.tsx new file mode 100644 index 00000000..586e83e2 --- /dev/null +++ b/src/components/LinkToEdit/index.tsx @@ -0,0 +1,38 @@ +import { Resource, Provenance } from 'fhir/r4b'; +import { useContext } from 'react'; +import { Link, useLocation } from 'react-router-dom'; +import { fromFHIRReference } from 'sdc-qrf'; + +import { LinkToEditContext } from 'src/components/LinkToEdit/context'; + +interface LinkToEditProps { + name?: string; + resource: Resource; + provenanceList: Provenance[]; + to?: string; +} + +export function LinkToEdit(props: LinkToEditProps) { + const { name, resource, provenanceList, to } = props; + + const location = useLocation(); + const provenance = provenanceList + .filter((provenance) => + provenance.target.find( + (target) => + fromFHIRReference(target)?.id === resource.id && + fromFHIRReference(target)?.resourceType === resource.resourceType, + ), + ) + .sort((a, b) => new Date(b.recorded).getTime() - new Date(a.recorded).getTime())[0]; + + const { getLinkToEditUrl } = useContext(LinkToEditContext); + + const customPathTo = getLinkToEditUrl({ provenance, pathname: location.pathname, to }); + + if (!customPathTo) { + return <>{name}; + } + + return {name}; +} diff --git a/src/components/LinkToEdit/utils.ts b/src/components/LinkToEdit/utils.ts new file mode 100644 index 00000000..d37a9f04 --- /dev/null +++ b/src/components/LinkToEdit/utils.ts @@ -0,0 +1,30 @@ +import { Provenance } from 'fhir/r4b'; +import { fromFHIRReference } from 'sdc-qrf'; + +export type GetLinkToEditUrlProps = { + provenance?: Provenance; + pathname?: string; + to?: string; +}; + +export function getLinkToEditUrl(props: GetLinkToEditUrlProps): string | undefined { + const { provenance, pathname, to } = props; + + const entity = provenance?.entity?.[0]?.what; + const qrId = fromFHIRReference(entity)?.id; + const baseUrl = pathname?.split('/').slice(0, 3).join('/'); + + if (!qrId) { + return undefined; + } + + if (to) { + return `${to}/${qrId}`; + } + + if (!baseUrl) { + return undefined; + } + + return `${baseUrl}/documents/${qrId}`; +} diff --git a/src/components/ResourceTable/index.tsx b/src/components/ResourceTable/index.tsx index a5aa4130..957a6413 100644 --- a/src/components/ResourceTable/index.tsx +++ b/src/components/ResourceTable/index.tsx @@ -3,8 +3,6 @@ import { Empty } from 'antd'; import { ColumnsType } from 'antd/lib/table'; import { Provenance, Resource } from 'fhir/r4b'; import { ReactNode } from 'react'; -import { Link, useLocation } from 'react-router-dom'; -import { fromFHIRReference } from 'sdc-qrf'; import { RenderRemoteData, SearchParams, extractBundleResources, ResourcesMap } from '@beda.software/fhir-react'; @@ -77,22 +75,3 @@ export function ResourceTable(props: ResourceTableProps) ); } - -export function LinkToEdit(props: { name?: string; resource: Resource; provenanceList: Provenance[] }) { - const { name, resource, provenanceList } = props; - const location = useLocation(); - const provenance = provenanceList.find( - (p) => - fromFHIRReference(p.target[0])?.id === resource.id && - fromFHIRReference(p.target[0])?.resourceType === resource.resourceType, - ); - const entity = provenance?.entity?.[0]?.what; - const qrId = fromFHIRReference(entity)?.id; - const pathname = location.pathname.split('/').slice(0, 3).join('/'); - - if (qrId) { - return {name}; - } - - return <>{name}; -} diff --git a/src/components/index.ts b/src/components/index.ts index fa495c91..906aba0c 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -11,6 +11,7 @@ export * from './DatePicker'; export * from './Empty'; export * from './EncounterStatusBadge'; export * from './EncountersTable'; +export * from './LinkToEdit'; export * from './Modal'; export * from './ModalChangeActiveHealthcareService'; export * from './ModalEditHealthcareService'; diff --git a/src/containers/PatientDetails/PatientOrders/index.tsx b/src/containers/PatientDetails/PatientOrders/index.tsx index 924e675c..793b1e6e 100644 --- a/src/containers/PatientDetails/PatientOrders/index.tsx +++ b/src/containers/PatientDetails/PatientOrders/index.tsx @@ -8,9 +8,10 @@ import styled from 'styled-components'; import { WithId } from '@beda.software/fhir-react'; +import { LinkToEdit } from 'src/components/LinkToEdit'; import { Modal } from 'src/components/Modal'; import { QuestionnaireResponseForm } from 'src/components/QuestionnaireResponseForm'; -import { ResourceTable, LinkToEdit } from 'src/components/ResourceTable'; +import { ResourceTable } from 'src/components/ResourceTable'; import { questionnaireIdLoader } from 'src/hooks/questionnaire-response-form-data'; import { formatHumanDate } from 'src/utils/date'; import { selectCurrentUserRoleResource } from 'src/utils/role'; diff --git a/src/containers/PatientDetails/PatientOverviewDynamic/components/LinkToEdit/index.tsx b/src/containers/PatientDetails/PatientOverviewDynamic/components/LinkToEdit/index.tsx deleted file mode 100644 index 4c49d494..00000000 --- a/src/containers/PatientDetails/PatientOverviewDynamic/components/LinkToEdit/index.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { Resource, Provenance } from 'fhir/r4b'; -import { Link, useLocation } from 'react-router-dom'; -import { fromFHIRReference } from 'sdc-qrf'; - -interface LinkToEditProps { - name?: string; - resource: Resource; - provenanceList: Provenance[]; - to?: string; -} -export function LinkToEdit(props: LinkToEditProps) { - const { name, resource, provenanceList, to } = props; - const location = useLocation(); - const provenance = provenanceList.find((provenance) => { - const targets = provenance.target || []; - - return targets.find((target) => { - return ( - fromFHIRReference(target)?.id === resource.id && - fromFHIRReference(target)?.resourceType === resource.resourceType - ); - }); - }); - const entity = provenance?.entity?.[0]?.what; - const qrId = fromFHIRReference(entity)?.id; - - if (qrId) { - return {name}; - } - - return <>{name}; -} diff --git a/src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx b/src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx index 0d4890d9..7ed5669a 100644 --- a/src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx +++ b/src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx @@ -19,8 +19,8 @@ import { extractExtension } from 'sdc-qrf'; import { WithId, extractBundleResources, formatFHIRDate, parseFHIRDateTime } from '@beda.software/fhir-react'; +import { LinkToEdit } from 'src/components/LinkToEdit'; import { PatientActivitySummary } from 'src/containers/PatientDetails/PatientActivitySummary'; -import { LinkToEdit } from 'src/containers/PatientDetails/PatientOverviewDynamic/components/LinkToEdit'; import { OverviewCard } from 'src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/types'; import medicationIcon from 'src/containers/PatientDetails/PatientOverviewDynamic/images/medication.svg'; import { formatHumanDate } from 'src/utils/date'; diff --git a/src/containers/PatientDetails/PatientResources/utils.tsx b/src/containers/PatientDetails/PatientResources/utils.tsx index e5c9458b..51e15df2 100644 --- a/src/containers/PatientDetails/PatientResources/utils.tsx +++ b/src/containers/PatientDetails/PatientResources/utils.tsx @@ -15,7 +15,8 @@ import { extractExtension } from 'sdc-qrf'; import { WithId } from '@beda.software/fhir-react'; -import { ResourceTable, Option, LinkToEdit } from 'src/components/ResourceTable'; +import { LinkToEdit } from 'src/components/LinkToEdit'; +import { ResourceTable, Option } from 'src/components/ResourceTable'; import { compileAsArray } from 'src/utils'; import { formatHumanDate, formatHumanDateTime } from 'src/utils/date'; From fe2e854cf3fa0e57d949210414dd9f649f9057c0 Mon Sep 17 00:00:00 2001 From: Alex Lipovka Date: Tue, 25 Feb 2025 10:54:13 +0400 Subject: [PATCH 14/21] Update readonly QR form item and group controls Updates to ReadonlyQuestionnaireresponseForm: - Add context `ItemControlQuestionItemReadonlyWidgetsContext` - Add context `ItemControlGroupItemReadonlyWidgetsContext` - Add default `MarkdownRenderControl` for `markdown-editor` in RQRF --- .../ReadonlyQuestionnaireResponseForm.tsx | 15 ++++++++++++- .../BaseQuestionnaireResponseForm/context.ts | 3 +++ .../readonly-widgets/MarkdownRender/index.tsx | 21 +++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/components/BaseQuestionnaireResponseForm/readonly-widgets/MarkdownRender/index.tsx diff --git a/src/components/BaseQuestionnaireResponseForm/ReadonlyQuestionnaireResponseForm.tsx b/src/components/BaseQuestionnaireResponseForm/ReadonlyQuestionnaireResponseForm.tsx index a0140bcc..d664613e 100644 --- a/src/components/BaseQuestionnaireResponseForm/ReadonlyQuestionnaireResponseForm.tsx +++ b/src/components/BaseQuestionnaireResponseForm/ReadonlyQuestionnaireResponseForm.tsx @@ -1,3 +1,4 @@ +import { useContext } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; import { calcInitialContext, @@ -8,6 +9,13 @@ import { QuestionnaireResponseFormProvider, } from 'sdc-qrf'; +import { + ItemControlGroupItemReadonlyWidgetsContext, + ItemControlQuestionItemReadonlyWidgetsContext, +} from 'src/components/BaseQuestionnaireResponseForm/context'; +import { MarkdownRenderControl } from 'src/components/BaseQuestionnaireResponseForm/readonly-widgets/MarkdownRender'; + +import { AudioAttachment } from './readonly-widgets/AudioAttachment'; import { QuestionBoolean } from './readonly-widgets/boolean'; import { QuestionChoice } from './readonly-widgets/choice'; import { QuestionDateTime } from './readonly-widgets/date'; @@ -19,7 +27,6 @@ import { AnxietyScore, DepressionScore } from './readonly-widgets/score'; import { QuestionText, TextWithInput } from './readonly-widgets/string'; import { TimeRangePickerControl } from './readonly-widgets/TimeRangePickerControl'; import { UploadFile } from './readonly-widgets/UploadFile'; -import { AudioAttachment } from './readonly-widgets/AudioAttachment'; interface Props extends Partial { formData: QuestionnaireResponseFormData; @@ -40,6 +47,9 @@ export function ReadonlyQuestionnaireResponseForm(props: Props) { const formValues = watch(); + const ItemControlQuestionItemReadonlyWidgetsFromContext = useContext(ItemControlQuestionItemReadonlyWidgetsContext); + const ItemControlGroupItemReadonlyWidgetsFromContext = useContext(ItemControlGroupItemReadonlyWidgetsContext); + return (
@@ -54,6 +64,7 @@ export function ReadonlyQuestionnaireResponseForm(props: Props) { row: Row, 'time-range-picker': TimeRangePickerControl, ...itemControlGroupItemComponents, + ...ItemControlGroupItemReadonlyWidgetsFromContext, }} questionItemComponents={{ text: QuestionText, @@ -76,7 +87,9 @@ export function ReadonlyQuestionnaireResponseForm(props: Props) { 'depression-score': DepressionScore, 'input-inside-text': TextWithInput, 'audio-recorder-uploader': AudioAttachment, + 'markdown-editor': MarkdownRenderControl, ...itemControlQuestionItemComponents, + ...ItemControlQuestionItemReadonlyWidgetsFromContext, }} > <> diff --git a/src/components/BaseQuestionnaireResponseForm/context.ts b/src/components/BaseQuestionnaireResponseForm/context.ts index ffed68c6..93013e4a 100644 --- a/src/components/BaseQuestionnaireResponseForm/context.ts +++ b/src/components/BaseQuestionnaireResponseForm/context.ts @@ -7,6 +7,9 @@ import { BaseQuestionnaireResponseFormProps } from '.'; export const ItemControlQuestionItemWidgetsContext = createContext({}); export const ItemControlGroupItemWidgetsContext = createContext({}); +export const ItemControlQuestionItemReadonlyWidgetsContext = createContext({}); +export const ItemControlGroupItemReadonlyWidgetsContext = createContext({}); + interface BaseQuestionnaireResponseFormPropsContextProps extends BaseQuestionnaireResponseFormProps { submitting: boolean; debouncedSaveDraft?: DebouncedFunc<(currentFormValues: FormItems) => Promise>; diff --git a/src/components/BaseQuestionnaireResponseForm/readonly-widgets/MarkdownRender/index.tsx b/src/components/BaseQuestionnaireResponseForm/readonly-widgets/MarkdownRender/index.tsx new file mode 100644 index 00000000..90d881c3 --- /dev/null +++ b/src/components/BaseQuestionnaireResponseForm/readonly-widgets/MarkdownRender/index.tsx @@ -0,0 +1,21 @@ +import classNames from 'classnames'; +import Markdown from 'react-markdown'; +import { QuestionItemProps } from 'sdc-qrf'; + +import { useFieldController } from 'src/components/BaseQuestionnaireResponseForm/hooks'; + +import s from '../ReadonlyWidgets.module.scss'; +import { S } from '../ReadonlyWidgets.styles'; + +export function MarkdownRenderControl({ parentPath, questionItem }: QuestionItemProps) { + const { linkId, text } = questionItem; + const fieldName = [...parentPath, linkId, 0, 'value', 'string']; + const { value } = useFieldController(fieldName, questionItem); + + return ( + + {text} + {value || '-'} + + ); +} From 8e0c364012f5af0aba052c1c92ce418fa9a3f9c6 Mon Sep 17 00:00:00 2001 From: Ilya Beda Date: Tue, 25 Feb 2025 18:11:22 +1100 Subject: [PATCH 15/21] Export ResourceListPageProps --- src/uberComponents/ResourceListPage/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uberComponents/ResourceListPage/index.tsx b/src/uberComponents/ResourceListPage/index.tsx index 68a3e868..a1dc92c8 100644 --- a/src/uberComponents/ResourceListPage/index.tsx +++ b/src/uberComponents/ResourceListPage/index.tsx @@ -45,7 +45,7 @@ interface ReportColumn { value: React.ReactNode; } -interface ResourceListPageProps { +export interface ResourceListPageProps { /* Page header title (for example, Organizations) */ headerTitle: string; From 3585327c35a8cdcf47e753584e2d731d887ad0c8 Mon Sep 17 00:00:00 2001 From: Ilya Beda Date: Tue, 25 Feb 2025 18:58:45 +1100 Subject: [PATCH 16/21] Use _count in pager --- src/hooks/pager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/pager.ts b/src/hooks/pager.ts index 00ff71a8..a3677987 100644 --- a/src/hooks/pager.ts +++ b/src/hooks/pager.ts @@ -13,7 +13,7 @@ export function usePagerExtended( debouncedFilterValues?: F, defaultPageSize?: number, ) { - const [pageSize, setPageSize] = useState(defaultPageSize ?? 10); + const [pageSize, setPageSize] = useState(defaultPageSize ?? searchParams?._count ?? 10); const [resourceResponse, pagerManager] = usePager({ resourceType, From ea51bd12341b4d36a2a766755b5fc0835ce667ec Mon Sep 17 00:00:00 2001 From: Ilya Beda Date: Tue, 25 Feb 2025 18:58:52 +1100 Subject: [PATCH 17/21] Expose pagerManager --- src/uberComponents/ResourceListPage/hooks.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/uberComponents/ResourceListPage/hooks.ts b/src/uberComponents/ResourceListPage/hooks.ts index 29d75484..8202977d 100644 --- a/src/uberComponents/ResourceListPage/hooks.ts +++ b/src/uberComponents/ResourceListPage/hooks.ts @@ -81,6 +81,7 @@ export function useResourceListPage( return { pagination, + pagerManager, recordResponse, handleTableChange, selectedRowKeys, From 7b4c86d5efd5e67129dcd689c2fdbf92fddaa0fd Mon Sep 17 00:00:00 2001 From: Ilya Beda Date: Tue, 25 Feb 2025 19:06:15 +1100 Subject: [PATCH 18/21] Revert "Expose pagerManager" This reverts commit ea51bd12341b4d36a2a766755b5fc0835ce667ec. --- src/uberComponents/ResourceListPage/hooks.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/uberComponents/ResourceListPage/hooks.ts b/src/uberComponents/ResourceListPage/hooks.ts index 8202977d..29d75484 100644 --- a/src/uberComponents/ResourceListPage/hooks.ts +++ b/src/uberComponents/ResourceListPage/hooks.ts @@ -81,7 +81,6 @@ export function useResourceListPage( return { pagination, - pagerManager, recordResponse, handleTableChange, selectedRowKeys, From e668ee49d217ff43881bdc1157cd184c4c4b11bc Mon Sep 17 00:00:00 2001 From: Ilya Beda Date: Tue, 25 Feb 2025 19:10:03 +1100 Subject: [PATCH 19/21] Revert "Use _count in pager" This reverts commit 3585327c35a8cdcf47e753584e2d731d887ad0c8. --- src/hooks/pager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/pager.ts b/src/hooks/pager.ts index a3677987..00ff71a8 100644 --- a/src/hooks/pager.ts +++ b/src/hooks/pager.ts @@ -13,7 +13,7 @@ export function usePagerExtended( debouncedFilterValues?: F, defaultPageSize?: number, ) { - const [pageSize, setPageSize] = useState(defaultPageSize ?? searchParams?._count ?? 10); + const [pageSize, setPageSize] = useState(defaultPageSize ?? 10); const [resourceResponse, pagerManager] = usePager({ resourceType, From 9991df0eddd7d7c340dd4c0ff21ba914afb9bbb2 Mon Sep 17 00:00:00 2001 From: Ilya Beda Date: Wed, 26 Feb 2025 11:48:11 +1100 Subject: [PATCH 20/21] Remove antd deps for useResourceListPage --- .../PatientResourceListExample/index.tsx | 4 +- src/uberComponents/ResourceListPage/hooks.ts | 43 +++++++++++-------- src/uberComponents/ResourceListPage/index.tsx | 41 +++++++++++------- 3 files changed, 53 insertions(+), 35 deletions(-) diff --git a/src/containers/PatientResourceListExample/index.tsx b/src/containers/PatientResourceListExample/index.tsx index 23f310bd..52ee0f40 100644 --- a/src/containers/PatientResourceListExample/index.tsx +++ b/src/containers/PatientResourceListExample/index.tsx @@ -9,8 +9,8 @@ import { formatHumanDate } from 'src/utils/date'; import { renderHumanName } from 'src/utils/fhir'; import { matchCurrentUserRole, Role } from 'src/utils/role'; -import { getPatientSearchParamsForPractitioner } from './utils'; import { S } from './styles'; +import { getPatientSearchParamsForPractitioner } from './utils'; export function PatientResourceListExample() { /* @@ -18,7 +18,7 @@ export function PatientResourceListExample() { */ const searchParams = matchCurrentUserRole({ [Role.Admin]: () => { - return {}; + return { _count: 33 }; }, [Role.Practitioner]: (practitioner) => { return getPatientSearchParamsForPractitioner(practitioner.id); diff --git a/src/uberComponents/ResourceListPage/hooks.ts b/src/uberComponents/ResourceListPage/hooks.ts index 29d75484..f5f7729f 100644 --- a/src/uberComponents/ResourceListPage/hooks.ts +++ b/src/uberComponents/ResourceListPage/hooks.ts @@ -1,13 +1,12 @@ -import { TablePaginationConfig } from 'antd'; import { Bundle, Resource } from 'fhir/r4b'; import { useEffect, useMemo, useState } from 'react'; -import { SearchParams } from '@beda.software/fhir-react'; +import { SearchParams, usePager } from '@beda.software/fhir-react'; import { isSuccess, mapSuccess } from '@beda.software/remote-data'; import { ColumnFilterValue } from 'src/components/SearchBar/types'; import { getSearchBarColumnFilterValue } from 'src/components/SearchBar/utils'; -import { usePagerExtended } from 'src/hooks/pager'; +import { service } from 'src/services'; import { useDebounce } from 'src/utils/debounce'; export function useResourceListPage( @@ -30,22 +29,31 @@ export function useResourceListPage( }; const searchParams = { _sort: '-_lastUpdated', ...defaultSearchParams, ...searchBarSearchParams }; - const { - resourceResponse, - pagerManager, - handleTableChange: pagerHandleTableChange, - pagination, - } = usePagerExtended(resourceType, searchParams); + const defaultPageSize = defaultSearchParams._count; - const handleTableChange = async (pagination: TablePaginationConfig) => { - // Handle pagination only - if (typeof pagination.current !== 'number') { - return; - } + const [pageSize, setPageSize] = useState(typeof defaultPageSize === 'number' ? defaultPageSize : 10); - pagerHandleTableChange(pagination); - setSelectedRowKeys([]); - }; + const [resourceResponse, pagerManager] = usePager({ + resourceType, + requestService: service, + resourcesOnPage: pageSize, + initialSearchParams: searchParams, + }); + + const total = isSuccess(resourceResponse) ? resourceResponse.data.total : 0; + + const pagination = useMemo( + () => ({ + ...pagerManager, + updatePageSize: (pageSize: number) => { + pagerManager.reload(); + setPageSize(pageSize); + }, + pageSize, + total, + }), + [pagerManager, pageSize, total, setPageSize], + ); useEffect(() => { setSelectedRowKeys([]); @@ -82,7 +90,6 @@ export function useResourceListPage( return { pagination, recordResponse, - handleTableChange, selectedRowKeys, setSelectedRowKeys, selectedResourcesBundle, diff --git a/src/uberComponents/ResourceListPage/index.tsx b/src/uberComponents/ResourceListPage/index.tsx index a1dc92c8..4866435b 100644 --- a/src/uberComponents/ResourceListPage/index.tsx +++ b/src/uberComponents/ResourceListPage/index.tsx @@ -1,13 +1,14 @@ import { Trans } from '@lingui/macro'; import { Empty } from 'antd'; -import { ColumnsType } from 'antd/lib/table'; +import { ColumnsType, TablePaginationConfig } from 'antd/lib/table'; import { Bundle, ParametersParameter, Resource } from 'fhir/r4b'; -import React, { useMemo } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { formatError, SearchParams } from '@beda.software/fhir-react'; import { isFailure, isLoading, isSuccess, RemoteData } from '@beda.software/remote-data'; import { PageContainer } from 'src/components/BaseLayout/PageContainer'; +import { Report } from 'src/components/Report'; import { SearchBar } from 'src/components/SearchBar'; import { useSearchBar } from 'src/components/SearchBar/hooks'; import { isTableFilter } from 'src/components/SearchBar/utils'; @@ -28,11 +29,10 @@ import { isCustomAction, } from './actions'; export { navigationAction, customAction, questionnaireAction } from './actions'; +import { BatchActions } from './BatchActions'; import { useResourceListPage } from './hooks'; -import { SearchBarColumn } from '../../components/SearchBar/types'; import { S } from './styles'; -import { Report } from 'src/components/Report'; -import { BatchActions } from './BatchActions'; +import { SearchBarColumn } from '../../components/SearchBar/types'; type RecordType = { resource: R; bundle: Bundle }; @@ -138,15 +138,26 @@ export function ResourceListPage({ [JSON.stringify(columnsFilterValues)], ); - const { - recordResponse, - reload, - pagination, - handleTableChange, - selectedRowKeys, - setSelectedRowKeys, - selectedResourcesBundle, - } = useResourceListPage(resourceType, extractPrimaryResources, columnsFilterValues, searchParams ?? {}); + const { recordResponse, reload, pagination, selectedRowKeys, setSelectedRowKeys, selectedResourcesBundle } = + useResourceListPage(resourceType, extractPrimaryResources, columnsFilterValues, searchParams ?? {}); + + const handleTableChange = useCallback( + (event: TablePaginationConfig) => { + if (typeof event.current !== 'number') { + return; + } + if (event.pageSize && event.pageSize !== pagination.pageSize) { + pagination.reload(); + pagination.updatePageSize(event.pageSize); + } else { + pagination.loadPage(event.current, { + _page: event.current, + }); + } + setSelectedRowKeys([]); + }, + [pagination], + ); // TODO: move to hooks const initialTableColumns = getTableColumns({ reload }); @@ -198,7 +209,7 @@ export function ResourceListPage({ ) : null} > - pagination={pagination} + pagination={{ total: pagination.total, pageSize: pagination.pageSize }} onChange={handleTableChange} rowSelection={batchActions.length ? { selectedRowKeys, onChange: setSelectedRowKeys } : undefined} locale={{ From 09753ee90093a4e2f83adcc3d5900e8e8e06a215 Mon Sep 17 00:00:00 2001 From: Ilya Beda Date: Wed, 26 Feb 2025 12:09:04 +1100 Subject: [PATCH 21/21] Refactor types for ResourceList Make it agnostic to antd and remove ResourceListPage specific props from a general types --- src/uberComponents/ResourceListPage/index.tsx | 76 +----------------- src/uberComponents/ResourceListPage/types.ts | 77 +++++++++++++++++++ 2 files changed, 81 insertions(+), 72 deletions(-) create mode 100644 src/uberComponents/ResourceListPage/types.ts diff --git a/src/uberComponents/ResourceListPage/index.tsx b/src/uberComponents/ResourceListPage/index.tsx index 4866435b..e59b99ef 100644 --- a/src/uberComponents/ResourceListPage/index.tsx +++ b/src/uberComponents/ResourceListPage/index.tsx @@ -4,7 +4,7 @@ import { ColumnsType, TablePaginationConfig } from 'antd/lib/table'; import { Bundle, ParametersParameter, Resource } from 'fhir/r4b'; import React, { useCallback, useMemo } from 'react'; -import { formatError, SearchParams } from '@beda.software/fhir-react'; +import { formatError } from '@beda.software/fhir-react'; import { isFailure, isLoading, isSuccess, RemoteData } from '@beda.software/remote-data'; import { PageContainer } from 'src/components/BaseLayout/PageContainer'; @@ -32,87 +32,19 @@ export { navigationAction, customAction, questionnaireAction } from './actions'; import { BatchActions } from './BatchActions'; import { useResourceListPage } from './hooks'; import { S } from './styles'; -import { SearchBarColumn } from '../../components/SearchBar/types'; +import { ResourceListProps, ReportColumn, TableManager } from './types'; type RecordType = { resource: R; bundle: Bundle }; -interface TableManager { - reload: () => void; -} - -interface ReportColumn { - title: React.ReactNode; - value: React.ReactNode; -} - -export interface ResourceListPageProps { +type ResourceListPageProps = ResourceListProps & { /* Page header title (for example, Organizations) */ headerTitle: string; /* Page content max width */ maxWidth?: number | string; - - /* Primary resource type (for example, Organization) */ - resourceType: R['resourceType']; - - /** - * Custom primary resources extractor, might be used when the same resource type included - * e.g. Organizations included via part-of - * - * Default - extract all resources matching `resourceType` - */ - extractPrimaryResources?: (bundle: Bundle) => R[]; - - /* Default search params */ - searchParams?: SearchParams; - - /* Filter that are displayed in the search bar and inside table columns */ - getFilters?: () => SearchBarColumn[]; - /* Table columns without action column - action column is generated based on `getRecordActions` */ getTableColumns: (manager: TableManager) => ColumnsType>; - - /** - * Record actions list that is displayed in the table per record - * (for example, edit organization) - */ - getRecordActions?: ( - record: RecordType, - manager: TableManager, - ) => Array; - - /** - * Header actions (for example, new organization) - * - * NOTE: Theoretically getHeaderActions can accept all resources Bundle - */ - getHeaderActions?: () => Array; - - /** - * Batch actions that are available when rows are selected - * (for example, delete multiple organizations) - * - * NOTE: Theoretically getHeaderActions can accept selected resources Bundle - */ - getBatchActions?: () => Array; - - /** - * Default launch context that will be added to all questionnaires - */ - defaultLaunchContext?: ParametersParameter[]; - - /** - * EXPERIMENTAL FEATURE. The interface might be changed - * TODO: https://github.com/beda-software/fhir-emr/issues/414 - */ - // loadReportBundle?: (searchParams: SearchParams) => Promise> - - /** - * EXPERIMENTAL FEATURE. The interface might be changed - * TODO: https://github.com/beda-software/fhir-emr/issues/414 - */ - getReportColumns?: (bundle: Bundle, reportBundle?: Bundle) => Array; -} +}; export function ResourceListPage({ headerTitle: title, diff --git a/src/uberComponents/ResourceListPage/types.ts b/src/uberComponents/ResourceListPage/types.ts new file mode 100644 index 00000000..fb467f8d --- /dev/null +++ b/src/uberComponents/ResourceListPage/types.ts @@ -0,0 +1,77 @@ +import { Bundle, ParametersParameter, Resource } from 'fhir/r4b'; + +import { SearchParams } from '@beda.software/fhir-react'; + +import { NavigationActionType, CustomActionType, QuestionnaireActionType } from './actions'; +import { SearchBarColumn } from '../../components/SearchBar/types'; + +export type RecordType = { resource: R; bundle: Bundle }; + +export interface ReportColumn { + title: React.ReactNode; + value: React.ReactNode; +} + +export interface TableManager { + reload: () => void; +} + +export interface ResourceListProps { + /* Primary resource type (for example, Organization) */ + resourceType: R['resourceType']; + + /** + * Custom primary resources extractor, might be used when the same resource type included + * e.g. Organizations included via part-of + * + * Default - extract all resources matching `resourceType` + */ + extractPrimaryResources?: (bundle: Bundle) => R[]; + + /* Default search params */ + searchParams?: SearchParams; + + /* Filter that are displayed in the search bar and inside table columns */ + getFilters?: () => SearchBarColumn[]; + + /** + * Record actions list that is displayed in the table per record + * (for example, edit organization) + */ + getRecordActions?: ( + record: RecordType, + manager: TableManager, + ) => Array; + + /** + * Header actions (for example, new organization) + * + * NOTE: Theoretically getHeaderActions can accept all resources Bundle + */ + getHeaderActions?: () => Array; + + /** + * Batch actions that are available when rows are selected + * (for example, delete multiple organizations) + * + * NOTE: Theoretically getHeaderActions can accept selected resources Bundle + */ + getBatchActions?: () => Array; + + /** + * Default launch context that will be added to all questionnaires + */ + defaultLaunchContext?: ParametersParameter[]; + + /** + * EXPERIMENTAL FEATURE. The interface might be changed + * TODO: https://github.com/beda-software/fhir-emr/issues/414 + */ + // loadReportBundle?: (searchParams: SearchParams) => Promise> + + /** + * EXPERIMENTAL FEATURE. The interface might be changed + * TODO: https://github.com/beda-software/fhir-emr/issues/414 + */ + getReportColumns?: (bundle: Bundle, reportBundle?: Bundle) => Array; +}