Skip to content

Commit

Permalink
feat: per-subject activity progress/submission
Browse files Browse the repository at this point in the history
Made widespread change to incorporate `targetSubjectId` into activity
progres tracking, when assignments feature is enabled. Anytime `eventId`
is used, now `targetSubjectid` also needs to be passed to identify which
activity assignment is the active assessment. This value is also passed
to the `answers` POST endpoint to ensure the submission is also properly
associated with the `targetSubjectId`.

For self-reports, and when assignments feature is disabled,
`targetSubjectId` is set to `null`, effectively inheriting existing
functionality.

For `PublicSurvey` and `PublicAutoCompletion`, `targetSubjectId` stays
`null` since public assessments do not support activity assignments.
  • Loading branch information
farmerpaul committed Aug 30, 2024
1 parent d4e2b54 commit 2c818e6
Show file tree
Hide file tree
Showing 50 changed files with 456 additions and 178 deletions.
5 changes: 4 additions & 1 deletion src/abstract/lib/GroupBuilder/GroupUtility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,10 @@ export class GroupUtility {
}

public getProgressRecord(eventEntity: EventEntity): GroupProgress | null {
const record = this.progress[getProgressId(eventEntity.entity.id, eventEntity.event.id)];
const record =
this.progress[
getProgressId(eventEntity.entity.id, eventEntity.event.id, eventEntity.targetSubject?.id)
];
return record ?? null;
}

Expand Down
4 changes: 2 additions & 2 deletions src/abstract/lib/GroupBuilder/activityGroups.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ export type Entity = Activity | ActivityFlow;
export type EventEntity = {
entity: Entity;
event: ScheduleEvent;
/** Target subject of assignment if not self-report, else undefined */
targetSubject?: SubjectDTO;
/** Target subject of assignment if not self-report, else null */
targetSubject: SubjectDTO | null;
};

