diff --git a/src/webapp/components/im-team-hierarchy/IMTeamHierarchyItem.tsx b/src/webapp/components/im-team-hierarchy/IMTeamHierarchyItem.tsx index e6d7ff0a..e666fc9f 100644 --- a/src/webapp/components/im-team-hierarchy/IMTeamHierarchyItem.tsx +++ b/src/webapp/components/im-team-hierarchy/IMTeamHierarchyItem.tsx @@ -15,10 +15,11 @@ type IMTeamHierarchyItemProps = { teamRole: string; member: Maybe; disabled?: boolean; - onSelectedChange: (nodeId: string, selected: boolean) => void; + onSelectedChange?: (nodeId: string, selected: boolean) => void; subChildren: IMTeamHierarchyOption[]; diseaseOutbreakEventName: string; - selectedItemIds: Id[]; + selectedItemIds?: Id[]; + isSelectable?: boolean; }; export const IMTeamHierarchyItem: React.FC = React.memo(props => { @@ -31,23 +32,28 @@ export const IMTeamHierarchyItem: React.FC = React.mem subChildren, diseaseOutbreakEventName, selectedItemIds, + isSelectable = false, } = props; const [openMemberProfile, setOpenMemberProfile] = React.useState(false); const onCheckboxChange = React.useCallback( (isChecked: boolean) => { - !disabled && onSelectedChange(nodeId, isChecked); + if (onSelectedChange && isSelectable && !disabled) { + onSelectedChange(nodeId, isChecked); + } }, - [disabled, nodeId, onSelectedChange] + [disabled, nodeId, onSelectedChange, isSelectable] ); const onTeamRoleClick = React.useCallback( (event: React.MouseEvent) => { - event.preventDefault(); - !disabled && onSelectedChange(nodeId, !selectedItemIds.includes(nodeId)); + if (isSelectable && onSelectedChange && selectedItemIds) { + event.preventDefault(); + !disabled && onSelectedChange(nodeId, !selectedItemIds.includes(nodeId)); + } }, - [disabled, nodeId, onSelectedChange, selectedItemIds] + [disabled, nodeId, onSelectedChange, selectedItemIds, isSelectable] ); const onMemberClick = React.useCallback( @@ -61,28 +67,22 @@ export const IMTeamHierarchyItem: React.FC = React.mem [member] ); - const onLabelClick = React.useCallback( - (event: React.MouseEvent) => { - event.preventDefault(); - !disabled && onSelectedChange(nodeId, !selectedItemIds.includes(nodeId)); - }, - [disabled, nodeId, onSelectedChange, selectedItemIds] - ); - return ( <> - + {isSelectable && selectedItemIds && ( + + )} @@ -106,6 +106,7 @@ export const IMTeamHierarchyItem: React.FC = React.mem onSelectedChange={onSelectedChange} diseaseOutbreakEventName={diseaseOutbreakEventName} subChildren={child.children} + isSelectable={isSelectable} /> ))} diff --git a/src/webapp/components/im-team-hierarchy/IMTeamHierarchyView.tsx b/src/webapp/components/im-team-hierarchy/IMTeamHierarchyView.tsx index 09370c10..b1df8cf4 100644 --- a/src/webapp/components/im-team-hierarchy/IMTeamHierarchyView.tsx +++ b/src/webapp/components/im-team-hierarchy/IMTeamHierarchyView.tsx @@ -20,12 +20,13 @@ export type IMTeamHierarchyOption = { type IMTeamHierarchyViewProps = { items: IMTeamHierarchyOption[]; - selectedItemIds: Id[]; - onSelectedItemChange: (nodeId: Id, selected: boolean) => void; + selectedItemIds?: Id[]; + onSelectedItemChange?: (nodeId: Id, selected: boolean) => void; diseaseOutbreakEventName: string; onSearchChange: (term: string) => void; searchTerm: string; defaultTeamRolesExpanded: Id[]; + isSelectable?: boolean; }; export const IMTeamHierarchyView: React.FC = React.memo(props => { @@ -37,6 +38,7 @@ export const IMTeamHierarchyView: React.FC = React.mem searchTerm, onSearchChange, defaultTeamRolesExpanded, + isSelectable = false, } = props; return ( @@ -59,6 +61,7 @@ export const IMTeamHierarchyView: React.FC = React.mem onSelectedChange={onSelectedItemChange} diseaseOutbreakEventName={diseaseOutbreakEventName} subChildren={item.children} + isSelectable={isSelectable} /> ))} diff --git a/src/webapp/components/incident-management-team/IncidentManagementTeamView.tsx b/src/webapp/components/incident-management-team/IncidentManagementTeamView.tsx new file mode 100644 index 00000000..e38aa46a --- /dev/null +++ b/src/webapp/components/incident-management-team/IncidentManagementTeamView.tsx @@ -0,0 +1,61 @@ +import React from "react"; +import styled from "styled-components"; + +import { + IMTeamHierarchyOption, + IMTeamHierarchyView, +} from "../im-team-hierarchy/IMTeamHierarchyView"; +import { Id } from "../../../domain/entities/Ref"; +import { BasicTable, TableColumn, TableRowType } from "../table/BasicTable"; + +type IncidentManagementTeamViewProps = { + selectedHierarchyItemIds?: Id[]; + onSelectHierarchyItem?: (nodeId: string, selected: boolean) => void; + searchTerm: string; + onSearchChange: (term: string) => void; + incidentManagementTeamHierarchyItems: IMTeamHierarchyOption[]; + defaultTeamRolesExpanded: Id[]; + diseaseOutbreakEventName: string; + isSelectable?: boolean; + constactTableColumns: TableColumn[]; + constactTableRows: TableRowType[]; +}; + +export const IncidentManagementTeamView: React.FC = React.memo( + props => { + const { + selectedHierarchyItemIds, + onSelectHierarchyItem, + searchTerm, + onSearchChange, + incidentManagementTeamHierarchyItems, + defaultTeamRolesExpanded, + diseaseOutbreakEventName, + constactTableColumns, + constactTableRows, + isSelectable = false, + } = props; + + return ( + + + + + ); + } +); + +const IncidentManagementTeamViewContainer = styled.div` + display: flex; + flex-direction: column; + gap: 24px; +`; diff --git a/src/webapp/components/incident-management-team/useIncidentManagementTeamView.ts b/src/webapp/components/incident-management-team/useIncidentManagementTeamView.ts new file mode 100644 index 00000000..a29b53a2 --- /dev/null +++ b/src/webapp/components/incident-management-team/useIncidentManagementTeamView.ts @@ -0,0 +1,244 @@ +import React from "react"; +import { Dispatch, SetStateAction, useCallback, useEffect, useState } from "react"; +import { useSnackbar } from "@eyeseetea/d2-ui-components"; + +import _c from "../../../domain/entities/generic/Collection"; +import i18n from "../../../utils/i18n"; +import { Maybe } from "../../../utils/ts-utils"; +import { Id } from "../../../domain/entities/Ref"; +import { useAppContext } from "../../contexts/app-context"; +import { IMTeamHierarchyOption } from "../im-team-hierarchy/IMTeamHierarchyView"; +import { IncidentManagementTeam } from "../../../domain/entities/incident-management-team/IncidentManagementTeam"; +import { TeamMember, TeamRole } from "../../../domain/entities/incident-management-team/TeamMember"; +import { TableColumn, TableRowType } from "../table/BasicTable"; + +type State = { + incidentManagementTeamHierarchyItems: Maybe; + selectedHierarchyItemIds: Id[]; + setSelectedHierarchyItemIds: Dispatch>; + onSearchChange: (term: string) => void; + getIncidentManagementTeam: () => void; + searchTerm: string; + defaultTeamRolesExpanded: Maybe; + incidentManagementTeam: IncidentManagementTeam | undefined; + constactTableColumns: TableColumn[]; + constactTableRows: TableRowType[]; +}; + +export function useIncidentManagementTeamView(id: Id): State { + const { compositionRoot, configurations } = useAppContext(); + const snackbar = useSnackbar(); + + const [incidentManagementTeamHierarchyItems, setIncidentManagementTeamHierarchyItems] = + useState(); + const [incidentManagementTeam, setIncidentManagementTeam] = useState< + IncidentManagementTeam | undefined + >(); + const [selectedHierarchyItemIds, setSelectedHierarchyItemIds] = useState([]); + const [defaultTeamRolesExpanded, setDefaultTeamRolesExpanded] = useState( + undefined + ); + const [searchTerm, setSearchTerm] = useState(""); + const [constactTableRows, setConstactTableRows] = useState([]); + + const getIncidentManagementTeam = useCallback(() => { + compositionRoot.incidentManagementTeam.get.execute(id, configurations).run( + incidentManagementTeam => { + setIncidentManagementTeam(incidentManagementTeam); + setDefaultTeamRolesExpanded(getDefaultTeamRolesExpanded(incidentManagementTeam)); + setIncidentManagementTeamHierarchyItems( + mapIncidentManagementTeamToIncidentManagementTeamHierarchyItems( + incidentManagementTeam?.teamHierarchy + ) + ); + setConstactTableRows( + mapIncidentManagementTeamToTableRows(incidentManagementTeam?.teamHierarchy) + ); + }, + err => { + console.debug(err); + snackbar.error(i18n.t(`Error loading current Incident Management Team`)); + } + ); + }, [compositionRoot.incidentManagementTeam.get, configurations, id, snackbar]); + + useEffect(() => { + getIncidentManagementTeam(); + }, [getIncidentManagementTeam]); + + const onSearchChange = useCallback( + (term: string) => { + setSearchTerm(term); + + if (incidentManagementTeamHierarchyItems) { + const filteredIncidentManagementTeamHierarchyItems = term + ? filterIncidentManagementTeamHierarchy( + incidentManagementTeamHierarchyItems, + term + ) + : mapIncidentManagementTeamToIncidentManagementTeamHierarchyItems( + incidentManagementTeam?.teamHierarchy + ); + + setIncidentManagementTeamHierarchyItems( + filteredIncidentManagementTeamHierarchyItems + ); + } + }, + [incidentManagementTeam?.teamHierarchy, incidentManagementTeamHierarchyItems] + ); + + const constactTableColumns: TableColumn[] = React.useMemo(() => { + return [ + { value: "role", label: "Role", type: "text" }, + { value: "name", label: "Name", type: "text" }, + { value: "email", label: "Email", type: "text" }, + { value: "phone", label: "Phone", type: "text" }, + ]; + }, []); + + return { + incidentManagementTeamHierarchyItems, + incidentManagementTeam, + selectedHierarchyItemIds, + defaultTeamRolesExpanded, + searchTerm, + constactTableColumns, + constactTableRows, + setSelectedHierarchyItemIds, + onSearchChange, + getIncidentManagementTeam, + }; +} + +function getTeamRolesMap( + incidentManagementTeamHierarchy: Maybe +): Record | undefined { + if (incidentManagementTeamHierarchy) { + const createHierarchyItem = ( + item: TeamMember, + teamRole: TeamRole + ): IMTeamHierarchyOption => ({ + id: teamRole.id, + teamRole: teamRole.name, + teamRoleId: teamRole.roleId, + member: new TeamMember({ + id: item.id, + name: item.name, + username: item.username, + phone: item.phone, + email: item.email, + status: item.status, + photo: item.photo, + teamRoles: item.teamRoles, + workPosition: item.workPosition, + }), + parent: teamRole.reportsToUsername, + children: [], + }); + + return incidentManagementTeamHierarchy.reduce>( + (map, item) => { + const hierarchyItems = item.teamRoles?.map(teamRole => + createHierarchyItem(item, teamRole) + ); + + return !hierarchyItems || hierarchyItems?.length === 0 + ? map + : hierarchyItems.reduce( + (acc, hierarchyItem) => ({ + ...acc, + [hierarchyItem.id]: hierarchyItem, + }), + map + ); + }, + {} + ); + } +} + +function mapIncidentManagementTeamToIncidentManagementTeamHierarchyItems( + incidentManagementTeamHierarchy: Maybe +): IMTeamHierarchyOption[] { + if (incidentManagementTeamHierarchy) { + const teamRolesMap = getTeamRolesMap(incidentManagementTeamHierarchy); + return teamRolesMap ? buildTree(teamRolesMap) : []; + } else { + return []; + } +} + +function buildTree(teamMap: Record): IMTeamHierarchyOption[] { + const findChildren = (parentUsername: string): IMTeamHierarchyOption[] => + Object.values(teamMap) + .filter(item => item.parent === parentUsername) + .reduce((acc, item) => { + const children = findChildren(item.member?.username || ""); + return [...acc, { ...item, children: [...item.children, ...children] }]; + }, []); + + return Object.values(teamMap).reduce((acc, item) => { + const isRoot = !item.parent; + if (isRoot) { + const children = findChildren(item.member?.username || ""); + return [...acc, { ...item, children: [...item.children, ...children] }]; + } + + return acc; + }, []); +} + +function filterIncidentManagementTeamHierarchy( + items: IMTeamHierarchyOption[], + searchTerm: string +): IMTeamHierarchyOption[] { + return _c( + items.map(item => { + const filteredChildren = filterIncidentManagementTeamHierarchy( + item.children, + searchTerm + ); + + const isMatch = + item.teamRole.toLowerCase().includes(searchTerm.toLowerCase()) || + item.member?.name.toLowerCase().includes(searchTerm.toLowerCase()); + + if (isMatch || filteredChildren.length > 0) { + return { + ...item, + children: filteredChildren, + }; + } + + return null; + }) + ) + .compact() + .toArray(); +} + +function getDefaultTeamRolesExpanded(incidentManagementTeam: Maybe): Id[] { + return ( + incidentManagementTeam?.teamHierarchy.flatMap(teamMember => { + return teamMember?.teamRoles?.map(teamRole => teamRole.id) || []; + }) || [] + ); +} + +function mapIncidentManagementTeamToTableRows( + incidentManagementTeamHierarchy: Maybe +): TableRowType[] { + const teamRolesMap = getTeamRolesMap(incidentManagementTeamHierarchy); + if (teamRolesMap) { + return Object.values(teamRolesMap).map(teamRole => ({ + id: teamRole.id, + role: teamRole.teamRole, + name: teamRole.member?.name || "", + email: teamRole.member?.email || "", + phone: teamRole.member?.phone || "", + })); + } else { + return []; + } +} diff --git a/src/webapp/components/table/BasicTable.tsx b/src/webapp/components/table/BasicTable.tsx index 35fa3bd0..b4276169 100644 --- a/src/webapp/components/table/BasicTable.tsx +++ b/src/webapp/components/table/BasicTable.tsx @@ -113,6 +113,7 @@ const StyledTable = styled(Table)` } & .MuiTableBody-root { color: ${props => props.theme.palette.common.grey}; + background-color: ${props => props.theme.palette.common.white}; } & .MuiTableCell-root { font-size: 0.75rem; diff --git a/src/webapp/pages/form-page/incident-management-team-member-assignment/mapIncidentManagementTeamMemberToInitialFormState.ts b/src/webapp/pages/form-page/incident-management-team-member-assignment/mapIncidentManagementTeamMemberToInitialFormState.ts index acc132b4..b2cb9f05 100644 --- a/src/webapp/pages/form-page/incident-management-team-member-assignment/mapIncidentManagementTeamMemberToInitialFormState.ts +++ b/src/webapp/pages/form-page/incident-management-team-member-assignment/mapIncidentManagementTeamMemberToInitialFormState.ts @@ -117,7 +117,7 @@ export function mapIncidentManagementTeamMemberToInitialFormState( value: teamRoleToAssing?.reportsToUsername || "", required: teamRoleToAssing?.roleId !== INCIDENT_MANAGER_ROLE, showIsRequired: teamRoleToAssing?.roleId !== INCIDENT_MANAGER_ROLE, - disabled: false, + disabled: teamRoleToAssing?.roleId === INCIDENT_MANAGER_ROLE, }, ], }, diff --git a/src/webapp/pages/incident-action-plan/IncidentActionPlanPage.tsx b/src/webapp/pages/incident-action-plan/IncidentActionPlanPage.tsx index 8e5f6b19..beda3408 100644 --- a/src/webapp/pages/incident-action-plan/IncidentActionPlanPage.tsx +++ b/src/webapp/pages/incident-action-plan/IncidentActionPlanPage.tsx @@ -10,6 +10,7 @@ import { ActionPlanFormSummary } from "../../components/form/form-summary/Action import { IncidentActionNotice } from "./IncidentActionNotice"; import { Loader } from "../../components/loader/Loader"; import { ResponseActionTable } from "./ResponseActionTable"; +import { TeamSection } from "./TeamSection"; export const IncidentActionPlanPage: React.FC = React.memo(() => { const { getCurrentEventTracker } = useCurrentEventTracker(); @@ -42,7 +43,9 @@ export const IncidentActionPlanPage: React.FC = React.memo(() => { title={i18n.t("Incident Action Plan")} subtitle={i18n.t(currentEventTracker?.name || "")} > - {!actionPlanSummary && responseActionRows.length === 0 && !summaryError && } + {(!actionPlanSummary && responseActionRows.length === 0 && !summaryError) || !id ? ( + + ) : null} {!incidentActionExists ? ( ) : ( @@ -75,6 +78,7 @@ export const IncidentActionPlanPage: React.FC = React.memo(() => { /> )} + {id && } ); }); diff --git a/src/webapp/pages/incident-action-plan/TeamSection.tsx b/src/webapp/pages/incident-action-plan/TeamSection.tsx new file mode 100644 index 00000000..ff441aaa --- /dev/null +++ b/src/webapp/pages/incident-action-plan/TeamSection.tsx @@ -0,0 +1,63 @@ +import React, { useCallback } from "react"; +import { IconEditItems24 } from "@dhis2/ui"; + +import i18n from "../../../utils/i18n"; +import { Section } from "../../components/section/Section"; +import { useCurrentEventTracker } from "../../contexts/current-event-tracker-context"; +import { RouteName, useRoutes } from "../../hooks/useRoutes"; +import { Button } from "../../components/button/Button"; +import { useIncidentManagementTeamView } from "../../components/incident-management-team/useIncidentManagementTeamView"; +import { Id } from "../../../domain/entities/Ref"; +import { IncidentManagementTeamView } from "../../components/incident-management-team/IncidentManagementTeamView"; + +type TeamSectionProps = { + diseaseOutbreakEventId: Id; +}; + +export const TeamSection: React.FC = React.memo(props => { + const { diseaseOutbreakEventId } = props; + const { goTo } = useRoutes(); + const { getCurrentEventTracker } = useCurrentEventTracker(); + const { + incidentManagementTeamHierarchyItems, + onSearchChange, + searchTerm, + defaultTeamRolesExpanded, + constactTableColumns, + constactTableRows, + } = useIncidentManagementTeamView(diseaseOutbreakEventId); + + const goToIncidentManagementTeamBuilder = useCallback(() => { + goTo(RouteName.IM_TEAM_BUILDER, { id: diseaseOutbreakEventId }); + }, [diseaseOutbreakEventId, goTo]); + + return ( +
} + onClick={goToIncidentManagementTeamBuilder} + > + {i18n.t("Edit Role")} + + } + titleVariant="secondary" + > + {!incidentManagementTeamHierarchyItems || !defaultTeamRolesExpanded ? null : ( + + )} +
+ ); +}); diff --git a/src/webapp/pages/incident-management-team-builder/IMTeamBuilderPage.tsx b/src/webapp/pages/incident-management-team-builder/IMTeamBuilderPage.tsx index f77a3295..4d5db70a 100644 --- a/src/webapp/pages/incident-management-team-builder/IMTeamBuilderPage.tsx +++ b/src/webapp/pages/incident-management-team-builder/IMTeamBuilderPage.tsx @@ -11,10 +11,10 @@ import LoaderContainer from "../../components/loader/LoaderContainer"; import { UserCard } from "../../components/user-selector/UserCard"; import { Section } from "../../components/section/Section"; import { Button } from "../../components/button/Button"; -import { IMTeamHierarchyView } from "../../components/im-team-hierarchy/IMTeamHierarchyView"; import { useIMTeamBuilder } from "./useIMTeamBuilder"; import { useCurrentEventTracker } from "../../contexts/current-event-tracker-context"; import { SimpleModal } from "../../components/simple-modal/SimpleModal"; +import { IncidentManagementTeamView } from "../../components/incident-management-team/IncidentManagementTeamView"; export const IMTeamBuilderPage: React.FC = React.memo(() => { const { id } = useParams<{ @@ -32,6 +32,8 @@ export const IMTeamBuilderPage: React.FC = React.memo(() => { disableDeletion, searchTerm, defaultTeamRolesExpanded, + constactTableColumns, + constactTableRows, onSearchChange, onSelectHierarchyItem, goToIncidentManagementTeamRole, @@ -99,14 +101,19 @@ export const IMTeamBuilderPage: React.FC = React.memo(() => { } > {!incidentManagementTeamHierarchyItems || !defaultTeamRolesExpanded ? null : ( - )} diff --git a/src/webapp/pages/incident-management-team-builder/useIMTeamBuilder.ts b/src/webapp/pages/incident-management-team-builder/useIMTeamBuilder.ts index 666f461b..fbc7aa19 100644 --- a/src/webapp/pages/incident-management-team-builder/useIMTeamBuilder.ts +++ b/src/webapp/pages/incident-management-team-builder/useIMTeamBuilder.ts @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useMemo, useState } from "react"; +import { useCallback, useMemo, useState } from "react"; import { Id } from "../../../domain/entities/Ref"; import { Maybe } from "../../../utils/ts-utils"; import { useAppContext } from "../../contexts/app-context"; @@ -6,10 +6,11 @@ import { User } from "../../components/user-selector/UserSelector"; import { mapTeamMemberToUser } from "../form-page/mapEntityToFormState"; import { IMTeamHierarchyOption } from "../../components/im-team-hierarchy/IMTeamHierarchyView"; import { RouteName, useRoutes } from "../../hooks/useRoutes"; -import { IncidentManagementTeam } from "../../../domain/entities/incident-management-team/IncidentManagementTeam"; -import { TeamMember, TeamRole } from "../../../domain/entities/incident-management-team/TeamMember"; +import { TeamMember } from "../../../domain/entities/incident-management-team/TeamMember"; import { INCIDENT_MANAGER_ROLE } from "../../../data/repositories/consts/IncidentManagementTeamBuilderConstants"; import _c from "../../../domain/entities/generic/Collection"; +import { useIncidentManagementTeamView } from "../../components/incident-management-team/useIncidentManagementTeamView"; +import { TableColumn, TableRowType } from "../../components/table/BasicTable"; type GlobalMessage = { text: string; @@ -31,51 +32,31 @@ type State = { onSearchChange: (term: string) => void; searchTerm: string; defaultTeamRolesExpanded: Maybe; + constactTableColumns: TableColumn[]; + constactTableRows: TableRowType[]; }; -export function useIMTeamBuilder(id: Id): State { - const { compositionRoot, configurations } = useAppContext(); +export function useIMTeamBuilder(diseaseOutbreakEventId: Id): State { + const { compositionRoot } = useAppContext(); const { goTo } = useRoutes(); + const { + incidentManagementTeamHierarchyItems, + incidentManagementTeam, + selectedHierarchyItemIds, + setSelectedHierarchyItemIds, + onSearchChange, + searchTerm, + defaultTeamRolesExpanded, + getIncidentManagementTeam, + constactTableColumns, + constactTableRows, + } = useIncidentManagementTeamView(diseaseOutbreakEventId); + const [globalMessage, setGlobalMessage] = useState>(); - const [incidentManagementTeamHierarchyItems, setIncidentManagementTeamHierarchyItems] = - useState(); - const [incidentManagementTeam, setIncidentManagementTeam] = useState< - IncidentManagementTeam | undefined - >(); - const [selectedHierarchyItemIds, setSelectedHierarchyItemIds] = useState([]); const [disableDeletion, setDisableDeletion] = useState(false); - const [defaultTeamRolesExpanded, setDefaultTeamRolesExpanded] = useState( - undefined - ); const [openDeleteModalData, setOpenDeleteModalData] = useState( undefined ); - const [searchTerm, setSearchTerm] = useState(""); - - const getIncidentManagementTeam = useCallback(() => { - compositionRoot.incidentManagementTeam.get.execute(id, configurations).run( - incidentManagementTeam => { - setIncidentManagementTeam(incidentManagementTeam); - setDefaultTeamRolesExpanded(getDefaultTeamRolesExpanded(incidentManagementTeam)); - setIncidentManagementTeamHierarchyItems( - mapIncidentManagementTeamToIncidentManagementTeamHierarchyItems( - incidentManagementTeam?.teamHierarchy - ) - ); - }, - err => { - console.debug(err); - setGlobalMessage({ - text: `Error loading current Incident Management Team`, - type: "error", - }); - } - ); - }, [compositionRoot.incidentManagementTeam.get, configurations, id]); - - useEffect(() => { - getIncidentManagementTeam(); - }, [getIncidentManagementTeam]); const goToIncidentManagementTeamRole = useCallback(() => { if (selectedHierarchyItemIds.length === 1 && selectedHierarchyItemIds[0]) { @@ -121,7 +102,11 @@ export function useIMTeamBuilder(id: Id): State { setSelectedHierarchyItemIds(newSelection); setDisableDeletion(isIncidentManagerRoleSelected || hasSomeParentReporting); }, - [incidentManagementTeam?.teamHierarchy, selectedHierarchyItemIds] + [ + incidentManagementTeam?.teamHierarchy, + selectedHierarchyItemIds, + setSelectedHierarchyItemIds, + ] ); const onOpenDeleteModalData = useCallback( @@ -148,7 +133,7 @@ export function useIMTeamBuilder(id: Id): State { if (disableDeletion || !selectedHierarchyItemIds.length) return; compositionRoot.incidentManagementTeam.deleteIncidentManagementTeamMemberRoles - .execute(id, selectedHierarchyItemIds) + .execute(diseaseOutbreakEventId, selectedHierarchyItemIds) .run( () => { setGlobalMessage({ @@ -176,10 +161,11 @@ export function useIMTeamBuilder(id: Id): State { }, [ compositionRoot.incidentManagementTeam.deleteIncidentManagementTeamMemberRoles, disableDeletion, + diseaseOutbreakEventId, getIncidentManagementTeam, - id, onOpenDeleteModalData, selectedHierarchyItemIds, + setSelectedHierarchyItemIds, ]); const incidentManagerUser = useMemo(() => { @@ -191,28 +177,6 @@ export function useIMTeamBuilder(id: Id): State { } }, [incidentManagementTeam?.teamHierarchy]); - const onSearchChange = useCallback( - (term: string) => { - setSearchTerm(term); - - if (incidentManagementTeamHierarchyItems) { - const filteredIncidentManagementTeamHierarchyItems = term - ? filterIncidentManagementTeamHierarchy( - incidentManagementTeamHierarchyItems, - term - ) - : mapIncidentManagementTeamToIncidentManagementTeamHierarchyItems( - incidentManagementTeam?.teamHierarchy - ); - - setIncidentManagementTeamHierarchyItems( - filteredIncidentManagementTeamHierarchyItems - ); - } - }, - [incidentManagementTeam?.teamHierarchy, incidentManagementTeamHierarchyItems] - ); - const lastUpdated = incidentManagementTeam?.lastUpdated?.toString() ?? ""; return { @@ -230,112 +194,7 @@ export function useIMTeamBuilder(id: Id): State { searchTerm, onSearchChange, defaultTeamRolesExpanded, + constactTableColumns, + constactTableRows, }; } - -function mapIncidentManagementTeamToIncidentManagementTeamHierarchyItems( - incidentManagementTeamHierarchy: Maybe -): IMTeamHierarchyOption[] { - if (incidentManagementTeamHierarchy) { - const createHierarchyItem = ( - item: TeamMember, - teamRole: TeamRole - ): IMTeamHierarchyOption => ({ - id: teamRole.id, - teamRole: teamRole.name, - teamRoleId: teamRole.roleId, - member: new TeamMember({ - id: item.id, - name: item.name, - username: item.username, - phone: item.phone, - email: item.email, - status: item.status, - photo: item.photo, - teamRoles: item.teamRoles, - workPosition: item.workPosition, - }), - parent: teamRole.reportsToUsername, - children: [], - }); - - const teamMap = incidentManagementTeamHierarchy.reduce< - Record - >((map, item) => { - const hierarchyItems = item.teamRoles?.map(teamRole => - createHierarchyItem(item, teamRole) - ); - - return !hierarchyItems || hierarchyItems?.length === 0 - ? map - : hierarchyItems.reduce( - (acc, hierarchyItem) => ({ - ...acc, - [hierarchyItem.id]: hierarchyItem, - }), - map - ); - }, {}); - - return buildTree(teamMap); - } else { - return []; - } -} - -function buildTree(teamMap: Record): IMTeamHierarchyOption[] { - const findChildren = (parentUsername: string): IMTeamHierarchyOption[] => - Object.values(teamMap) - .filter(item => item.parent === parentUsername) - .reduce((acc, item) => { - const children = findChildren(item.member?.username || ""); - return [...acc, { ...item, children: [...item.children, ...children] }]; - }, []); - - return Object.values(teamMap).reduce((acc, item) => { - const isRoot = !item.parent; - if (isRoot) { - const children = findChildren(item.member?.username || ""); - return [...acc, { ...item, children: [...item.children, ...children] }]; - } - - return acc; - }, []); -} - -function filterIncidentManagementTeamHierarchy( - items: IMTeamHierarchyOption[], - searchTerm: string -): IMTeamHierarchyOption[] { - return _c( - items.map(item => { - const filteredChildren = filterIncidentManagementTeamHierarchy( - item.children, - searchTerm - ); - - const isMatch = - item.teamRole.toLowerCase().includes(searchTerm.toLowerCase()) || - item.member?.name.toLowerCase().includes(searchTerm.toLowerCase()); - - if (isMatch || filteredChildren.length > 0) { - return { - ...item, - children: filteredChildren, - }; - } - - return null; - }) - ) - .compact() - .toArray(); -} - -function getDefaultTeamRolesExpanded(incidentManagementTeam: Maybe): Id[] { - return ( - incidentManagementTeam?.teamHierarchy.flatMap(teamMember => { - return teamMember?.teamRoles?.map(teamRole => teamRole.id) || []; - }) || [] - ); -}