generated from openmrs/openmrs-esm-template-app
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
(feat) O3-4002 Add implementation for configuring dashboard Encounter…
… List Table component
- Loading branch information
1 parent
3a47f77
commit 765c1ae
Showing
18 changed files
with
815 additions
and
9 deletions.
There are no files selected for viewing
165 changes: 165 additions & 0 deletions
165
src/components/interactive-builder/add-columns-modal.component.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
import React, { useState, useCallback } from 'react'; | ||
import { useTranslation } from 'react-i18next'; | ||
import { | ||
Button, | ||
Form, | ||
FormGroup, | ||
ModalBody, | ||
ModalFooter, | ||
ModalHeader, | ||
Stack, | ||
TextInput, | ||
Dropdown, | ||
RadioButton, | ||
RadioButtonGroup, | ||
} from '@carbon/react'; | ||
import { isDesktop, useLayoutType } from '@openmrs/esm-framework'; | ||
import { type Schema, type Form as FormType } from '../../types'; | ||
import styles from './modals.scss'; | ||
import { useForms } from '../../hooks/useForm'; | ||
import { useFormConcepts } from '../../hooks/useFormConcepts'; | ||
|
||
interface ConfigureDashboardModalProps { | ||
schema: Schema; | ||
onSchemaChange: (schema: Schema) => void; | ||
closeModal: () => void; | ||
slotName: string; | ||
} | ||
|
||
const ConfigureDashboardModal: React.FC<ConfigureDashboardModalProps> = ({ | ||
schema, | ||
onSchemaChange, | ||
closeModal, | ||
slotName, | ||
}) => { | ||
const { t } = useTranslation(); | ||
const desktopLayout = isDesktop(useLayoutType()); | ||
const [columnTitle, setColumnTitle] = useState(''); | ||
const [columnConcept, setColumnConcept] = useState(''); | ||
const [isColumnDate, setIsColumnDate] = useState(false); | ||
const [isColumnLink, setIsColumnLink] = useState(false); | ||
const [selectedForm, setSelectedForm] = useState<FormType>(); | ||
const [selectedFormForConcepts, setSelectedFormForConcepts] = useState<FormType>(); | ||
const { isLoadingForm, forms, formsError } = useForms(); | ||
const { isLoadingFormConcepts, formConcepts, formConceptsError } = useFormConcepts(selectedFormForConcepts); | ||
|
||
const newColumns = { | ||
id: columnTitle, | ||
title: columnTitle, | ||
concept: columnConcept, | ||
isDate: isColumnDate, | ||
isLink: isColumnLink, | ||
}; | ||
const updateSchema = () => {}; | ||
|
||
const handleCreateColumn = () => { | ||
updateSchema(); | ||
closeModal(); | ||
}; | ||
|
||
const handleConceptChange = useCallback(({ selectedItem }) => setColumnConcept(selectedItem.concept), []); | ||
const handleFormChange = useCallback(({ selectedItem }) => { | ||
setSelectedForm(selectedItem.uuid); | ||
setSelectedFormForConcepts(selectedItem); | ||
}, []); | ||
|
||
return ( | ||
<> | ||
<ModalHeader | ||
className={styles.modalHeader} | ||
closeModal={closeModal} | ||
title={t('createNewSubMenu', 'Create a new submenu')} | ||
/> | ||
<Form onSubmit={(event: React.SyntheticEvent) => event.preventDefault()}> | ||
<ModalBody> | ||
<Stack gap={5}> | ||
<FormGroup legendText={t('configureColumns', 'Configure columns')}> | ||
<Dropdown | ||
id="form" | ||
initialSelectedItem={forms[0]} | ||
label={t('selectform', 'Select form')} | ||
titleText={t('form', 'Form') + ':'} | ||
items={[...forms]} | ||
itemToString={(item) => item.display} | ||
onChange={handleFormChange} | ||
size={desktopLayout ? 'sm' : 'lg'} | ||
className={styles.label} | ||
/> | ||
<Dropdown | ||
id="form" | ||
initialSelectedItem={formConcepts[0]} | ||
label={t('selectConcept', 'Select concept')} | ||
titleText={t('concept', 'Concept') + ':'} | ||
items={[...formConcepts]} | ||
itemToString={(item) => item.label} | ||
onChange={handleConceptChange} | ||
size={desktopLayout ? 'sm' : 'lg'} | ||
className={styles.label} | ||
/> | ||
<TextInput | ||
required | ||
id="columnTitle" | ||
labelText={t('columnTitle', 'Column Title')} | ||
placeholder={t('columnTitlePlaceholder', 'e.g. Visit title')} | ||
value={columnTitle} | ||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => setColumnTitle(event.target.value)} | ||
className={styles.label} | ||
/> | ||
<RadioButtonGroup | ||
name="isDate" | ||
orientation="horizontal" | ||
legendText={t('isDate', 'Is date')} | ||
className={styles.label} | ||
onChange={(event) => setIsColumnDate(event.toString())} | ||
> | ||
<RadioButton | ||
className={styles.radioButton} | ||
id="isDateTrue" | ||
labelText={t('true', 'True')} | ||
value="true" | ||
/> | ||
<RadioButton | ||
className={styles.radioButton} | ||
id="isDateFalse" | ||
labelText={t('false', 'False')} | ||
value="false" | ||
/> | ||
</RadioButtonGroup> | ||
|
||
<RadioButtonGroup | ||
name="isLink" | ||
orientation="horizontal" | ||
legendText={t('isLink', 'Is link')} | ||
className={styles.label} | ||
onChange={(event) => setIsColumnLink(event.toString())} | ||
> | ||
<RadioButton | ||
className={styles.radioButton} | ||
id="isLinkTrue" | ||
labelText={t('true', 'True')} | ||
value="true" | ||
/> | ||
<RadioButton | ||
className={styles.radioButton} | ||
id="isLinkFalse" | ||
labelText={t('false', 'False')} | ||
value="false" | ||
/> | ||
</RadioButtonGroup> | ||
</FormGroup> | ||
</Stack> | ||
</ModalBody> | ||
</Form> | ||
<ModalFooter> | ||
<Button kind="secondary" onClick={closeModal}> | ||
{t('cancel', 'Cancel')} | ||
</Button> | ||
<Button onClick={handleCreateColumn}> | ||
<span>{t('createSubMenu', 'Create Submenu')}</span> | ||
</Button> | ||
</ModalFooter> | ||
</> | ||
); | ||
}; | ||
|
||
export default ConfigureDashboardModal; |
179 changes: 179 additions & 0 deletions
179
src/components/interactive-builder/configure-dashboard-modal.component.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
import React, { useState, useCallback } from 'react'; | ||
import { useTranslation } from 'react-i18next'; | ||
import { | ||
Button, | ||
Form, | ||
FormGroup, | ||
ModalBody, | ||
ModalFooter, | ||
ModalHeader, | ||
Stack, | ||
TextInput, | ||
Dropdown, | ||
} from '@carbon/react'; | ||
import { isDesktop, showSnackbar, useLayoutType } from '@openmrs/esm-framework'; | ||
import { type Schema, type Form as FormType } from '../../types'; | ||
import styles from './modals.scss'; | ||
import { useEncounterTypes } from '../../hooks/useEncounter'; | ||
|
||
interface ConfigureDashboardModalProps { | ||
schema: Schema; | ||
onSchemaChange: (schema: Schema) => void; | ||
closeModal: () => void; | ||
slotName: string; | ||
} | ||
|
||
const ConfigureDashboardModal: React.FC<ConfigureDashboardModalProps> = ({ | ||
schema, | ||
onSchemaChange, | ||
closeModal, | ||
slotName, | ||
}) => { | ||
const { t } = useTranslation(); | ||
const [selectedWidget, setSelectedWidget] = useState(''); | ||
const [tabName, setTabName] = useState(''); | ||
const [displayTitle, setDisplayTitle] = useState(''); | ||
const [encounterType, setEncounterType] = useState(''); | ||
const desktopLayout = isDesktop(useLayoutType()); | ||
const [selectedFormForConcepts, setSelectedFormForConcepts] = useState<FormType>(); | ||
const { isLoading, encounterTypes, encounterTypesError } = useEncounterTypes(); | ||
|
||
const availableWidgets = [ | ||
{ uuid: 'encounter-list-table-tabs', value: 'Encounter list table' }, | ||
{ uuid: 'program-summary', value: 'Encounter tile' }, | ||
]; | ||
|
||
const newExtensionSlot = { | ||
[slotName]: { | ||
add: [slotName], | ||
configure: { | ||
[slotName]: { | ||
title: tabName, | ||
slotName: slotName, | ||
isExpanded: true, | ||
tabDefinitions: [ | ||
{ | ||
tabName: tabName, | ||
headerTitle: tabName, | ||
displayText: displayTitle, | ||
encounterType: encounterType, | ||
columns: [], | ||
}, | ||
], | ||
}, | ||
}, | ||
}, | ||
}; | ||
const updateSchema = () => { | ||
try { | ||
const updatedSchema = { | ||
...schema, | ||
'@openmrs/esm-patient-chart-app': { | ||
...schema['@openmrs/esm-patient-chart-app'], | ||
extensionSlots: { | ||
...schema['@openmrs/esm-patient-chart-app'].extensionSlots, | ||
...newExtensionSlot, | ||
}, | ||
}, | ||
}; | ||
|
||
onSchemaChange(updatedSchema); | ||
|
||
// Show success notification | ||
showSnackbar({ | ||
title: t('success', 'Success!'), | ||
kind: 'success', | ||
isLowContrast: true, | ||
subtitle: t('submenuCreated', 'New submenu created'), | ||
}); | ||
} catch (error) { | ||
if (error instanceof Error) { | ||
showSnackbar({ | ||
title: t('errorCreatingSubmenu', 'Error creating submenu'), | ||
kind: 'error', | ||
subtitle: error.message, | ||
}); | ||
} | ||
} | ||
}; | ||
|
||
const handleCreateWidget = () => { | ||
updateSchema(); | ||
closeModal(); | ||
}; | ||
|
||
const handleEncounterTypeChange = useCallback(({ selectedItem }) => setEncounterType(selectedItem.uuid), []); | ||
|
||
return ( | ||
<> | ||
<ModalHeader | ||
className={styles.modalHeader} | ||
closeModal={closeModal} | ||
title={t('createNewSubMenu', 'Create a new submenu')} | ||
/> | ||
<Form onSubmit={(event: React.SyntheticEvent) => event.preventDefault()}> | ||
<ModalBody> | ||
<Stack gap={5}> | ||
<FormGroup legendText={''}> | ||
<TextInput required readOnly id="slotName" labelText={t('slotName', 'Slot name')} value={slotName} /> | ||
<Dropdown | ||
id="widget" | ||
items={[...availableWidgets]} | ||
initialSelectedItem={availableWidgets[0]} | ||
itemToString={(item) => (item ? item.value : 'Not Set')} | ||
titleText={t('selectWidget', 'Select Widget')} | ||
onChange={({ selectedItem }) => setSelectedWidget(selectedItem?.uuid)} | ||
size={desktopLayout ? 'sm' : 'lg'} | ||
className={styles.label} | ||
/> | ||
</FormGroup> | ||
|
||
{selectedWidget === 'encounter-list-table-tabs' && ( | ||
<FormGroup legendText={t('configureColumns', 'Configure columns')}> | ||
<TextInput | ||
required | ||
id="tabName" | ||
labelText={t('tabName', 'Tab name')} | ||
placeholder={t('tabNamePlaceholder', 'e.g. Clinical Visit')} | ||
value={tabName} | ||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => setTabName(event.target.value)} | ||
className={styles.label} | ||
/> | ||
<TextInput | ||
required | ||
id="displayTitle" | ||
labelText={t('displayTitle', 'Display title')} | ||
placeholder={t('displayTitlePlaceholder', 'e.g. Clinical Visit Encounters')} | ||
value={displayTitle} | ||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => setDisplayTitle(event.target.value)} | ||
className={styles.label} | ||
/> | ||
<Dropdown | ||
id="encounterType" | ||
initialSelectedItem={encounterTypes[0]} | ||
label={t('selectEncounterType', 'select encounter type')} | ||
titleText={t('encounterType', 'Encounter type') + ':'} | ||
items={[...encounterTypes]} | ||
itemToString={(item) => item.display} | ||
onChange={handleEncounterTypeChange} | ||
size={desktopLayout ? 'sm' : 'lg'} | ||
className={styles.label} | ||
/> | ||
</FormGroup> | ||
)} | ||
</Stack> | ||
</ModalBody> | ||
</Form> | ||
<ModalFooter> | ||
<Button kind="secondary" onClick={closeModal}> | ||
{t('cancel', 'Cancel')} | ||
</Button> | ||
<Button disabled={!selectedWidget} onClick={handleCreateWidget}> | ||
<span>{t('createSubMenu', 'Create Submenu')}</span> | ||
</Button> | ||
</ModalFooter> | ||
</> | ||
); | ||
}; | ||
|
||
export default ConfigureDashboardModal; |
Oops, something went wrong.