export type EntityType = 'regular' | 'flow';
2 changes: 1 addition & 1 deletion src/abstract/lib/GroupBuilder/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export type ActivityListItem = {
activityId: string;
flowId: string | null;
eventId: string;
targetSubject?: SubjectDTO;
targetSubject: SubjectDTO | null;

name: string;
description: string;
Expand Down
18 changes: 12 additions & 6 deletions src/abstract/lib/getProgressId.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
export const getProgressId = (entityId: string, eventId: string): string => {
return `${entityId}/${eventId}`;
import { GroupProgressId } from './types';

export const getProgressId = (
entityId: string,
eventId: string,
targetSubjectId?: string | null,
): GroupProgressId => {
return targetSubjectId ? `${entityId}/${eventId}/${targetSubjectId}` : `${entityId}/${eventId}`;
};

export const getDataFromProgressId = (
progressId: string,
): { entityId: string; eventId: string } => {
const [entityId, eventId] = progressId.split('/');
progressId: GroupProgressId,
): { entityId: string; eventId: string; targetSubjectId: string | null } => {
const [entityId, eventId, targetSubjectId = null] = progressId.split('/');

return { entityId, eventId };
return { entityId, eventId, targetSubjectId };
};
8 changes: 7 additions & 1 deletion src/abstract/lib/types/entityProgress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ type EventProgressTimestampState = {

export type GroupProgress = ActivityOrFlowProgress & EventProgressTimestampState;

type GroupProgressId = string; // Group progress id is a combination of entityId and eventId (EntityId = ActivityId or FlowId)
/**
* Combination of:
* - entityId (= activityId/flowId),
* - eventId
* - targetSubjectId (optional; only if not self-report)
*/
export type GroupProgressId = `${string}/${string}` | `${string}/${string}/${string}`;

export type GroupProgressState = Record<GroupProgressId, GroupProgress>;
10 changes: 9 additions & 1 deletion src/entities/applet/model/hooks/useActivityProgress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ import { useAppDispatch, useAppSelector } from '~/shared/utils';
type SaveProgressProps = {
activity: ActivityDTO;
eventId: string;
targetSubjectId: string | null;
};

type DefaultProps = {
activityId: string;
eventId: string;
targetSubjectId: string | null;
};

export const useActivityProgress = () => {
Expand All @@ -26,7 +28,10 @@ export const useActivityProgress = () => {

const getActivityProgress = useCallback(
(props: DefaultProps): ActivityProgress | null => {
const progress = activitiesProgressState[getProgressId(props.activityId, props.eventId)];
const progress =
activitiesProgressState[
getProgressId(props.activityId, props.eventId, props.targetSubjectId)
];

return progress ?? null;
},
Expand Down Expand Up @@ -61,6 +66,7 @@ export const useActivityProgress = () => {
actions.saveActivityProgress({
activityId: props.activity.id,
eventId: props.eventId,
targetSubjectId: props.targetSubjectId,
progress: {
items: preparedActivityItemProgressRecords,
step: initialStep,
Expand All @@ -81,6 +87,7 @@ export const useActivityProgress = () => {
actions.changeSummaryScreenVisibility({
activityId: props.activityId,
eventId: props.eventId,
targetSubjectId: props.targetSubjectId,
isSummaryScreenOpen: true,
}),
);
Expand All @@ -94,6 +101,7 @@ export const useActivityProgress = () => {
actions.changeSummaryScreenVisibility({
activityId: props.activityId,
eventId: props.eventId,
targetSubjectId: props.targetSubjectId,
isSummaryScreenOpen: false,
}),
);
Expand Down
36 changes: 32 additions & 4 deletions src/entities/applet/model/hooks/useEntityComplete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type CompletionType = 'regular' | 'autoCompletion';
type Props = {
activityId: string;
eventId: string;
targetSubjectId: string | null;

flowId: string | null;
publicAppletKey: string | null;
Expand Down Expand Up @@ -40,6 +41,7 @@ export const useEntityComplete = (props: Props) => {
entityCompleted({
entityId: props.flowId ? props.flowId : props.activityId,
eventId: props.eventId,
targetSubjectId: props.targetSubjectId,
});

const isAutoCompletion = completionType === 'autoCompletion';
Expand Down Expand Up @@ -73,6 +75,7 @@ export const useEntityComplete = (props: Props) => {
props.eventId,
props.flowId,
props.publicAppletKey,
props.targetSubjectId,
],
);

Expand All @@ -97,13 +100,21 @@ export const useEntityComplete = (props: Props) => {
appletId: props.appletId,
activityId,
eventId: props.eventId,
targetSubjectId: props.targetSubjectId,
entityType: 'flow',
flowId: props.flowId,
}),
{ replace: true },
);
},
[navigator, props.appletId, props.eventId, props.flowId, props.publicAppletKey],
[
navigator,
props.appletId,
props.eventId,
props.flowId,
props.publicAppletKey,
props.targetSubjectId,
],
);

const completeFlow = useCallback(
Expand All @@ -113,6 +124,7 @@ export const useEntityComplete = (props: Props) => {
const groupProgress = getGroupProgress({
entityId: props.flowId ? props.flowId : props.activityId,
eventId: props.eventId,
targetSubjectId: props.targetSubjectId,
});

if (!groupProgress) {
Expand All @@ -137,10 +149,15 @@ export const useEntityComplete = (props: Props) => {
activityId: nextActivityId ? nextActivityId : props.flow.activityIds[0],
flowId: props.flow.id,
eventId: props.eventId,
targetSubjectId: props.targetSubjectId,
pipelineActivityOrder: nextActivityId ? currentPipelineActivityOrder + 1 : 0,
});

removeActivityProgress({ activityId: props.activityId, eventId: props.eventId });
removeActivityProgress({
activityId: props.activityId,
eventId: props.eventId,
targetSubjectId: props.targetSubjectId,
});

if (nextActivityId && !isAutoCompletion) {
return redirectToNextActivity(nextActivityId);
Expand All @@ -158,18 +175,29 @@ export const useEntityComplete = (props: Props) => {
props.eventId,
props.flow,
props.flowId,
props.targetSubjectId,
redirectToNextActivity,
removeActivityProgress,
],
);

const completeActivity = useCallback(
(input?: CompleteOptions) => {
removeActivityProgress({ activityId: props.activityId, eventId: props.eventId });
removeActivityProgress({
activityId: props.activityId,
eventId: props.eventId,
targetSubjectId: props.targetSubjectId,
});

return completeEntityAndRedirect(input?.type || 'regular');
},
[completeEntityAndRedirect, props.activityId, props.eventId, removeActivityProgress],
[
completeEntityAndRedirect,
props.activityId,
props.eventId,
props.targetSubjectId,
removeActivityProgress,
],
);

return {
Expand Down
32 changes: 23 additions & 9 deletions src/entities/applet/model/hooks/useEntityStart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,24 @@ export const useEntityStart = () => {
const dispatch = useAppDispatch();
const groupProgress = useAppSelector(groupProgressSelector);

const getProgress = (entityId: string, eventId: string): GroupProgress =>
groupProgress[getProgressId(entityId, eventId)];
const getProgress = (
entityId: string,
eventId: string,
targetSubjectId: string | null,
): GroupProgress => groupProgress[getProgressId(entityId, eventId, targetSubjectId)];

const isInProgress = (payload: GroupProgress): boolean => payload && !payload.endAt;

function activityStarted(activityId: string, eventId: string): void {
function activityStarted(
activityId: string,
eventId: string,
targetSubjectId: string | null,
): void {
dispatch(
actions.activityStarted({
activityId,
eventId,
targetSubjectId,
}),
);
}
Expand All @@ -27,32 +35,38 @@ export const useEntityStart = () => {
flowId: string,
activityId: string,
eventId: string,
targetSubjectId: string | null,
pipelineActivityOrder: number,
): void {
dispatch(
actions.flowStarted({
flowId,
activityId,
eventId,
targetSubjectId,
pipelineActivityOrder,
}),
);
}

function startActivity(activityId: string, eventId: string): void {
const isActivityInProgress = isInProgress(getProgress(activityId, eventId));
function startActivity(
activityId: string,
eventId: string,
targetSubjectId: string | null,
): void {
const isActivityInProgress = isInProgress(getProgress(activityId, eventId, targetSubjectId));

if (isActivityInProgress) {
return;
}

return activityStarted(activityId, eventId);
return activityStarted(activityId, eventId, targetSubjectId);
}

function startFlow(eventId: string, flow: ActivityFlowDTO): void {
function startFlow(eventId: string, flow: ActivityFlowDTO, targetSubjectId: string | null): void {
const flowId = flow.id;

const isFlowInProgress = isInProgress(getProgress(flowId, eventId));
const isFlowInProgress = isInProgress(getProgress(flowId, eventId, targetSubjectId));

if (isFlowInProgress) {
return;
Expand All @@ -68,7 +82,7 @@ export const useEntityStart = () => {

const firstActivityId: string = flowActivities[0];

return flowStarted(flowId, firstActivityId, eventId, 0);
return flowStarted(flowId, firstActivityId, eventId, targetSubjectId, 0);
}

return { startActivity, startFlow };
Expand Down
9 changes: 7 additions & 2 deletions src/entities/applet/model/hooks/useGroupProgressRecord.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@ import { useAppSelector } from '~/shared/utils';
type Props = {
entityId: string;
eventId: string;
targetSubjectId: string | null;
};

export const useGroupProgressRecord = ({ entityId, eventId }: Props): GroupProgress | null => {
export const useGroupProgressRecord = ({
entityId,
eventId,
targetSubjectId,
}: Props): GroupProgress | null => {
const record = useAppSelector((state) =>
selectGroupProgress(state, getProgressId(entityId, eventId)),
selectGroupProgress(state, getProgressId(entityId, eventId, targetSubjectId)),
);

return record ?? null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ export const useGroupProgressStateManager = (): Return => {
return null;
}

return groupProgresses[getProgressId(params.entityId, params.eventId)] ?? null;
return (
groupProgresses[getProgressId(params.entityId, params.eventId, params.targetSubjectId)] ??
null
);
},
[groupProgresses],
);
Expand Down
Loading

0 comments on commit 2c818e6

Please sign in to comment.