diff --git a/.gitignore b/.gitignore index 59b26cb1..78bdf248 100644 --- a/.gitignore +++ b/.gitignore @@ -79,6 +79,7 @@ dist/ .editorconfig .idea +.vscode .turbo /test-results/ /playwright-report/ diff --git a/jest.config.js b/jest.config.js index d6a382e5..3c845807 100644 --- a/jest.config.js +++ b/jest.config.js @@ -15,7 +15,7 @@ module.exports = { '^dexie$': '/node_modules/dexie', '^react-i18next$': '/__mocks__/react-i18next.js', }, - setupFilesAfterEnv: ['/src/tools/setup-tests.ts'], + setupFilesAfterEnv: ['/tools/setup-tests.ts'], testEnvironment: 'jsdom', testPathIgnorePatterns: ['/e2e'], }; diff --git a/package.json b/package.json index 8f38d098..6044d0b3 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "verify": "turbo run lint typescript coverage --color", "coverage": "yarn test --coverage --passWithNoTests", "postinstall": "husky install", - "extract-translations": "i18next 'src/**/*.component.tsx' 'src/**/*.modal.tsx' --config ./i18next-parser.config.js", + "extract-translations": "i18next 'src/**/*.component.tsx' 'src/**/*.modal.tsx' --config ./tools/i18next-parser.config.js", "ci:bump-form-engine-lib": "yarn up @openmrs/esm-form-engine-lib@next" }, "files": [ diff --git a/src/components/action-buttons/action-buttons.component.tsx b/src/components/action-buttons/action-buttons.component.tsx index c6bec954..c759afde 100644 --- a/src/components/action-buttons/action-buttons.component.tsx +++ b/src/components/action-buttons/action-buttons.component.tsx @@ -1,16 +1,15 @@ import React, { useCallback, useState } from 'react'; import { Button, InlineLoading } from '@carbon/react'; import { useParams } from 'react-router-dom'; +import { showModal, showSnackbar, useConfig } from '@openmrs/esm-framework'; +import SaveFormModal from '../interactive-builder/modals/save-form/save-form.modal'; +import { handleFormValidation } from '../../resources/form-validator.resource'; +import { publishForm, unpublishForm } from '../../resources/forms.resource'; +import { useForm } from '@hooks/useForm'; import type { IMarker } from 'react-ace'; import type { TFunction } from 'react-i18next'; -import { showModal, showSnackbar, useConfig } from '@openmrs/esm-framework'; - -import { handleFormValidation } from '../../form-validator.resource'; -import { publishForm, unpublishForm } from '../../forms.resource'; -import { useForm } from '../../hooks/useForm'; -import SaveFormModal from '../modals/save-form.modal'; import type { ConfigObject } from '../../config-schema'; -import type { Schema } from '../../types'; +import type { Schema } from '@types'; import styles from './action-buttons.scss'; interface ActionButtonsProps { diff --git a/src/components/audit-details/audit-details.component.tsx b/src/components/audit-details/audit-details.component.tsx index 4dc4acc8..238af341 100644 --- a/src/components/audit-details/audit-details.component.tsx +++ b/src/components/audit-details/audit-details.component.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import { formatDatetime, parseDate } from '@openmrs/esm-framework'; import { StructuredListWrapper, StructuredListRow, StructuredListCell, StructuredListBody } from '@carbon/react'; -import type { EncounterType } from '../../types'; +import type { EncounterType } from '@types'; interface AuditDetailsProps { form: FormGroupData; diff --git a/src/components/dashboard/dashboard.component.tsx b/src/components/dashboard/dashboard.component.tsx index a0c95519..4149d46d 100644 --- a/src/components/dashboard/dashboard.component.tsx +++ b/src/components/dashboard/dashboard.component.tsx @@ -34,15 +34,15 @@ import { useLayoutType, usePagination, } from '@openmrs/esm-framework'; -import type { ConfigObject } from '../../config-schema'; -import type { Form as TypedForm } from '../../types'; -import { deleteForm } from '../../forms.resource'; -import { FormBuilderPagination } from '../pagination'; -import { useClobdata } from '../../hooks/useClobdata'; -import { useForms } from '../../hooks/useForms'; import EmptyState from '../empty-state/empty-state.component'; import ErrorState from '../error-state/error-state.component'; import Header from '../header/header.component'; +import { deleteForm } from '@resources/forms.resource'; +import { FormBuilderPagination } from '../pagination'; +import { useClobdata } from '@hooks/useClobdata'; +import { useForms } from '../../hooks/useForms'; +import type { ConfigObject } from '../../config-schema'; +import type { Form as TypedForm } from '@types'; import styles from './dashboard.scss'; type Mutator = KeyedMutator<{ diff --git a/src/components/dashboard/dashboard.test.tsx b/src/components/dashboard/dashboard.test.tsx index f6594120..b3ad9d8e 100644 --- a/src/components/dashboard/dashboard.test.tsx +++ b/src/components/dashboard/dashboard.test.tsx @@ -2,9 +2,9 @@ import React from 'react'; import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { type FetchResponse, navigate, openmrsFetch, showModal } from '@openmrs/esm-framework'; -import { renderWithSwr, waitForLoadingToFinish } from '../../tools/test-helpers'; -import { deleteForm } from '../../forms.resource'; import Dashboard from './dashboard.component'; +import { renderWithSwr, waitForLoadingToFinish } from '@tools/test-helpers'; +import { deleteForm } from '@resources/forms.resource'; type OpenmrsFetchResponse = Promise< FetchResponse<{ @@ -38,7 +38,7 @@ const formsResponse = [ }, ]; -jest.mock('../../forms.resource', () => ({ +jest.mock('@resources/forms.resource', () => ({ deleteForm: jest.fn(), })); diff --git a/src/components/form-editor/form-editor.component.tsx b/src/components/form-editor/form-editor.component.tsx index 90162c13..1813c6b4 100644 --- a/src/components/form-editor/form-editor.component.tsx +++ b/src/components/form-editor/form-editor.component.tsx @@ -19,13 +19,6 @@ import { ArrowLeft, Maximize, Minimize, Download } from '@carbon/react/icons'; import { useParams } from 'react-router-dom'; import { type TFunction, useTranslation } from 'react-i18next'; import { ConfigurableLink, showModal, useConfig } from '@openmrs/esm-framework'; -import type { IMarker } from 'react-ace'; -import type { FormSchema } from '@openmrs/esm-form-engine-lib'; -import type { Schema } from '../../types'; -import { useClobdata } from '../../hooks/useClobdata'; -import { useForm } from '../../hooks/useForm'; -import { handleFormValidation } from '../../form-validator.resource'; -import { type ConfigObject } from '../../config-schema'; import ActionButtons from '../action-buttons/action-buttons.component'; import AuditDetails from '../audit-details/audit-details.component'; import FormRenderer from '../form-renderer/form-renderer.component'; @@ -33,6 +26,13 @@ import Header from '../header/header.component'; import InteractiveBuilder from '../interactive-builder/interactive-builder.component'; import SchemaEditor from '../schema-editor/schema-editor.component'; import ValidationMessage from '../validation-info/validation-info.component'; +import { handleFormValidation } from '@resources/form-validator.resource'; +import { useClobdata } from '@hooks/useClobdata'; +import { useForm } from '@hooks/useForm'; +import type { IMarker } from 'react-ace'; +import type { FormSchema } from '@openmrs/esm-form-engine-lib'; +import type { Schema } from '@types'; +import type { ConfigObject } from '../../config-schema'; import styles from './form-editor.scss'; interface ErrorProps { diff --git a/src/components/form-editor/restore-draft-schema.modal.tsx b/src/components/form-editor/restore-draft-schema.modal.tsx index 10b861b4..f4d5eff2 100644 --- a/src/components/form-editor/restore-draft-schema.modal.tsx +++ b/src/components/form-editor/restore-draft-schema.modal.tsx @@ -1,7 +1,7 @@ import React, { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { Button, Form, ModalBody, ModalHeader, ModalFooter } from '@carbon/react'; -import { type Schema } from '../../types'; +import { type Schema } from '@types'; import styles from '../modals.scss'; interface RestoreDraftSchemaModalProps { diff --git a/src/components/interactive-builder/draggable-question.component.tsx b/src/components/interactive-builder/draggable/draggable-question.component.tsx similarity index 98% rename from src/components/interactive-builder/draggable-question.component.tsx rename to src/components/interactive-builder/draggable/draggable-question.component.tsx index 7ee11c0e..33e75f30 100644 --- a/src/components/interactive-builder/draggable-question.component.tsx +++ b/src/components/interactive-builder/draggable/draggable-question.component.tsx @@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next'; import { CopyButton, IconButton } from '@carbon/react'; import { Draggable, Edit, TrashCan } from '@carbon/react/icons'; import { showModal } from '@openmrs/esm-framework'; -import type { Question, Schema } from '../../types'; +import type { Question, Schema } from '@types'; import styles from './draggable-question.scss'; interface DraggableQuestionProps { diff --git a/src/components/interactive-builder/draggable-question.scss b/src/components/interactive-builder/draggable/draggable-question.scss similarity index 92% rename from src/components/interactive-builder/draggable-question.scss rename to src/components/interactive-builder/draggable/draggable-question.scss index 8431925f..3676a326 100644 --- a/src/components/interactive-builder/draggable-question.scss +++ b/src/components/interactive-builder/draggable/draggable-question.scss @@ -1,6 +1,6 @@ @use '@carbon/colors'; @use '@carbon/layout'; -@use "@carbon/type"; +@use '@carbon/type'; .buttonsContainer { display: flex; @@ -28,7 +28,7 @@ @extend .dragContainer; box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25); background-color: rgba(255, 255, 255, 0.552); - transform: scale(.75); + transform: scale(0.75); } .dragIcon { diff --git a/src/components/interactive-builder/droppable-container.component.tsx b/src/components/interactive-builder/droppable/droppable-container.component.tsx similarity index 100% rename from src/components/interactive-builder/droppable-container.component.tsx rename to src/components/interactive-builder/droppable/droppable-container.component.tsx diff --git a/src/components/interactive-builder/droppable-container.scss b/src/components/interactive-builder/droppable/droppable-container.scss similarity index 100% rename from src/components/interactive-builder/droppable-container.scss rename to src/components/interactive-builder/droppable/droppable-container.scss diff --git a/src/components/interactive-builder/editable-value.component.tsx b/src/components/interactive-builder/editable/editable-value.component.tsx similarity index 94% rename from src/components/interactive-builder/editable-value.component.tsx rename to src/components/interactive-builder/editable/editable-value.component.tsx index e44036ce..ba63d46f 100644 --- a/src/components/interactive-builder/editable-value.component.tsx +++ b/src/components/interactive-builder/editable/editable-value.component.tsx @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { IconButton } from '@carbon/react'; import { Edit } from '@carbon/react/icons'; -import ValueEditor from './value-editor.component'; +import ValueEditor from '../value-editor/value-editor.component'; import styles from './editable-value.scss'; interface EditableValueProps { diff --git a/src/components/interactive-builder/editable-value.scss b/src/components/interactive-builder/editable/editable-value.scss similarity index 89% rename from src/components/interactive-builder/editable-value.scss rename to src/components/interactive-builder/editable/editable-value.scss index 02eeac87..a3e11465 100644 --- a/src/components/interactive-builder/editable-value.scss +++ b/src/components/interactive-builder/editable/editable-value.scss @@ -1,4 +1,4 @@ -@use "@carbon/type"; +@use '@carbon/type'; .schemaLabel { @include type.type-style('heading-03'); @@ -9,7 +9,7 @@ margin: 0.5rem 0rem; &:after { - content: ""; + content: ''; display: block; width: 2rem; padding-top: 0.188rem; @@ -19,4 +19,4 @@ .sectionLabel { @include type.type-style('heading-02'); -} \ No newline at end of file +} diff --git a/src/components/interactive-builder/interactive-builder.component.tsx b/src/components/interactive-builder/interactive-builder.component.tsx index 5ddd2210..441f672f 100644 --- a/src/components/interactive-builder/interactive-builder.component.tsx +++ b/src/components/interactive-builder/interactive-builder.component.tsx @@ -1,16 +1,16 @@ import React, { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; -import type { DragEndEvent } from '@dnd-kit/core'; import { DndContext, KeyboardSensor, MouseSensor, closestCorners, useSensor, useSensors } from '@dnd-kit/core'; import { Accordion, AccordionItem, Button, IconButton, InlineLoading } from '@carbon/react'; import { Add, TrashCan } from '@carbon/react/icons'; import { useParams } from 'react-router-dom'; import { showModal, showSnackbar } from '@openmrs/esm-framework'; +import DraggableQuestion from './draggable/draggable-question.component'; +import Droppable from './droppable/droppable-container.component'; +import EditableValue from './editable/editable-value.component'; +import type { DragEndEvent } from '@dnd-kit/core'; import type { FormSchema } from '@openmrs/esm-form-engine-lib'; -import type { Schema, Question } from '../../types'; -import DraggableQuestion from './draggable-question.component'; -import Droppable from './droppable-container.component'; -import EditableValue from './editable-value.component'; +import type { Schema, Question } from '@types'; import styles from './interactive-builder.scss'; interface ValidationError { diff --git a/src/components/interactive-builder/delete-page.modal.tsx b/src/components/interactive-builder/modals/delete-page/delete-page.modal.tsx similarity index 97% rename from src/components/interactive-builder/delete-page.modal.tsx rename to src/components/interactive-builder/modals/delete-page/delete-page.modal.tsx index 8871404f..cee0eed6 100644 --- a/src/components/interactive-builder/delete-page.modal.tsx +++ b/src/components/interactive-builder/modals/delete-page/delete-page.modal.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import { Button, ModalBody, ModalFooter, ModalHeader } from '@carbon/react'; import { showSnackbar } from '@openmrs/esm-framework'; -import type { Schema } from '../../types'; +import type { Schema } from '@types'; import styles from '../modals.scss'; interface DeletePageModalProps { diff --git a/src/components/interactive-builder/delete-question.modal.tsx b/src/components/interactive-builder/modals/delete-question/delete-question.modal.tsx similarity index 98% rename from src/components/interactive-builder/delete-question.modal.tsx rename to src/components/interactive-builder/modals/delete-question/delete-question.modal.tsx index 9e0e97b5..741a4e7d 100644 --- a/src/components/interactive-builder/delete-question.modal.tsx +++ b/src/components/interactive-builder/modals/delete-question/delete-question.modal.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import { Button, ModalBody, ModalFooter, ModalHeader } from '@carbon/react'; import { showSnackbar } from '@openmrs/esm-framework'; -import type { Question, Schema } from '../../types'; +import type { Question, Schema } from '@types'; import styles from '../modals.scss'; interface DeleteQuestionModal { diff --git a/src/components/interactive-builder/delete-section.modal.tsx b/src/components/interactive-builder/modals/delete-section/delete-section.modal.tsx similarity index 98% rename from src/components/interactive-builder/delete-section.modal.tsx rename to src/components/interactive-builder/modals/delete-section/delete-section.modal.tsx index 56fdae0d..7ddacda7 100644 --- a/src/components/interactive-builder/delete-section.modal.tsx +++ b/src/components/interactive-builder/modals/delete-section/delete-section.modal.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import { Button, ModalBody, ModalFooter, ModalHeader } from '@carbon/react'; import { showSnackbar } from '@openmrs/esm-framework'; -import type { Schema } from '../../types'; +import type { Schema } from '@types'; import styles from '../modals.scss'; interface DeleteSectionModal { diff --git a/src/components/modals.scss b/src/components/interactive-builder/modals/modals.scss similarity index 100% rename from src/components/modals.scss rename to src/components/interactive-builder/modals/modals.scss diff --git a/src/components/interactive-builder/new-form.modal.tsx b/src/components/interactive-builder/modals/new-form/new-form.modal.tsx similarity index 98% rename from src/components/interactive-builder/new-form.modal.tsx rename to src/components/interactive-builder/modals/new-form/new-form.modal.tsx index dce730a2..e6a3c4e2 100644 --- a/src/components/interactive-builder/new-form.modal.tsx +++ b/src/components/interactive-builder/modals/new-form/new-form.modal.tsx @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Button, Form, FormGroup, ModalBody, ModalFooter, ModalHeader, Stack, TextInput } from '@carbon/react'; import { showSnackbar } from '@openmrs/esm-framework'; -import type { Schema } from '../../types'; +import type { Schema } from '@types'; import styles from '../modals.scss'; interface NewFormModalProps { diff --git a/src/components/interactive-builder/page.modal.tsx b/src/components/interactive-builder/modals/new-page/page.modal.tsx similarity index 98% rename from src/components/interactive-builder/page.modal.tsx rename to src/components/interactive-builder/modals/new-page/page.modal.tsx index 2027a848..6353786e 100644 --- a/src/components/interactive-builder/page.modal.tsx +++ b/src/components/interactive-builder/modals/new-page/page.modal.tsx @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Button, Form, FormGroup, ModalBody, ModalFooter, ModalHeader, TextInput } from '@carbon/react'; import { showSnackbar } from '@openmrs/esm-framework'; -import type { Schema } from '../../types'; +import type { Schema } from '@types'; import styles from '../modals.scss'; interface PageModalProps { diff --git a/src/components/interactive-builder/section.modal.tsx b/src/components/interactive-builder/modals/new-section/section.modal.tsx similarity index 98% rename from src/components/interactive-builder/section.modal.tsx rename to src/components/interactive-builder/modals/new-section/section.modal.tsx index 18e4ae04..1fcd95e3 100644 --- a/src/components/interactive-builder/section.modal.tsx +++ b/src/components/interactive-builder/modals/new-section/section.modal.tsx @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Button, Form, FormGroup, ModalBody, ModalFooter, ModalHeader, TextInput } from '@carbon/react'; import { showSnackbar } from '@openmrs/esm-framework'; -import type { Schema } from '../../types'; +import type { Schema } from '@types'; import styles from '../modals.scss'; interface SectionModalProps { diff --git a/src/components/interactive-builder/question-form/question-types/inputs/index.tsx b/src/components/interactive-builder/modals/question/question-form/question-types/inputs/index.tsx similarity index 100% rename from src/components/interactive-builder/question-form/question-types/inputs/index.tsx rename to src/components/interactive-builder/modals/question/question-form/question-types/inputs/index.tsx diff --git a/src/components/interactive-builder/question-form/question-types/inputs/obs/obs-type-question.component.tsx b/src/components/interactive-builder/modals/question/question-form/question-types/inputs/obs/obs-type-question.component.tsx similarity index 97% rename from src/components/interactive-builder/question-form/question-types/inputs/obs/obs-type-question.component.tsx rename to src/components/interactive-builder/modals/question/question-form/question-types/inputs/obs/obs-type-question.component.tsx index d774072a..abdc5e29 100644 --- a/src/components/interactive-builder/question-form/question-types/inputs/obs/obs-type-question.component.tsx +++ b/src/components/interactive-builder/modals/question/question-form/question-types/inputs/obs/obs-type-question.component.tsx @@ -14,9 +14,9 @@ import { import { useTranslation } from 'react-i18next'; import { useDebounce } from '@openmrs/esm-framework'; import { ArrowUpRight } from '@carbon/react/icons'; -import { useConceptLookup } from '../../../../../../hooks/useConceptLookup'; -import { useConceptId } from '../../../../../../hooks/useConceptName'; -import type { Concept, ConceptMapping, DatePickerType, ComponentProps } from '../../../../../../types'; +import { useConceptLookup } from '../../../../../../../../hooks/useConceptLookup'; +import { useConceptId } from '../../../../../../../../hooks/useConceptId'; +import type { Concept, ConceptMapping, ComponentProps, DatePickerType } from '../../../../../../../../types'; import styles from './obs-type-question.scss'; interface AnswerItem { diff --git a/src/components/interactive-builder/question-form/question-types/inputs/obs/obs-type-question.scss b/src/components/interactive-builder/modals/question/question-form/question-types/inputs/obs/obs-type-question.scss similarity index 100% rename from src/components/interactive-builder/question-form/question-types/inputs/obs/obs-type-question.scss rename to src/components/interactive-builder/modals/question/question-form/question-types/inputs/obs/obs-type-question.scss diff --git a/src/components/interactive-builder/question-form/question-types/inputs/patient-identifier/patient-identifier-type-question.component.tsx b/src/components/interactive-builder/modals/question/question-form/question-types/inputs/patient-identifier/patient-identifier-type-question.component.tsx similarity index 86% rename from src/components/interactive-builder/question-form/question-types/inputs/patient-identifier/patient-identifier-type-question.component.tsx rename to src/components/interactive-builder/modals/question/question-form/question-types/inputs/patient-identifier/patient-identifier-type-question.component.tsx index dd093743..8a648be6 100644 --- a/src/components/interactive-builder/question-form/question-types/inputs/patient-identifier/patient-identifier-type-question.component.tsx +++ b/src/components/interactive-builder/modals/question/question-form/question-types/inputs/patient-identifier/patient-identifier-type-question.component.tsx @@ -1,9 +1,9 @@ -import React, { useState } from 'react'; +import React, { useState, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { FormLabel, InlineNotification, ComboBox, InlineLoading } from '@carbon/react'; -import { usePatientIdentifierTypes } from '../../../../../../hooks/usePatientIdentifierTypes'; -import { usePatientIdentifierName } from '../../../../../../hooks/usePatientIdentifierName'; -import type { ComponentProps, PatientIdentifierType } from '../../../../../../types'; +import { usePatientIdentifierTypes } from '@hooks/usePatientIdentifierTypes'; +import { usePatientIdentifierName } from '@hooks/usePatientIdentifierName'; +import type { ComponentProps, PatientIdentifierType } from '@types'; import styles from './patient-identifier-type-question.scss'; const PatientIdentifierTypeQuestion: React.FC = ({ formField, setFormField }) => { @@ -31,6 +31,8 @@ const PatientIdentifierTypeQuestion: React.FC = ({ formField, se }); }; + const convertItemsToString = useCallback((item: PatientIdentifierType) => item?.display ?? '', []); + return (
@@ -55,7 +57,7 @@ const PatientIdentifierTypeQuestion: React.FC = ({ formField, se )} id="patientIdentifierTypeLookup" items={patientIdentifierTypes} - itemToString={(item: PatientIdentifierType) => item?.display} + itemToString={convertItemsToString} onChange={handlePatientIdentifierTypeChange} placeholder={t('choosePatientIdentifierType', 'Choose a patient identifier type')} selectedItem={selectedPatientIdetifierType} diff --git a/src/components/interactive-builder/question-form/question-types/inputs/patient-identifier/patient-identifier-type-question.scss b/src/components/interactive-builder/modals/question/question-form/question-types/inputs/patient-identifier/patient-identifier-type-question.scss similarity index 100% rename from src/components/interactive-builder/question-form/question-types/inputs/patient-identifier/patient-identifier-type-question.scss rename to src/components/interactive-builder/modals/question/question-form/question-types/inputs/patient-identifier/patient-identifier-type-question.scss diff --git a/src/components/interactive-builder/question-form/question-types/inputs/program-state/program-state-type-question.component.tsx b/src/components/interactive-builder/modals/question/question-form/question-types/inputs/program-state/program-state-type-question.component.tsx similarity index 96% rename from src/components/interactive-builder/question-form/question-types/inputs/program-state/program-state-type-question.component.tsx rename to src/components/interactive-builder/modals/question/question-form/question-types/inputs/program-state/program-state-type-question.component.tsx index c6714021..0a024e54 100644 --- a/src/components/interactive-builder/question-form/question-types/inputs/program-state/program-state-type-question.component.tsx +++ b/src/components/interactive-builder/modals/question/question-form/question-types/inputs/program-state/program-state-type-question.component.tsx @@ -1,8 +1,8 @@ import React, { useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { SelectSkeleton, Stack, ComboBox, InlineNotification, MultiSelect, Tag } from '@carbon/react'; -import { usePrograms, useProgramWorkStates } from '../../../../../../hooks/useProgramStates'; -import type { ProgramWorkflow, Program, ComponentProps } from '../../../../../../types'; +import { usePrograms, useProgramWorkStates } from '@hooks/useProgramStates'; +import type { ProgramWorkflow, Program, ComponentProps } from '@types'; import type { ProgramState } from '@openmrs/esm-form-engine-lib'; import styles from './program-state-type-question.scss'; diff --git a/src/components/interactive-builder/question-form/question-types/inputs/program-state/program-state-type-question.scss b/src/components/interactive-builder/modals/question/question-form/question-types/inputs/program-state/program-state-type-question.scss similarity index 100% rename from src/components/interactive-builder/question-form/question-types/inputs/program-state/program-state-type-question.scss rename to src/components/interactive-builder/modals/question/question-form/question-types/inputs/program-state/program-state-type-question.scss diff --git a/src/components/interactive-builder/question-form/question-types/question-type.component.tsx b/src/components/interactive-builder/modals/question/question-form/question-types/question-type.component.tsx similarity index 90% rename from src/components/interactive-builder/question-form/question-types/question-type.component.tsx rename to src/components/interactive-builder/modals/question/question-form/question-types/question-type.component.tsx index 476a9a0e..18e72a9a 100644 --- a/src/components/interactive-builder/question-form/question-types/question-type.component.tsx +++ b/src/components/interactive-builder/modals/question/question-form/question-types/question-type.component.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { ObsTypeQuestion, ProgramStateTypeQuestion, PatientIdentifierTypeQuestion } from './inputs'; -import type { QuestionType, ComponentProps } from '../../../../types'; +import type { QuestionType, ComponentProps } from '@types'; const componentMap: Partial>> = { obs: ObsTypeQuestion, diff --git a/src/components/interactive-builder/question-form/question/question.component.tsx b/src/components/interactive-builder/modals/question/question-form/question/question.component.tsx similarity index 98% rename from src/components/interactive-builder/question-form/question/question.component.tsx rename to src/components/interactive-builder/modals/question/question-form/question/question.component.tsx index b3608303..102a9e7d 100644 --- a/src/components/interactive-builder/question-form/question/question.component.tsx +++ b/src/components/interactive-builder/modals/question/question-form/question/question.component.tsx @@ -5,8 +5,8 @@ import RenderTypeComponent from '../rendering-types/rendering-type.component'; import QuestionTypeComponent from '../question-types/question-type.component'; import RequiredLabel from '../required-label/required-label.component'; import type { FormField, RenderType } from '@openmrs/esm-form-engine-lib'; -import type { ComponentProps } from '../../../../types'; -import { questionTypes, renderTypeOptions, renderingTypes } from '../../../../constants'; +import type { ComponentProps } from '@types'; +import { questionTypes, renderTypeOptions, renderingTypes } from '@constants'; import styles from './question.scss'; interface QuestionProps extends ComponentProps { diff --git a/src/components/interactive-builder/question-form/question/question.scss b/src/components/interactive-builder/modals/question/question-form/question/question.scss similarity index 100% rename from src/components/interactive-builder/question-form/question/question.scss rename to src/components/interactive-builder/modals/question/question-form/question/question.scss diff --git a/src/components/interactive-builder/question-form/rendering-types/inputs/date/date.component.tsx b/src/components/interactive-builder/modals/question/question-form/rendering-types/inputs/date/date.component.tsx similarity index 94% rename from src/components/interactive-builder/question-form/rendering-types/inputs/date/date.component.tsx rename to src/components/interactive-builder/modals/question/question-form/rendering-types/inputs/date/date.component.tsx index 272a9247..9cc4beda 100644 --- a/src/components/interactive-builder/question-form/rendering-types/inputs/date/date.component.tsx +++ b/src/components/interactive-builder/modals/question/question-form/rendering-types/inputs/date/date.component.tsx @@ -1,7 +1,7 @@ import React, { useCallback } from 'react'; import { RadioButtonGroup, RadioButton } from '@carbon/react'; import { useTranslation } from 'react-i18next'; -import type { DatePickerTypeOption, ComponentProps } from '../../../../../../types'; +import type { DatePickerTypeOption, ComponentProps } from '@types'; const Date: React.FC = ({ formField, setFormField }) => { const { t } = useTranslation(); diff --git a/src/components/interactive-builder/question-form/rendering-types/inputs/index.tsx b/src/components/interactive-builder/modals/question/question-form/rendering-types/inputs/index.tsx similarity index 100% rename from src/components/interactive-builder/question-form/rendering-types/inputs/index.tsx rename to src/components/interactive-builder/modals/question/question-form/rendering-types/inputs/index.tsx diff --git a/src/components/interactive-builder/question-form/rendering-types/inputs/number/number.component.tsx b/src/components/interactive-builder/modals/question/question-form/rendering-types/inputs/number/number.component.tsx similarity index 96% rename from src/components/interactive-builder/question-form/rendering-types/inputs/number/number.component.tsx rename to src/components/interactive-builder/modals/question/question-form/rendering-types/inputs/number/number.component.tsx index eb626532..d2fc9ec1 100644 --- a/src/components/interactive-builder/question-form/rendering-types/inputs/number/number.component.tsx +++ b/src/components/interactive-builder/modals/question/question-form/rendering-types/inputs/number/number.component.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import { TextInput } from '@carbon/react'; import type { FormField } from '@openmrs/esm-form-engine-lib'; -import type { ComponentProps } from '../../../../../../types'; +import type { ComponentProps } from '@types'; const Number: React.FC = ({ formField, setFormField }) => { const { t } = useTranslation(); diff --git a/src/components/interactive-builder/question-form/rendering-types/inputs/text-area/textarea.component.tsx b/src/components/interactive-builder/modals/question/question-form/rendering-types/inputs/text-area/textarea.component.tsx similarity index 92% rename from src/components/interactive-builder/question-form/rendering-types/inputs/text-area/textarea.component.tsx rename to src/components/interactive-builder/modals/question/question-form/rendering-types/inputs/text-area/textarea.component.tsx index 53834191..60c57e0c 100644 --- a/src/components/interactive-builder/question-form/rendering-types/inputs/text-area/textarea.component.tsx +++ b/src/components/interactive-builder/modals/question/question-form/rendering-types/inputs/text-area/textarea.component.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import { NumberInput } from '@carbon/react'; import type { FormField } from '@openmrs/esm-form-engine-lib'; -import type { ComponentProps } from '../../../../../../types'; +import type { ComponentProps } from '@types'; const TextArea: React.FC = ({ formField, setFormField }) => { const { t } = useTranslation(); diff --git a/src/components/interactive-builder/question-form/rendering-types/inputs/text/text.component.tsx b/src/components/interactive-builder/modals/question/question-form/rendering-types/inputs/text/text.component.tsx similarity index 97% rename from src/components/interactive-builder/question-form/rendering-types/inputs/text/text.component.tsx rename to src/components/interactive-builder/modals/question/question-form/rendering-types/inputs/text/text.component.tsx index c5fc45d2..3ef84169 100644 --- a/src/components/interactive-builder/question-form/rendering-types/inputs/text/text.component.tsx +++ b/src/components/interactive-builder/modals/question/question-form/rendering-types/inputs/text/text.component.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import { TextInput } from '@carbon/react'; import type { FormField } from '@openmrs/esm-form-engine-lib'; -import type { ComponentProps } from '../../../../../../types'; +import type { ComponentProps } from '@types'; const Text: React.FC = ({ formField, setFormField }) => { const { t } = useTranslation(); diff --git a/src/components/interactive-builder/question-form/rendering-types/inputs/toggle/toggle.component.tsx b/src/components/interactive-builder/modals/question/question-form/rendering-types/inputs/toggle/toggle.component.tsx similarity index 96% rename from src/components/interactive-builder/question-form/rendering-types/inputs/toggle/toggle.component.tsx rename to src/components/interactive-builder/modals/question/question-form/rendering-types/inputs/toggle/toggle.component.tsx index 5bd6e067..dfec5133 100644 --- a/src/components/interactive-builder/question-form/rendering-types/inputs/toggle/toggle.component.tsx +++ b/src/components/interactive-builder/modals/question/question-form/rendering-types/inputs/toggle/toggle.component.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import { TextInput } from '@carbon/react'; import type { FormField } from '@openmrs/esm-form-engine-lib'; -import type { ComponentProps } from '../../../../../../types'; +import type { ComponentProps } from '@types'; const Toggle: React.FC = ({ formField, setFormField }) => { const { t } = useTranslation(); diff --git a/src/components/interactive-builder/question-form/rendering-types/inputs/ui-select-extended/ui-select-extended.component.tsx b/src/components/interactive-builder/modals/question/question-form/rendering-types/inputs/ui-select-extended/ui-select-extended.component.tsx similarity index 96% rename from src/components/interactive-builder/question-form/rendering-types/inputs/ui-select-extended/ui-select-extended.component.tsx rename to src/components/interactive-builder/modals/question/question-form/rendering-types/inputs/ui-select-extended/ui-select-extended.component.tsx index db59d7da..029e645a 100644 --- a/src/components/interactive-builder/question-form/rendering-types/inputs/ui-select-extended/ui-select-extended.component.tsx +++ b/src/components/interactive-builder/modals/question/question-form/rendering-types/inputs/ui-select-extended/ui-select-extended.component.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import { RadioButtonGroup, RadioButton } from '@carbon/react'; import type { FormField } from '@openmrs/esm-form-engine-lib'; -import type { ComponentProps } from '../../../../../../types'; +import type { ComponentProps } from '@types'; const UiSelectExtended: React.FC = ({ formField, setFormField }) => { const { t } = useTranslation(); diff --git a/src/components/interactive-builder/question-form/rendering-types/rendering-type.component.tsx b/src/components/interactive-builder/modals/question/question-form/rendering-types/rendering-type.component.tsx similarity index 90% rename from src/components/interactive-builder/question-form/rendering-types/rendering-type.component.tsx rename to src/components/interactive-builder/modals/question/question-form/rendering-types/rendering-type.component.tsx index 0cd57544..4cd3c54a 100644 --- a/src/components/interactive-builder/question-form/rendering-types/rendering-type.component.tsx +++ b/src/components/interactive-builder/modals/question/question-form/rendering-types/rendering-type.component.tsx @@ -1,8 +1,8 @@ import React from 'react'; import { Date, Number, Text, TextArea, Toggle, UiSelectExtended } from './inputs'; import type { RenderType } from '@openmrs/esm-form-engine-lib'; -import type { ComponentProps } from '../../../../types'; -import { renderTypeOptions, renderingTypes } from '../../../../constants'; +import type { ComponentProps } from '@types'; +import { renderTypeOptions, renderingTypes } from '@constants'; const componentMap: Partial>> = { number: Number, diff --git a/src/components/interactive-builder/question-form/required-label/required-label.component.tsx b/src/components/interactive-builder/modals/question/question-form/required-label/required-label.component.tsx similarity index 100% rename from src/components/interactive-builder/question-form/required-label/required-label.component.tsx rename to src/components/interactive-builder/modals/question/question-form/required-label/required-label.component.tsx diff --git a/src/components/interactive-builder/question-form/required-label/required-label.scss b/src/components/interactive-builder/modals/question/question-form/required-label/required-label.scss similarity index 100% rename from src/components/interactive-builder/question-form/required-label/required-label.scss rename to src/components/interactive-builder/modals/question/question-form/required-label/required-label.scss diff --git a/src/components/interactive-builder/question-form/question.modal.tsx b/src/components/interactive-builder/modals/question/question.modal.tsx similarity index 75% rename from src/components/interactive-builder/question-form/question.modal.tsx rename to src/components/interactive-builder/modals/question/question.modal.tsx index 70b30cd6..31a6bafe 100644 --- a/src/components/interactive-builder/question-form/question.modal.tsx +++ b/src/components/interactive-builder/modals/question/question.modal.tsx @@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'; import flattenDeep from 'lodash-es/flattenDeep'; import { ModalHeader, Form, ModalBody, FormGroup, Button, Stack, ModalFooter } from '@carbon/react'; import { showSnackbar } from '@openmrs/esm-framework'; -import Question from './question/question.component'; +import Question from './question-form/question/question.component'; import type { FormField, FormSchema } from '@openmrs/esm-form-engine-lib'; import styles from './question-modal.scss'; @@ -32,22 +32,28 @@ const QuestionModal: React.FC = ({ formFieldProp ?? { type: '', questionOptions: undefined, id: '' }, ); - const checkIfQuestionIdExists = (idToTest: string): boolean => { - if (formFieldProp) return false; - else { - const nestedIds = schema?.pages?.map((page) => { - return page?.sections?.map((section) => { - return section?.questions?.map((question) => { - return question.id; + const checkIfQuestionIdExists = useCallback( + (idToTest: string): boolean => { + if (formFieldProp) return false; + else { + const nestedIds = schema?.pages?.map((page) => { + return page?.sections?.map((section) => { + return section?.questions?.map((question) => { + question.questions?.map((nestedQuestion) => { + return nestedQuestion.id; + }); + return question.id; + }); }); }); - }); - const questionIds: Array = flattenDeep(nestedIds); - return questionIds.includes(idToTest); - } - }; + const questionIds: Array = flattenDeep(nestedIds); + return questionIds.includes(idToTest); + } + }, + [formFieldProp, schema], + ); - const addObsGroupQuestion = () => { + const addObsGroupQuestion = useCallback(() => { const emptyQuestion: FormField = { type: '', questionOptions: undefined, @@ -58,7 +64,7 @@ const QuestionModal: React.FC = ({ questions: formField.questions ? [...formField.questions, emptyQuestion] : [emptyQuestion], }; setFormField(newFormField); - }; + }, [formField, setFormField]); const saveQuestion = () => { try { @@ -97,6 +103,19 @@ const QuestionModal: React.FC = ({ [setFormField], ); + const updateObsGroupQuestion = useCallback( + (updatedObsGroupFormField: FormField) => { + const formFieldCopy = { ...formField }; + if (formFieldCopy.questions.length === 1 && formFieldCopy.questions[0].id === '') { + formFieldCopy.questions[0] = updatedObsGroupFormField; + } else { + formFieldCopy.questions.push(updatedObsGroupFormField); + } + setFormField(formFieldCopy); + }, + [formField, setFormField], + ); + return ( <> = ({ formField.questions.map((question) => ( ))} diff --git a/src/components/interactive-builder/question-form/question-modal.scss b/src/components/interactive-builder/modals/question/question.scss similarity index 100% rename from src/components/interactive-builder/question-form/question-modal.scss rename to src/components/interactive-builder/modals/question/question.scss diff --git a/src/components/modals/save-form.modal.tsx b/src/components/interactive-builder/modals/save-form/save-form.modal.tsx similarity index 98% rename from src/components/modals/save-form.modal.tsx rename to src/components/interactive-builder/modals/save-form/save-form.modal.tsx index 2489bf11..bf2e37ad 100644 --- a/src/components/modals/save-form.modal.tsx +++ b/src/components/interactive-builder/modals/save-form/save-form.modal.tsx @@ -17,7 +17,8 @@ import { TextInput, } from '@carbon/react'; import { navigate, showSnackbar } from '@openmrs/esm-framework'; - +import { useEncounterTypes } from '@hooks/useEncounterTypes'; +import { useForm } from '@hooks/useForm'; import { deleteClobdata, deleteResource, @@ -25,10 +26,8 @@ import { saveNewForm, updateForm, uploadSchema, -} from '../../forms.resource'; -import type { EncounterType, Resource, Schema } from '../../types'; -import { useEncounterTypes } from '../../hooks/useEncounterTypes'; -import { useForm } from '../../hooks/useForm'; +} from '@resources/forms.resource'; +import type { EncounterType, Resource, Schema } from '@types'; import styles from './save-form-modal.scss'; interface FormGroupData { diff --git a/src/components/modals/save-form-modal.scss b/src/components/interactive-builder/modals/save-form/save-form.scss similarity index 100% rename from src/components/modals/save-form-modal.scss rename to src/components/interactive-builder/modals/save-form/save-form.scss diff --git a/src/components/interactive-builder/value-editor.component.tsx b/src/components/interactive-builder/value-editor/value-editor.component.tsx similarity index 100% rename from src/components/interactive-builder/value-editor.component.tsx rename to src/components/interactive-builder/value-editor/value-editor.component.tsx diff --git a/src/components/interactive-builder/value-editor.scss b/src/components/interactive-builder/value-editor/value-editor.scss similarity index 84% rename from src/components/interactive-builder/value-editor.scss rename to src/components/interactive-builder/value-editor/value-editor.scss index 48628d81..a98aca21 100644 --- a/src/components/interactive-builder/value-editor.scss +++ b/src/components/interactive-builder/value-editor/value-editor.scss @@ -5,6 +5,6 @@ margin: 1rem 0; button { - margin-left: 1rem + margin-left: 1rem; } } diff --git a/src/components/schema-editor/schema-editor.component.tsx b/src/components/schema-editor/schema-editor.component.tsx index 48effb08..9120d3ef 100644 --- a/src/components/schema-editor/schema-editor.component.tsx +++ b/src/components/schema-editor/schema-editor.component.tsx @@ -4,12 +4,11 @@ import 'ace-builds/webpack-resolver'; import { addCompleter } from 'ace-builds/src-noconflict/ext-language_tools'; import type { IMarker } from 'react-ace'; import { useTranslation } from 'react-i18next'; -import { useStandardFormSchema } from '../../hooks/useStandardFormSchema'; +import { ActionableNotification, Link } from '@carbon/react'; +import { useStandardFormSchema } from '@hooks/useStandardFormSchema'; import Ajv from 'ajv'; import debounce from 'lodash-es/debounce'; -import { ActionableNotification, Link } from '@carbon/react'; import { ChevronRight, ChevronLeft } from '@carbon/react/icons'; - import styles from './schema-editor.scss'; interface MarkerProps extends IMarker { diff --git a/src/hooks/useConceptName.ts b/src/hooks/useConceptId.ts similarity index 100% rename from src/hooks/useConceptName.ts rename to src/hooks/useConceptId.ts diff --git a/src/index.ts b/src/index.ts index c1e28b06..fa99b36e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -17,32 +17,38 @@ export const systemAdministrationFormBuilderCardLink = getAsyncLifecycle( options, ); -export const newFormModal = getAsyncLifecycle(() => import('./components/interactive-builder/new-form.modal'), options); +export const newFormModal = getAsyncLifecycle( + () => import('./components/interactive-builder/modals/new-form/new-form.modal'), + options, +); -export const newPageModal = getAsyncLifecycle(() => import('./components/interactive-builder/page.modal'), options); +export const newPageModal = getAsyncLifecycle( + () => import('./components/interactive-builder/modals/new-page/page.modal'), + options, +); export const deletePageModal = getAsyncLifecycle( - () => import('./components/interactive-builder/delete-page.modal'), + () => import('./components/interactive-builder/modals/delete-page/delete-page.modal'), options, ); export const newSectionModal = getAsyncLifecycle( - () => import('./components/interactive-builder/section.modal'), + () => import('./components/interactive-builder/modals/new-section/section.modal'), options, ); export const deleteSectionModal = getAsyncLifecycle( - () => import('./components/interactive-builder/delete-section.modal'), + () => import('./components/interactive-builder/modals/delete-section/delete-section.modal'), options, ); export const questionModal = getAsyncLifecycle( - () => import('./components/interactive-builder/question-form/question.modal'), + () => import('./components/interactive-builder/modals/question/question.modal'), options, ); export const deleteQuestionModal = getAsyncLifecycle( - () => import('./components/interactive-builder/delete-question.modal'), + () => import('./components/interactive-builder/modals/delete-question/delete-question.modal'), options, ); diff --git a/src/form-validator.resource.ts b/src/resources/form-validator.resource.ts similarity index 98% rename from src/form-validator.resource.ts rename to src/resources/form-validator.resource.ts index dab81f5f..614f3c87 100644 --- a/src/form-validator.resource.ts +++ b/src/resources/form-validator.resource.ts @@ -1,6 +1,6 @@ import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework'; -import type { Question, Schema } from './types'; -import type { ConfigObject } from './config-schema'; +import type { Question, Schema } from '../types'; +import type { ConfigObject } from '../config-schema'; interface Field { label: string; diff --git a/src/forms.resource.ts b/src/resources/forms.resource.ts similarity index 98% rename from src/forms.resource.ts rename to src/resources/forms.resource.ts index 440e18ba..52ee9767 100644 --- a/src/forms.resource.ts +++ b/src/resources/forms.resource.ts @@ -1,5 +1,5 @@ import { openmrsFetch, type FetchResponse, restBaseUrl } from '@openmrs/esm-framework'; -import type { Form, Schema } from './types'; +import type { Form, Schema } from '../types'; interface SavePayload { name: string; diff --git a/i18next-parser.config.js b/tools/i18next-parser.config.js similarity index 100% rename from i18next-parser.config.js rename to tools/i18next-parser.config.js diff --git a/src/tools/setup-tests.ts b/tools/setup-tests.ts similarity index 100% rename from src/tools/setup-tests.ts rename to tools/setup-tests.ts diff --git a/src/tools/test-helpers.tsx b/tools/test-helpers.tsx similarity index 100% rename from src/tools/test-helpers.tsx rename to tools/test-helpers.tsx diff --git a/tsconfig.json b/tsconfig.json index abe23d5d..fce99fb8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,7 +20,16 @@ "noImplicitAny": false, "resolveJsonModule": true, "skipLibCheck": true, - "target": "es2015" + "target": "es2015", + "baseUrl": ".", + "paths": { + "__mocks__": ["__mocks__"], + "@hooks/*": ["src/hooks/*"], + "@types": ["src/types"], + "@tools/*": ["tools/*"], + "@constants": ["src/constants.ts"], + "@resources/*": ["src/resources/*"] + } }, "types": ["@testing-library/jest-dom", "lodash"], }