Skip to content

Commit

Permalink
feat: disable auto-assigned activities/flows from assignment (M2-7604) (
Browse files Browse the repository at this point in the history
#1926)

* Add a disabled button color on the ActivityCheckbox.

* Add disabeled states to activitie and flow based on autoAssign value. Update the slectAll button and logic to account for selectable activites and flows. Wrapping all new changes in the 'enableActivityAssign' feature flag.

* Add translation for disabled auto assign flow and activity.

* Remove redunent feature flag

* Update test

* Update disabled button colour
  • Loading branch information
LashaunnaS authored Sep 25, 2024
1 parent 792c664 commit 0e15c97
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 74 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useTranslation } from 'react-i18next';
import { ListItemIcon, ListItemText } from '@mui/material';

import { Chip, ChipShape, Svg } from 'shared/components';
import { Chip, ChipShape, Svg, Tooltip } from 'shared/components';
import { ActivityFlowThumbnail } from 'modules/Dashboard/components';
import { StyledActivityThumbnailContainer, StyledActivityThumbnailImg } from 'shared/styles';

Expand Down Expand Up @@ -51,67 +51,81 @@ export const ActivitiesList = ({

return (
<StyledList data-testid={dataTestId} sx={isReadOnly ? { height: 'auto', py: 0.5 } : undefined}>
{flows.map(({ id = '', activities, name }) => (
<StyledListItem
key={id}
secondaryAction={
isReadOnly ? undefined : (
<ActivityCheckbox
checked={flowIds?.includes(id)}
onChange={() => handleFlowClick(id)}
data-testid={`${dataTestId}-flow-checkbox-${id}`}
{flows.map(({ id = '', activities, name, autoAssign }) => (
<Tooltip placement="left" tooltipTitle={autoAssign && t('autoAssignFlowDisabled')}>
<StyledListItem
key={id}
secondaryAction={
isReadOnly ? undefined : (
<ActivityCheckbox
checked={flowIds?.includes(id)}
onChange={() => handleFlowClick(id)}
data-testid={`${dataTestId}-flow-checkbox-${id}`}
disabled={autoAssign}
/>
)
}
data-testid={`${dataTestId}-flow-item`}
>
<ButtonComponent
onClick={isReadOnly ? undefined : () => handleFlowClick(id)}
disabled={autoAssign}
>
<ListItemIcon>
<StyledActivityThumbnailContainer sx={{ width: '4.8rem', height: '4.8rem' }}>
<ActivityFlowThumbnail activities={activities} />
</StyledActivityThumbnailContainer>
</ListItemIcon>
<ListItemText
primary={
<StyledListItemTextPrimary>
{name}
<Chip
color="secondary"
size="medium"
icon={<Svg aria-hidden id="multiple-activities" height={18} width={18} />}
shape={ChipShape.Rectangular}
title={t('flow')}
/>
</StyledListItemTextPrimary>
}
/>
)
}
data-testid={`${dataTestId}-flow-item`}
>
<ButtonComponent onClick={isReadOnly ? undefined : () => handleFlowClick(id)}>
<ListItemIcon>
<StyledActivityThumbnailContainer sx={{ width: '4.8rem', height: '4.8rem' }}>
<ActivityFlowThumbnail activities={activities} />
</StyledActivityThumbnailContainer>
</ListItemIcon>
<ListItemText
primary={
<StyledListItemTextPrimary>
{name}
<Chip
color="secondary"
size="medium"
icon={<Svg aria-hidden id="multiple-activities" height={18} width={18} />}
shape={ChipShape.Rectangular}
title={t('flow')}
/>
</StyledListItemTextPrimary>
}
/>
</ButtonComponent>
</StyledListItem>
</ButtonComponent>
</StyledListItem>
</Tooltip>
))}

{activities.map(({ id = '', name, image }) => (
<StyledListItem
key={id}
secondaryAction={
isReadOnly ? undefined : (
<ActivityCheckbox
checked={activityIds?.includes(id)}
onChange={() => handleActivityClick(id)}
data-testid={`${dataTestId}-activity-checkbox-${id}`}
{activities.map(({ id = '', name, image, autoAssign }) => (
<Tooltip placement="left" tooltipTitle={autoAssign && t('autoAssignActivityDisabled')}>
<StyledListItem
key={id}
secondaryAction={
isReadOnly ? undefined : (
<ActivityCheckbox
checked={activityIds?.includes(id)}
onChange={() => handleActivityClick(id)}
data-testid={`${dataTestId}-activity-checkbox-${id}`}
disabled={autoAssign}
/>
)
}
data-testid={`${dataTestId}-activity-item`}
>
<ButtonComponent
onClick={isReadOnly ? undefined : () => handleActivityClick(id)}
disabled={autoAssign}
>
<ListItemIcon>
<StyledActivityThumbnailContainer sx={{ width: '4.8rem', height: '4.8rem' }}>
{!!image && <StyledActivityThumbnailImg src={image} alt={name} />}
</StyledActivityThumbnailContainer>
</ListItemIcon>
<ListItemText
primary={<StyledListItemTextPrimary>{name}</StyledListItemTextPrimary>}
/>
)
}
data-testid={`${dataTestId}-activity-item`}
>
<ButtonComponent onClick={isReadOnly ? undefined : () => handleActivityClick(id)}>
<ListItemIcon>
<StyledActivityThumbnailContainer sx={{ width: '4.8rem', height: '4.8rem' }}>
{!!image && <StyledActivityThumbnailImg src={image} alt={name} />}
</StyledActivityThumbnailContainer>
</ListItemIcon>
<ListItemText primary={<StyledListItemTextPrimary>{name}</StyledListItemTextPrimary>} />
</ButtonComponent>
</StyledListItem>
</ButtonComponent>
</StyledListItem>
</Tooltip>
))}
</StyledList>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ describe('ActivityAssignDrawer', () => {
});
});

it('toggles selection of all activities and flows when toggling Select All', async () => {
it('toggles selection of all non-disabled activities and flows when toggling Select All', async () => {
renderWithProviders(
<ActivityAssignDrawer appletId={mockedAppletId} open onClose={mockedOnClose} />,
{ preloadedState },
Expand All @@ -279,12 +279,22 @@ describe('ActivityAssignDrawer', () => {

fireEvent.click(selectAll);
[...activities, ...flows].forEach((checkbox) => {
expect(within(checkbox).getByRole('checkbox')).toBeChecked();
const checkboxElement = within(checkbox).getByRole('checkbox');
const itemIsNotDisabled = checkboxElement.getAttribute('disable') === 'false';

if (itemIsNotDisabled) {
expect(checkboxElement).toBeChecked();
}
});

fireEvent.click(selectAll);
[...activities, ...flows].forEach((checkbox) => {
expect(within(checkbox).getByRole('checkbox')).not.toBeChecked();
const checkboxElement = within(checkbox).getByRole('checkbox');
const itemIsNotDisabled = checkboxElement.getAttribute('disable') === 'false';

if (itemIsNotDisabled) {
expect(checkboxElement).not.toBeChecked();
}
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export const ActivityAssignDrawer = ({
...rest
}: ActivityAssignDrawerProps) => {
const { t } = useTranslation('app', { keyPrefix: 'activityAssign' });

const drawerRef = useRef<HTMLDivElement>(null);
const [showHelpPopup, setShowHelpPopup] = useState(false);
const [showDeletePopup, setShowDeletePopup] = useState(false);
Expand Down Expand Up @@ -127,7 +128,6 @@ export const ActivityAssignDrawer = ({
activitiesData?.data?.result?.appletDetail?.activityFlows ?? [],
activities,
);
const activitiesCount = activities.length + flows.length;

const defaultValues = {
activityIds: activityId ? [activityId] : [],
Expand Down Expand Up @@ -179,21 +179,26 @@ export const ActivityAssignDrawer = ({
drawerRef.current?.scrollTo({ top, behavior: 'smooth' });
};

const assignableActivities = activities
.map(({ autoAssign, id = '' }) => !autoAssign && id)
.filter((activity) => !!activity) as [] | string[];

const assignableFlows = flows
.map(({ autoAssign, id = '' }) => !autoAssign && id)
.filter((flow) => !!flow) as [] | string[];

const activitiesCount = assignableActivities.length + assignableFlows.length;
const selectAllIsChecked = activitiesCount !== 0 && selectionCount === activitiesCount;
const disableSelectAll =
activities.every(({ autoAssign }) => autoAssign) && flows.every(({ autoAssign }) => autoAssign);

const handleSelectAll = () => {
if (selectionCount === activitiesCount) {
setValue('activityIds', [], { shouldDirty: true });
setValue('flowIds', [], { shouldDirty: true });
} else {
setValue(
'activityIds',
activities.map(({ id = '' }) => id),
{ shouldDirty: true },
);
setValue(
'flowIds',
flows.map(({ id = '' }) => id),
{ shouldDirty: true },
);
setValue('activityIds', assignableActivities, { shouldDirty: true });
setValue('flowIds', assignableFlows, { shouldDirty: true });
}
};

Expand Down Expand Up @@ -506,11 +511,13 @@ export const ActivityAssignDrawer = ({
size="small"
onClick={handleSelectAll}
data-testid={`${dataTestId}-select-all`}
disabled={disableSelectAll}
>
{t('selectAll')}
<ActivityCheckbox
checked={selectionCount === activitiesCount}
checked={selectAllIsChecked}
onChange={handleSelectAll}
disabled={disableSelectAll}
/>
</Button>
</StyledFlexTopBaseline>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,16 @@ import { variables } from 'shared/styles';

export const ActivityCheckbox = (props: CheckboxProps) => (
<Checkbox
icon={<Svg id="add-circle" fill={variables.palette.on_surface_variant} />}
icon={
<Svg
id="add-circle"
fill={
props.disabled
? variables.palette.on_surface_variant_alfa16
: variables.palette.on_surface_variant
}
/>
}
checkedIcon={<Svg id="check-circle" fill={variables.palette.green} />}
sx={{ p: 0, m: 0, pointerEvents: 'none' }}
tabIndex={-1}
Expand Down
2 changes: 2 additions & 0 deletions src/resources/app-en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1626,5 +1626,7 @@
"autoAssignActivity": "Auto-assign this activity (as self-report)",
"autoAssignFlow": "Auto-assign this flow (as self-report)",
"autoAssignTooltip": "Keep this box selected to automatically assign this Activity or Flow to all new Participants. If instead you’d like to manually assign Activities or Flows to your Participants (for either Self-Reporting or Multi-Informant reporting) unselect this box. You’ll then be able to assign Activities or Flows from the Activities Tab in your Applet.",
"autoAssignActivityDisabled": "This activity is set to ‘Auto-assign’ in the Activity Builder and therefore cannot be assigned here.",
"autoAssignFlowDisabled": "This flow is set to ‘Auto-assign’ in the Activity Flow Builder and therefore cannot be assigned here.",
"goToDashboard": "Go to Dashboard"
}
2 changes: 2 additions & 0 deletions src/resources/app-fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -1625,5 +1625,7 @@
"autoAssignActivity": "Attribuer automatiquement cette activité (sous forme d'auto-évaluation)",
"autoAssignFlow": "Attribuer automatiquement ce flux (sous forme d'auto-évaluation)",
"autoAssignTooltip": "Gardez cette case cochée pour attribuer automatiquement cette activité ou ce flux à tous les nouveaux participants. Si, à la place, vous souhaitez attribuer manuellement des activités ou des flux à vos participants (pour une déclaration automatique ou une déclaration multi-informateurs), décochez cette case. Vous pourrez ensuite attribuer des activités ou des flux à partir de l'onglet Activités de votre applet.",
"autoAssignActivityDisabled": "Cette activité est paramétrée sur « Attribution automatique » dans le générateur d'activités et ne peut donc pas être attribuée ici.",
"autoAssignFlowDisabled": "Ce flux est défini sur « Auto-assign » dans l'Activity Flow Builder et ne peut donc pas être affecté ici.",
"goToDashboard": "Aller au tableau de bord"
}
1 change: 1 addition & 0 deletions src/shared/styles/variables/palette.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const palette = {
on_surface_alfa38: 'rgba(26, 28, 30, 0.38)',
on_surface_variant_alfa8: 'rgba(66, 71, 78, 0.08)',
on_surface_variant_alfa12: 'rgba(66, 71, 78, 0.12)',
on_surface_variant_alfa16: 'rgba(66, 71, 78, 0.16)',
on_primary_container_alfa8: 'rgba(0, 29, 50, 0.08)',
on_secondary_container_alfa8: 'rgba(14, 29, 42, 0.08)',
on_secondary_container_alfa12: 'rgba(14, 29, 42, 0.12)',
Expand Down

0 comments on commit 0e15c97

Please sign in to comment.