Skip to content

Commit 16b12c3

Browse files
author
Lucian
committed
feat(ora-grading): add prompt rendering and sync prompts with learner responses
- added support for reading prompts from oraMetadata in ResponseDisplay - implemented prompt → response pairing using array index alignment - sanitized and parsed prompt and response HTML before rendering - introduced fallback behavior when no prompts are defined - updated component structure to display prompt/response pairs consistently
1 parent bc4abcd commit 16b12c3

File tree

1 file changed

+64
-19
lines changed

1 file changed

+64
-19
lines changed

src/containers/ResponseDisplay/index.jsx

Lines changed: 64 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ import parse from 'html-react-parser';
1010

1111
import { selectors } from 'data/redux';
1212
import { fileUploadResponseOptions } from 'data/services/lms/constants';
13-
14-
import { getConfig } from '@edx/frontend-platform';
1513
import SubmissionFiles from './SubmissionFiles';
1614
import PreviewDisplay from './PreviewDisplay';
1715

@@ -27,13 +25,7 @@ export class ResponseDisplay extends React.Component {
2725
}
2826

2927
get textContents() {
30-
const { text } = this.props.response;
31-
32-
const formattedText = text
33-
.map((item) => item.replaceAll(/\.\.\/asset/g, `${getConfig().LMS_BASE_URL}/asset`))
34-
.map((item) => parse(this.purify.sanitize(item)));
35-
36-
return formattedText;
28+
return this.props.response.text.map(text => parse(this.purify.sanitize(text)));
3729
}
3830

3931
get submittedFiles() {
@@ -46,19 +38,60 @@ export class ResponseDisplay extends React.Component {
4638
);
4739
}
4840

41+
// New getter to extract prompts
42+
get prompts() {
43+
const raw = this.props.oraMetadata?.prompts || [];
44+
return raw.map(p => p.description || '');
45+
}
46+
47+
// New helper method
48+
sanitizeAndParse = (html = '') => parse(this.purify.sanitize(html));
49+
4950
render() {
51+
const textResponses = this.textContents || [];
52+
const { prompts } = this;
53+
5054
return (
5155
<div className="response-display">
52-
{this.allowFileUpload && <SubmissionFiles files={this.submittedFiles} data-testid="submission-files" />}
53-
{this.allowFileUpload && <PreviewDisplay files={this.submittedFiles} data-testid="allow-file-upload" />}
54-
{
55-
/* eslint-disable react/no-array-index-key */
56-
this.textContents.map((textContent, index) => (
57-
<Card key={index}>
58-
<Card.Section className="response-display-text-content" data-testid="response-display-text-content">{textContent}</Card.Section>
59-
</Card>
60-
))
61-
}
56+
{this.allowFileUpload && <SubmissionFiles files={this.submittedFiles} />}
57+
{this.allowFileUpload && <PreviewDisplay files={this.submittedFiles} />}
58+
59+
{/* Prompt → Response pairs */}
60+
{prompts.map((prompt, i) => {
61+
const answer = textResponses[i] || '';
62+
63+
return (
64+
<div key={prompt} className="prompt-response-pair my-5">
65+
{/* Prompt */}
66+
<Card className="mb-3">
67+
<Card.Header title={<strong>Prompt {i + 1}</strong>} />
68+
<Card.Section className="prompt-text">
69+
{this.sanitizeAndParse(prompt)}
70+
</Card.Section>
71+
</Card>
72+
73+
{/* Learner Response */}
74+
<Card>
75+
<Card.Header title="Learner Response" />
76+
<Card.Section className="response-display-text-content">
77+
{answer ? (
78+
this.sanitizeAndParse(answer)
79+
) : (
80+
<em className="text-muted">No response submitted for this prompt.</em>
81+
)}
82+
</Card.Section>
83+
</Card>
84+
</div>
85+
);
86+
})}
87+
88+
{/* only shows if no prompts */}
89+
{prompts.length === 0
90+
&& textResponses.map((text) => (
91+
<Card key={text} className="my-3">
92+
<Card.Section>{this.sanitizeAndParse(text)}</Card.Section>
93+
</Card>
94+
))}
6295
</div>
6396
);
6497
}
@@ -69,6 +102,8 @@ ResponseDisplay.defaultProps = {
69102
text: [],
70103
files: [],
71104
},
105+
// Add default
106+
oraMetadata: { prompts: [] },
72107
fileUploadResponseConfig: fileUploadResponseOptions.none,
73108
};
74109
ResponseDisplay.propTypes = {
@@ -80,13 +115,23 @@ ResponseDisplay.propTypes = {
80115
}),
81116
).isRequired,
82117
}),
118+
// Add PropTypes
119+
oraMetadata: PropTypes.shape({
120+
prompts: PropTypes.arrayOf(
121+
PropTypes.shape({
122+
description: PropTypes.string,
123+
}),
124+
),
125+
}),
83126
fileUploadResponseConfig: PropTypes.oneOf(
84127
Object.values(fileUploadResponseOptions),
85128
),
86129
};
87130

88131
export const mapStateToProps = (state) => ({
89132
response: selectors.grading.selected.response(state),
133+
// Add oraMetadata + use correct selector
134+
oraMetadata: selectors.app.oraMetadata(state),
90135
fileUploadResponseConfig: selectors.app.ora.fileUploadResponseConfig(state),
91136
});
92137

0 commit comments

Comments
 (0)