Skip to content

Commit

Permalink
Merge branch 'master' into CHI-1976-case_timeline_rework
Browse files Browse the repository at this point in the history
# Conflicts:
#	plugin-hrm-form/src/components/case/CaseHome.tsx
#	plugin-hrm-form/src/components/case/timeline/Timeline.tsx
  • Loading branch information
stephenhand committed Dec 15, 2023
2 parents 211ecdf + 0b628c0 commit 68639d6
Show file tree
Hide file tree
Showing 33 changed files with 449 additions and 108 deletions.
9 changes: 9 additions & 0 deletions .github/workflows/flex-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,20 @@ jobs:
uses: actions/setup-node@v1
with:
node-version: '16.x'

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1

- name: Set Twilio account SID
uses: "marvinpinto/action-inject-ssm-secrets@latest"
with:
ssm_parameter: "/${{inputs.environment_code}}/twilio/${{inputs.helpline_code}}/account_sid"
env_variable_name: "TWILIO_ACCOUNT_SID"

- name: Set Twilio Auth Token
uses: "marvinpinto/action-inject-ssm-secrets@latest"
with:
Expand Down
1 change: 1 addition & 0 deletions plugin-hrm-form/src/components/case/CaseHome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ const mapDispatchToProps = (dispatch: Dispatch<any>, { task }: CaseHomeProps) =>
asyncDispatch(dispatch)(connectToCaseAsyncAction(taskContact.id, cas.id)),
closeModal: () => dispatch(newCloseModalAction(task.taskSid, 'tabbed-forms')),
});

const connector = connect(mapStateToProps, mapDispatchToProps);
const connected = connector(CaseHome);

