Skip to content

Commit

Permalink
feat: add Action Plan support for paragraphText
Browse files Browse the repository at this point in the history
  • Loading branch information
farmerpaul committed Nov 19, 2024
1 parent 6ae0aba commit b81c010
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 29 deletions.
1 change: 1 addition & 0 deletions src/abstract/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const phrasalTemplateCompatibleResponseTypes = [
'singleSelect',
'slider',
'text',
'paragraphText',
'time',
'timeRange',
'multiSelectRows',
Expand Down
11 changes: 10 additions & 1 deletion src/entities/activity/ui/items/ActionPlan/Document.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,19 @@ export type LineBreakPageComponent = BasePageComponent & {
componentType: 'line_break';
};

/**
* Newline is a special component that is used to force a new line in the document, used when
* rendering the `paragraphText` item type.
*/
export type NewlinePageComponent = BasePageComponent & {
componentType: 'newline';
};

export type PageComponent =
| SentencePageComponent
| ItemResponsePageComponent
| LineBreakPageComponent;
| LineBreakPageComponent
| NewlinePageComponent;

export type DocumentData = {
imageUrlByPhraseId: Record<string, string>;
Expand Down
9 changes: 7 additions & 2 deletions src/entities/activity/ui/items/ActionPlan/Phrase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const Phrase = ({
(isLastOnPage && componentIndex === pageComponents.length - 1)
) {
// Remove leading and trailing line-break components.
if (component.componentType !== 'line_break') {
if (component.componentType !== 'line_break' && component.componentType !== 'newline') {
acc.push(component);
}
} else {
Expand All @@ -60,7 +60,10 @@ export const Phrase = ({
let previousComponentType: PageComponent['componentType'] | undefined;
phraseComponents.forEach((component, componentIndex) => {
const componentType = component.componentType;
const isAtStart = componentIndex === 0 || previousComponentType === 'line_break';
const isAtStart =
componentIndex === 0 ||
previousComponentType === 'line_break' ||
previousComponentType === 'newline';

if (componentType === 'sentence') {
rendered.push(<TextSegment text={component.text} isAtStart={isAtStart} />);
Expand All @@ -80,6 +83,8 @@ export const Phrase = ({
rendered.push(<ResponseSegment itemResponse={itemResponse} isAtStart={isAtStart} />);
} else if (componentType === 'line_break') {
rendered.push(<Box component="hr" sx={{ m: 0, height: 32, border: 'none' }} />);
} else if (componentType === 'newline') {
rendered.push(<br />);
}

previousComponentType = componentType;
Expand Down
27 changes: 25 additions & 2 deletions src/entities/activity/ui/items/ActionPlan/pageComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
IdentifiablePhrasalTemplatePhrase,
LineBreakPageComponent,
ListItemResponsePageComponent,
NewlinePageComponent,
PageComponent,
SentencePageComponent,
TextItemResponsePageComponent,
Expand Down Expand Up @@ -89,7 +90,7 @@ export const buildPageComponents = (
}

let valueItems: string[];
if (fieldPhrasalData.type === 'array') {
if (fieldPhrasalDataType === 'array') {
valueItems = isAnswersSkipped(fieldPhrasalData.values)
? [t('questionSkipped')]
: fieldPhrasalData.values.map(transformValue);
Expand Down Expand Up @@ -158,6 +159,28 @@ export const buildPageComponents = (
items: valueItems,
};
components.push(component);
} else if (fieldPhrasalData.context.itemResponseType === 'paragraphText') {
valueItems
.flatMap((item) => item.split(/\r?\n/))
.forEach((text, index) => {
if (index > 0) {
const component: NewlinePageComponent = {
phraseIndex,
phraseId: phrase.id,
componentType: 'newline',
};
components.push(component);
}

const component: TextItemResponsePageComponent = {
phraseIndex,
phraseId: phrase.id,
componentType: 'item_response',
itemResponseType: 'text',
text: text || ' ', // Preserve empty lines
};
components.push(component);
});
} else {
const component: TextItemResponsePageComponent = {
phraseIndex,
Expand Down Expand Up @@ -317,7 +340,7 @@ export const deepDivideComponents = (
}
}
} else {
// Line-break items don't have "content". So just divide at components level.
// Line-break and newline items don't have "content". So just divide at components level.
return divideComponents(components, inclusiveComponentEnd);
}
}
Expand Down
9 changes: 9 additions & 0 deletions src/entities/activity/ui/items/ActionPlan/phrasalData.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,15 @@ describe('Action Plan', () => {
expect(data.item).toHaveProperty('context.itemResponseType', 'text');
});

it('should extract data from `paragraphText` activity type', () => {
const data = extractActivitiesPhrasalData([newTextItem('item', ['oh hai'])]);

expect(data).toHaveProperty('item');
expect(data.item).toHaveProperty('type', 'array');
expect(data.item).toHaveProperty('values.0', 'oh hai');
expect(data.item).toHaveProperty('context.itemResponseType', 'text');
});

it('should extract data from `singleSelect` activity type', () => {
const data = extractActivitiesPhrasalData([
newSingleSelectItem('item', ['1'], ['one', 'two', 'three']),
Expand Down
39 changes: 15 additions & 24 deletions src/entities/activity/ui/items/ActionPlan/phrasalData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ type ActivityPhrasalBaseData<

type ActivityPhrasalArrayFieldData = ActivityPhrasalBaseData<'array', string[]>;

type ActivityPhrasalParagraphFieldData = ActivityPhrasalBaseData<'paragraph', string[]>;

type ActivityPhrasalItemizedArrayValue = Record<number, string[]>;

type ActivityPhrasalIndexedArrayFieldData = ActivityPhrasalBaseData<
Expand All @@ -49,8 +47,7 @@ type ActivityPhrasalMatrixFieldData = ActivityPhrasalBaseData<'matrix', Activity
type ActivityPhrasalData =
| ActivityPhrasalArrayFieldData
| ActivityPhrasalIndexedArrayFieldData
| ActivityPhrasalMatrixFieldData
| ActivityPhrasalParagraphFieldData;
| ActivityPhrasalMatrixFieldData;

export type ActivitiesPhrasalData = Record<string, ActivityPhrasalData>;

Expand All @@ -77,42 +74,36 @@ export const extractActivitiesPhrasalData = (items: ItemRecord[]): ActivitiesPhr
};
fieldData = dateFieldData;
} else if (item.responseType === 'time' || item.responseType === 'timeRange') {
const dateFieldData: ActivityPhrasalArrayFieldData = {
const timeFieldData: ActivityPhrasalArrayFieldData = {
type: 'array',
values: item.answer
.map((value) => new Date(value))
.filter((value) => !!value)
.map((value) => formatToDtoTime(value)),
context: fieldDataContext,
};
fieldData = dateFieldData;
fieldData = timeFieldData;
} else if (
item.responseType === 'numberSelect' ||
item.responseType === 'slider' ||
item.responseType === 'text'
item.responseType === 'text' ||
item.responseType === 'paragraphText'
) {
const dateFieldData: ActivityPhrasalArrayFieldData = {
const textFieldData: ActivityPhrasalArrayFieldData = {
type: 'array',
values: item.answer.map((value) => `${value || ''}`),
context: fieldDataContext,
};
fieldData = dateFieldData;
} else if (item.responseType === 'paragraphText') {
const dateFieldData: ActivityPhrasalParagraphFieldData = {
type: 'paragraph',
values: item.answer.map((value) => value || ''),
context: fieldDataContext,
};
fieldData = dateFieldData;
fieldData = textFieldData;
} else if (item.responseType === 'singleSelect' || item.responseType === 'multiSelect') {
const dateFieldData: ActivityPhrasalArrayFieldData = {
const selectFieldData: ActivityPhrasalArrayFieldData = {
type: 'array',
values: item.answer
.map((value) => item.responseValues.options[parseInt(value, 10)]?.text)
.filter((value) => !!value),
context: fieldDataContext,
};
fieldData = dateFieldData;
fieldData = selectFieldData;
} else if (item.responseType === 'multiSelectRows') {
const byRow = item.responseValues.rows.map<ActivityPhrasalIndexedMatrixValue>(
(row, rowIndex) => {
Expand Down Expand Up @@ -143,12 +134,12 @@ export const extractActivitiesPhrasalData = (items: ItemRecord[]): ActivitiesPhr
},
);

const dateFieldData: ActivityPhrasalMatrixFieldData = {
const selectFieldData: ActivityPhrasalMatrixFieldData = {
type: 'matrix',
values: { byRow, byColumn },
context: fieldDataContext,
};
fieldData = dateFieldData;
fieldData = selectFieldData;
} else if (item.responseType === 'singleSelectRows') {
const byRow = item.responseValues.rows.map<ActivityPhrasalIndexedMatrixValue>(
(row, rowIndex) => {
Expand All @@ -171,25 +162,25 @@ export const extractActivitiesPhrasalData = (items: ItemRecord[]): ActivitiesPhr
},
);

const dateFieldData: ActivityPhrasalMatrixFieldData = {
const selectFieldData: ActivityPhrasalMatrixFieldData = {
type: 'matrix',
values: { byRow, byColumn },
context: fieldDataContext,
};
fieldData = dateFieldData;
fieldData = selectFieldData;
} else if (item.responseType === 'sliderRows') {
(fieldDataContext as ActivityPhrasalDataSliderRowContext).maxValues =
item.responseValues.rows.map(({ maxValue }) => maxValue);

const dateFieldData: ActivityPhrasalIndexedArrayFieldData = {
const sliderRowsFieldData: ActivityPhrasalIndexedArrayFieldData = {
type: 'indexed-array',
values: item.answer.reduce((acc, answerValue, answerIndex) => {
acc[answerIndex] = [`${answerValue || ''}`];
return acc;
}, {} as ActivityPhrasalItemizedArrayValue),
context: fieldDataContext,
};
fieldData = dateFieldData;
fieldData = sliderRowsFieldData;
}

if (fieldData) {
Expand Down

0 comments on commit b81c010

Please sign in to comment.