From 4a0fc412cd0abbec34728d18e273b41436f6cfd4 Mon Sep 17 00:00:00 2001 From: Luis Oliveira Date: Wed, 9 Aug 2023 15:11:40 +0100 Subject: [PATCH 1/4] Added support to cohort attributes. --- src/add-group-modal/AddGroupModal.tsx | 51 +++++++++++++++- .../CohortAttributeComponent.tsx | 60 +++++++++++++++++++ .../cohort-attribute-component/styles.scss | 3 + src/config-schema.ts | 52 ++++++++++++++++ 4 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 src/add-group-modal/cohort-attribute-component/CohortAttributeComponent.tsx create mode 100644 src/add-group-modal/cohort-attribute-component/styles.scss diff --git a/src/add-group-modal/AddGroupModal.tsx b/src/add-group-modal/AddGroupModal.tsx index c12b550..6720bb6 100644 --- a/src/add-group-modal/AddGroupModal.tsx +++ b/src/add-group-modal/AddGroupModal.tsx @@ -16,10 +16,13 @@ import { } from "@carbon/react"; import { TrashCan } from "@carbon/react/icons"; import { useTranslation } from "react-i18next"; -import { ExtensionSlot, showToast } from "@openmrs/esm-framework"; +import { ExtensionSlot, showToast, useConfig } from "@openmrs/esm-framework"; import styles from "./styles.scss"; import GroupFormWorkflowContext from "../context/GroupFormWorkflowContext"; import { usePostCohort } from "../hooks"; +import CohortAttributeComponent, { + CohortAttribute, +} from "./cohort-attribute-component/CohortAttributeComponent"; const MemExtension = React.memo(ExtensionSlot); @@ -79,6 +82,8 @@ const NewGroupForm = (props) => { errors, validate, removePatient, + groupAttributes, + onCohortAttributeValueChange, } = props; const { t } = useTranslation(); @@ -103,6 +108,10 @@ const NewGroupForm = (props) => { : errors.name}

)} + {patientList.length} {t("patientsInGroup", "Patients in group")} @@ -154,6 +163,8 @@ const AddGroupModal = ({ const [name, setName] = useState(groupName); const [patientList, setPatientList] = useState(patients || []); const { post, result, error } = usePostCohort(); + const { groupAttributesConfig } = useConfig(); + const [groupAttributes, setGroupAttributes] = useState([]); const removePatient = useCallback( (patientUuid: string) => @@ -205,11 +216,47 @@ const AddGroupModal = ({ [setPatientList] ); + useMemo(() => { + setGroupAttributes( + groupAttributesConfig?.map((config) => { + return { + labelCode: config.labelCode, + attributeType: { + name: config.name, + type: config.type, + uuid: config.uuid, + }, + }; + }) + ); + }, [groupAttributesConfig]); + + const onCohortAttributeValueChange = (attributeId: string, value: any) => { + const updatedAttributes = [...groupAttributes]; + updatedAttributes.find( + (a: CohortAttribute) => a.attributeType.uuid == attributeId + ).value = value; + setGroupAttributes(updatedAttributes); + }; + + const getAttributesPayload = () => { + return groupAttributes.map((a: CohortAttribute) => { + return { + uuid: a.uuid, + value: a.value, + attributeType: { + uuid: a.attributeType.uuid, + }, + }; + }); + }; + const handleSubmit = () => { if (validate()) { post({ uuid: cohortUuid, name: name, + attributes: getAttributesPayload(), cohortMembers: patientList.map((p) => ({ patient: p.uuid })), }); if (onPostSubmit) { @@ -269,6 +316,8 @@ const AddGroupModal = ({ errors, validate, removePatient, + groupAttributes, + onCohortAttributeValueChange, }} /> diff --git a/src/add-group-modal/cohort-attribute-component/CohortAttributeComponent.tsx b/src/add-group-modal/cohort-attribute-component/CohortAttributeComponent.tsx new file mode 100644 index 0000000..9420d6f --- /dev/null +++ b/src/add-group-modal/cohort-attribute-component/CohortAttributeComponent.tsx @@ -0,0 +1,60 @@ +import React from "react"; +import { TextInput, Checkbox } from "@carbon/react"; +import { useTranslation } from "react-i18next"; +import styles from "./styles.scss"; + +interface CohortAttributeComponentProps { + cohortAttributeTypes: CohortAttribute[]; + onChange: any; +} +const CohortAttributeComponent: React.FC = ( + props +) => { + const { cohortAttributeTypes, onChange } = props; + const { t } = useTranslation(); + + return ( + <> + {cohortAttributeTypes.map((attribute) => { + switch (attribute.attributeType.type) { + case "org.openmrs.customdatatype.datatype.FreeTextDatatype": + return ( + { + onChange(event.target.id, event.target.value); + }} + /> + ); + case "org.openmrs.customdatatype.datatype.BooleanDatatype": + return ( + { + onChange(event.target.id, event.target.checked); + }} + /> + ); + default: + break; + } + })} + + ); +}; +export default CohortAttributeComponent; + +export type CohortAttribute = { + uuid?: string; + labelCode?: string; + value?: any; + attributeType: { + uuid: string; + name: string; + type: string; + }; +}; diff --git a/src/add-group-modal/cohort-attribute-component/styles.scss b/src/add-group-modal/cohort-attribute-component/styles.scss new file mode 100644 index 0000000..ff98b1a --- /dev/null +++ b/src/add-group-modal/cohort-attribute-component/styles.scss @@ -0,0 +1,3 @@ +@use '@carbon/styles/scss/spacing'; +@use '@carbon/colors'; + diff --git a/src/config-schema.ts b/src/config-schema.ts index b50f1b9..4fda3f9 100644 --- a/src/config-schema.ts +++ b/src/config-schema.ts @@ -82,6 +82,48 @@ export const configSchema = { _default: "fa8fedc0-c066-4da3-8dc1-2ad8621fc480", }, }, + groupAttributesConfig: { + _type: Type.Array, + _description: + "List of group attributes, must correspond to an Cohort Attribute Type on the database", + _elements: { + uuid: { + _type: Type.String, + _description: "UUID of the Cohort Attribute Type", + }, + name: { + _type: Type.String, + _description: "Name of the Cohort Attribute Type", + }, + id: { + _type: Type.String, + _description: "ID of the attribute.", + }, + labelCode: { + _type: Type.String, + _description: "Code to be use in translation.", + }, + type: { + _type: Type.String, + _description: + "Datatype of the Cohort Attribute Type, acceptable values are 'FreeTextDatatype' | 'BooleanDatatype'", + }, + }, + _default: [ + { + uuid: "09790099-9190-429d-811a-aac9edb8d98a", + name: "Test 01", + labelCode: "test01", + type: "org.openmrs.customdatatype.datatype.FreeTextDatatype", + }, + { + uuid: "09790099-9190-429d-811a-aac9edb8d98d", + name: "Close Group", + labelCode: "closeGroup", + type: "org.openmrs.customdatatype.datatype.BooleanDatatype", + }, + ], + }, }; export type Form = { @@ -94,7 +136,17 @@ export type Category = { forms: Array
; }; +export type CohortAttributeTypeConfig = { + uuid: string; + name: string; + labelCode: string; + type: + | "org.openmrs.customdatatype.datatype.FreeTextDatatype" + | "org.openmrs.customdatatype.datatype.BooleanDatatype"; +}; + export type Config = { formCategories: Array; formCategoriesToShow: Array; + groupAttributesConfig: Array; }; From e588ff2846886f16366fa511f331280a5e0d190b Mon Sep 17 00:00:00 2001 From: Luis Oliveira Date: Wed, 9 Aug 2023 15:26:07 +0100 Subject: [PATCH 2/4] Added support to cohort attributes. --- src/add-group-modal/AddGroupModal.tsx | 6 +++--- ...tAttributeComponent.tsx => GroupAttributeComponent.tsx} | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) rename src/add-group-modal/cohort-attribute-component/{CohortAttributeComponent.tsx => GroupAttributeComponent.tsx} (89%) diff --git a/src/add-group-modal/AddGroupModal.tsx b/src/add-group-modal/AddGroupModal.tsx index 6720bb6..8a89ba3 100644 --- a/src/add-group-modal/AddGroupModal.tsx +++ b/src/add-group-modal/AddGroupModal.tsx @@ -20,9 +20,9 @@ import { ExtensionSlot, showToast, useConfig } from "@openmrs/esm-framework"; import styles from "./styles.scss"; import GroupFormWorkflowContext from "../context/GroupFormWorkflowContext"; import { usePostCohort } from "../hooks"; -import CohortAttributeComponent, { +import GroupAttributeComponent, { CohortAttribute, -} from "./cohort-attribute-component/CohortAttributeComponent"; +} from "./cohort-attribute-component/GroupAttributeComponent"; const MemExtension = React.memo(ExtensionSlot); @@ -108,7 +108,7 @@ const NewGroupForm = (props) => { : errors.name}

)} - diff --git a/src/add-group-modal/cohort-attribute-component/CohortAttributeComponent.tsx b/src/add-group-modal/cohort-attribute-component/GroupAttributeComponent.tsx similarity index 89% rename from src/add-group-modal/cohort-attribute-component/CohortAttributeComponent.tsx rename to src/add-group-modal/cohort-attribute-component/GroupAttributeComponent.tsx index 9420d6f..50d0641 100644 --- a/src/add-group-modal/cohort-attribute-component/CohortAttributeComponent.tsx +++ b/src/add-group-modal/cohort-attribute-component/GroupAttributeComponent.tsx @@ -3,11 +3,11 @@ import { TextInput, Checkbox } from "@carbon/react"; import { useTranslation } from "react-i18next"; import styles from "./styles.scss"; -interface CohortAttributeComponentProps { +interface GroupAttributeComponentProps { cohortAttributeTypes: CohortAttribute[]; onChange: any; } -const CohortAttributeComponent: React.FC = ( +const GroupAttributeComponent: React.FC = ( props ) => { const { cohortAttributeTypes, onChange } = props; @@ -22,6 +22,7 @@ const CohortAttributeComponent: React.FC = ( { onChange(event.target.id, event.target.value); @@ -46,7 +47,7 @@ const CohortAttributeComponent: React.FC = ( ); }; -export default CohortAttributeComponent; +export default GroupAttributeComponent; export type CohortAttribute = { uuid?: string; From bbd693f8472a4ee3eb5e251299f6b9f19d723d9b Mon Sep 17 00:00:00 2001 From: Luis Oliveira Date: Wed, 9 Aug 2023 16:21:42 +0100 Subject: [PATCH 3/4] Added support to cohort attributes. --- src/add-group-modal/AddGroupModal.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/add-group-modal/AddGroupModal.tsx b/src/add-group-modal/AddGroupModal.tsx index 8a89ba3..2d7a080 100644 --- a/src/add-group-modal/AddGroupModal.tsx +++ b/src/add-group-modal/AddGroupModal.tsx @@ -156,6 +156,7 @@ const AddGroupModal = ({ isOpen, handleCancel, onPostSubmit, + attributes = undefined, }) => { const { setGroup } = useContext(GroupFormWorkflowContext); const { t } = useTranslation(); @@ -164,7 +165,7 @@ const AddGroupModal = ({ const [patientList, setPatientList] = useState(patients || []); const { post, result, error } = usePostCohort(); const { groupAttributesConfig } = useConfig(); - const [groupAttributes, setGroupAttributes] = useState([]); + const [groupAttributes, setGroupAttributes] = useState([]); const removePatient = useCallback( (patientUuid: string) => @@ -219,8 +220,13 @@ const AddGroupModal = ({ useMemo(() => { setGroupAttributes( groupAttributesConfig?.map((config) => { + const attribute = attributes?.find( + (a) => a.attributeType.uuid == config.uuid + ); return { + uuid: attribute?.uuid, labelCode: config.labelCode, + value: attribute?.value, attributeType: { name: config.name, type: config.type, @@ -229,7 +235,7 @@ const AddGroupModal = ({ }; }) ); - }, [groupAttributesConfig]); + }, [groupAttributesConfig, attributes]); const onCohortAttributeValueChange = (attributeId: string, value: any) => { const updatedAttributes = [...groupAttributes]; From 32be9a626672f757db781757b60a91f7ed2e5def Mon Sep 17 00:00:00 2001 From: Luis Oliveira Date: Thu, 10 Aug 2023 12:25:14 +0100 Subject: [PATCH 4/4] Added API support for cohort attributes. --- src/add-group-modal/AddGroupModal.tsx | 3 +++ src/context/GroupFormWorkflowContext.tsx | 5 +++++ .../attendance-table/AttendanceTable.tsx | 10 +++++++--- .../group-search/GroupSearch.tsx | 2 ++ 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/add-group-modal/AddGroupModal.tsx b/src/add-group-modal/AddGroupModal.tsx index 2d7a080..f06d3e0 100644 --- a/src/add-group-modal/AddGroupModal.tsx +++ b/src/add-group-modal/AddGroupModal.tsx @@ -167,6 +167,9 @@ const AddGroupModal = ({ const { groupAttributesConfig } = useConfig(); const [groupAttributes, setGroupAttributes] = useState([]); + console.log("result", result); + console.log("groupName", groupName); + const removePatient = useCallback( (patientUuid: string) => setPatientList((patientList) => diff --git a/src/context/GroupFormWorkflowContext.tsx b/src/context/GroupFormWorkflowContext.tsx index 3e97972..4c59d60 100644 --- a/src/context/GroupFormWorkflowContext.tsx +++ b/src/context/GroupFormWorkflowContext.tsx @@ -11,6 +11,7 @@ export interface GroupType { id: string; name: string; members: Array; + attributes: Array; } export interface MetaType { sessionName: string; @@ -56,6 +57,7 @@ export const initialWorkflowState = { activeGroupUuid: null, // pseudo field from state[activeFormUuid].groupUuid activeGroupName: null, // pseudo field from state[activeFormUuid].groupName activeGroupMembers: [], // pseudo field from state[activeFormUuid].groupMembers + activeGroupAttributes: [], // pseudo field from state[activeFormUuid].groupAttributes activeSessionMeta: { sessionName: null, practitionerName: null, @@ -162,6 +164,9 @@ const GroupFormWorkflowProvider = ({ children }) => { activeGroupMembers: state.forms?.[state.activeFormUuid]?.groupMembers ?? initialWorkflowState.activeGroupMembers, + activeGroupAttributes: + state.forms?.[state.activeFormUuid]?.groupAttributes ?? + initialWorkflowState.activeGroupAttributes, activeSessionMeta: state.forms?.[state.activeFormUuid]?.sessionMeta ?? initialWorkflowState.activeSessionMeta, diff --git a/src/group-form-entry-workflow/attendance-table/AttendanceTable.tsx b/src/group-form-entry-workflow/attendance-table/AttendanceTable.tsx index 3f8042d..a943149 100644 --- a/src/group-form-entry-workflow/attendance-table/AttendanceTable.tsx +++ b/src/group-form-entry-workflow/attendance-table/AttendanceTable.tsx @@ -71,9 +71,12 @@ const PatientRow = ({ patient }) => { const AttendanceTable = ({ patients }) => { const { t } = useTranslation(); - const { activeGroupUuid, activeGroupName, activeGroupMembers } = useContext( - GroupFormWorkflowContext - ); + const { + activeGroupUuid, + activeGroupName, + activeGroupAttributes, + activeGroupMembers, + } = useContext(GroupFormWorkflowContext); const [isOpen, setOpen] = useState(false); @@ -118,6 +121,7 @@ const AttendanceTable = ({ patients }) => { isOpen: isOpen, handleCancel: handleCancel, onPostSubmit: onPostSubmit, + attributes: activeGroupAttributes, }} /> diff --git a/src/group-form-entry-workflow/group-search/GroupSearch.tsx b/src/group-form-entry-workflow/group-search/GroupSearch.tsx index 63980fd..e4f7714 100644 --- a/src/group-form-entry-workflow/group-search/GroupSearch.tsx +++ b/src/group-form-entry-workflow/group-search/GroupSearch.tsx @@ -35,6 +35,8 @@ const GroupSearch: React.FC = ({ }, }); + console.log("results", results); + const lastItem = useRef(null); const observer = useRef(null); const loadingRef = useCallback(