Expand Down
3 changes: 2 additions & 1 deletion plugin-hrm-form/src/components/case/timeline/Timeline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import DialogContent from '@material-ui/core/DialogContent';
import CallTypeIcon from '../../common/icons/CallTypeIcon';
import TimelineIcon from './TimelineIcon';
import {
CaseDetailsBorder,
CaseSectionFont,
TimelineCallTypeIcon,
TimelineDate,
Expand Down Expand Up @@ -93,7 +94,7 @@ const Timeline: React.FC<Props> = ({
return null;
}

const caseId = connectedCase.id.toString();
const caseId = connectedCase.id;
const handleViewNoteClick = ({ id }: NoteActivity) => {
openViewCaseSectionModal(caseId, NewCaseSubroutes.Note, id);
};
Expand Down
6 changes: 4 additions & 2 deletions plugin-hrm-form/src/components/profile/ProfileTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { connect, ConnectedProps } from 'react-redux';
import { Tab as TwilioTab, Template } from '@twilio/flex-ui';

import { Box } from '../../styles/HrmStyles';
import { useProfile } from '../../states/profile/hooks';
import { useProfile, useProfileLoader } from '../../states/profile/hooks';
import * as RoutingTypes from '../../states/routing/types';
import { getCurrentTopmostRouteForTask } from '../../states/routing/getRoute';
import * as RoutingActions from '../../states/routing/actions';
Expand Down Expand Up @@ -60,7 +60,9 @@ const connector = connect(mapStateToProps, mapDispatchToProps);
type Props = OwnProps & ConnectedProps<typeof connector>;

const ProfileTabs: React.FC<Props> = ({ profileId, task, currentTab, changeProfileTab }) => {
const { profile: { contactsCount, casesCount } = {} } = useProfile({ profileId, shouldAutoload: true });
const { profile: { contactsCount, casesCount } = {} } = useProfile({ profileId });
useProfileLoader({ profileId });

const tabs = [
{
label: 'Client',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const ProfileFlagsEdit: React.FC<Props> = (props: Props) => {
const { modalRef, profileId } = props;

const { allProfileFlags, profileFlags, associateProfileFlag } = useProfileFlags(profileId);
const { loading } = useSelector((state: RootState) => selectProfileAsyncPropertiesById(state, profileId));
const loading = useSelector((state: RootState) => selectProfileAsyncPropertiesById(state, profileId))?.loading;

const anchorRef = useRef(null);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ type Props = OwnProps;

const ProfileFlagsList: React.FC<Props> = ({ disassociateRef, enableDisassociate, profileId }) => {
const { profileFlags, disassociateProfileFlag } = useProfileFlags(profileId);
const { loading } = useSelector((state: RootState) => selectProfileAsyncPropertiesById(state, profileId));
const loading = useSelector((state: RootState) => selectProfileAsyncPropertiesById(state, profileId))?.loading;

const renderDisassociate = (flag: ProfileFlag) => {
if (!enableDisassociate) return null;
Expand Down
4 changes: 2 additions & 2 deletions plugin-hrm-form/src/permissions/nz.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@

"viewContact": [["everyone"]],
"editContact": [["isSupervisor"],["isOwner"]],
"viewExternalTranscript": [["everyone"]],
"viewRecording": [["everyone"]],
"viewExternalTranscript": [],
"viewRecording": [],
"viewPostSurvey": [["isSupervisor"]],
"addContactToCase": [["isSupervisor"], ["isOwner"]],

Expand Down
2 changes: 2 additions & 0 deletions plugin-hrm-form/src/states/profile/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@
export * from './useIdentifier';
export * from './useProfile';
export * from './useProfileFlags';
export * from './useProfileLoader';
export * from './useProfileProperty';
20 changes: 20 additions & 0 deletions plugin-hrm-form/src/states/profile/hooks/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Copyright (C) 2021-2023 Technology Matters
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
import { ProfileIdParam } from '../selectors';

export type UseProfileCommonParams = {
profileId: ProfileIdParam;
};
66 changes: 7 additions & 59 deletions plugin-hrm-form/src/states/profile/hooks/useProfile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,52 +21,13 @@ import { Profile } from '../types';
import * as ProfileActions from '../profiles';
import * as ProfileSelectors from '../selectors';
import { RootState } from '../..';
import { UseProfileCommonParams } from './types';

export type UseProfileLoaderParams = {
profileId: ProfileSelectors.ProfileIdParam;
shouldAutoload?: Boolean;
};

export type UseProfileLoaderReturn = {
error?: any;
loading: boolean;
loadProfile: () => void;
};

export type UseProfileParams = UseProfileLoaderParams;

export type UseProfileReturn = UseProfileLoaderReturn & {
profile?: Profile;
};

/**
* Load a profile by id into redux
* @param {UseProfileLoaderParams}
* @returns {UseProfileLoaderReturn} - State and actions for the profile
*/
export const useProfileLoader = ({
profileId,
shouldAutoload = false,
}: UseProfileLoaderParams): UseProfileLoaderReturn => {
const dispatch = useDispatch();
const error = useSelector((state: RootState) => ProfileSelectors.selectProfileById(state, profileId)?.error);
const loading = useSelector((state: RootState) => ProfileSelectors.selectProfileById(state, profileId)?.loading);
const loadProfile = useCallback(() => {
asyncDispatch(dispatch)(ProfileActions.loadProfileAsync(profileId));
}, [dispatch, profileId]);

useEffect(() => {
if (shouldAutoload && !loading) {
loadProfile();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [profileId, shouldAutoload, loadProfile]);
export type UseProfileParams = UseProfileCommonParams;

return {
error,
loading,
loadProfile,
};
export type UseProfileReturn = {
profile: Profile | undefined;
loading: boolean | undefined;
};

/**
Expand All @@ -78,23 +39,10 @@ export const useProfileLoader = ({
export const useProfile = (params: UseProfileParams): UseProfileReturn => {
const { profileId } = params;
const profile = useSelector((state: RootState) => ProfileSelectors.selectProfileById(state, profileId)?.data);
const loading = useSelector((state: RootState) => ProfileSelectors.selectProfileById(state, profileId)?.loading);

return {
loading,
profile,
...useProfileLoader(params),
};
};

/**
* Access a profile property by id for the current account
*
* @param {ProfileSelectors.ProfileIdParam} profileId - The id of the profile to access
* @param {T} property - The property to access
* @returns {UseProfile} - State and actions for the profile
*/
export const useProfileProperty = <T extends keyof Profile>(
profileId: ProfileSelectors.ProfileIdParam,
property: T,
): Profile[T] | undefined => {
return useSelector((state: RootState) => ProfileSelectors.selectProfilePropertyById(state, profileId, property));
};
65 changes: 65 additions & 0 deletions plugin-hrm-form/src/states/profile/hooks/useProfileLoader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/**
* Copyright (C) 2021-2023 Technology Matters
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
import { useCallback, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';

import { RootState } from '../..';
import asyncDispatch from '../../asyncDispatch';
import * as ProfileActions from '../profiles';
import * as ProfileSelectors from '../selectors';
import { UseProfileCommonParams } from './types';

type UseProfileLoaderParams = UseProfileCommonParams & {
skipAutoload?: boolean;
};

type UseProfileLoaderReturn = {
error?: any;
loading: boolean;
loadProfile: () => void;
};

/**
* Tools to load a profile by id into redux, by default it will load the profile automatically
* @param {UseProfileLoaderParams} params - Parameters for the hook
* @param params.profileId - The id of the profile to load
* @param params.skipAutoload - If true, the profile will not be loaded automatically (default: false)
* @returns {UseProfileLoaderReturn} - loading state and actions for the profile
*/
export const useProfileLoader = ({
profileId,
skipAutoload = false,
}: UseProfileLoaderParams): UseProfileLoaderReturn => {
const dispatch = useDispatch();
const error = useSelector((state: RootState) => ProfileSelectors.selectProfileById(state, profileId)?.error);
const loading = useSelector((state: RootState) => ProfileSelectors.selectProfileById(state, profileId)?.loading);
const loadProfile = useCallback(() => {
asyncDispatch(dispatch)(ProfileActions.loadProfileAsync(profileId));
}, [dispatch, profileId]);

useEffect(() => {
if (!skipAutoload && !loading) {
loadProfile();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [profileId, skipAutoload, loadProfile]);

return {
error,
loading,
loadProfile,
};
};
33 changes: 33 additions & 0 deletions plugin-hrm-form/src/states/profile/hooks/useProfileProperty.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* Copyright (C) 2021-2023 Technology Matters
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
import { useSelector } from 'react-redux';

import { RootState } from '../..';
import { Profile } from '../types';
import * as ProfileSelectors from '../selectors';

/**
* Access a profile property by id for the current account
*
* @param {ProfileSelectors.ProfileIdParam} profileId - The id of the profile to access
* @param {T} property - The property to access
* @returns {UseProfile} - State and actions for the profile
*/
export const useProfileProperty = <T extends keyof Profile>(
profileId: ProfileSelectors.ProfileIdParam,
property: T,
): Profile[T] | undefined =>
useSelector((state: RootState) => ProfileSelectors.selectProfilePropertyById(state, profileId, property));
8 changes: 4 additions & 4 deletions plugin-hrm-form/src/states/profile/hooks/useProfileSection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ import { Profile, ProfileSection } from '../types';
import * as ProfileActions from '../profiles';
import * as ProfileSelectors from '../selectors';
import { RootState } from '../..';
import { UseProfileCommonParams } from './types';

export type useProfileSectionByType = {
profileId: Profile['id'];
export type UseProfileSectionByType = UseProfileCommonParams & {
sectionType: string;
};

export const useProfileSectionLoaderByType = ({ profileId, sectionType }: useProfileSectionByType) => {
export const useProfileSectionLoaderByType = ({ profileId, sectionType }: UseProfileSectionByType) => {
const dispatch = useDispatch();
// We need the profile section out of the profile data to use it in the useEffect below
const profileSection = useSelector((state: RootState) =>
Expand Down Expand Up @@ -63,7 +63,7 @@ export const useProfileSectionLoaderByType = ({ profileId, sectionType }: usePro
};
};

export const useProfileSectionByType = ({ profileId, sectionType }: useProfileSectionByType) => {
export const useProfileSectionByType = ({ profileId, sectionType }: UseProfileSectionByType) => {
const section = useSelector(
(state: RootState) => ProfileSelectors.selectProfileSectionByType(state, profileId, sectionType)?.data,
);
Expand Down
Loading

0 comments on commit 68639d6

Please sign in to comment.