l-min-components 1.7.1406 → 1.7.1407
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/components/reportsComponents/fullAnalysis/components/InlineClampedText.jsx +35 -62
- package/src/components/reportsComponents/fullAnalysis/components/SpeechAnalysis.jsx +3 -3
- package/src/components/reportsComponents/fullAnalysis/index.jsx +22 -19
- package/src/components/reportsComponents/reportQuestions/api/index.jsx +114 -0
- package/src/components/reportsComponents/reportQuestions/components/comment.jsx +98 -5
- package/src/components/reportsComponents/reportQuestions/components/modals/gradingModal.jsx +16 -2
- package/src/components/reportsComponents/reportQuestions/components/style/comment.style.jsx +4 -0
- package/src/components/reportsComponents/reportQuestions/contants.jsx +22 -16
- package/src/components/reportsComponents/reportQuestions/index.jsx +46 -5
package/package.json
CHANGED
|
@@ -1,78 +1,51 @@
|
|
|
1
|
-
import React, { useState } from "react";
|
|
2
|
-
import Truncate from "react-truncate";
|
|
1
|
+
import React, { useState, useRef, useEffect } from "react";
|
|
3
2
|
import styled from "styled-components";
|
|
4
3
|
|
|
5
4
|
const InlineClampedText = ({ text }) => {
|
|
6
5
|
const [isExpanded, setIsExpanded] = useState(false);
|
|
7
|
-
const [
|
|
6
|
+
const [isClamped, setIsClamped] = useState(false);
|
|
7
|
+
const textRef = useRef(null);
|
|
8
|
+
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
const el = textRef.current;
|
|
11
|
+
if (el) {
|
|
12
|
+
// Check if the text is clamped by comparing scrollHeight and offsetHeight
|
|
13
|
+
setIsClamped(el.scrollHeight > el.offsetHeight);
|
|
14
|
+
}
|
|
15
|
+
}, [text]);
|
|
8
16
|
|
|
9
17
|
return (
|
|
10
18
|
<Container>
|
|
11
|
-
{
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
<span
|
|
19
|
-
onClick={() => setIsExpanded(true)}
|
|
20
|
-
style={{
|
|
21
|
-
cursor: "pointer",
|
|
22
|
-
color: "#00C2C2",
|
|
23
|
-
fontSize: "14px",
|
|
24
|
-
}}
|
|
25
|
-
>
|
|
26
|
-
See more
|
|
27
|
-
</span>
|
|
28
|
-
</>
|
|
29
|
-
) : (
|
|
30
|
-
""
|
|
31
|
-
)
|
|
32
|
-
}
|
|
33
|
-
onTruncate={(trunc) => setTruncated(trunc)}
|
|
34
|
-
>
|
|
35
|
-
<span
|
|
36
|
-
style={{
|
|
37
|
-
color: "#4A4D4D",
|
|
38
|
-
fontSize: "14px",
|
|
39
|
-
}}
|
|
40
|
-
>
|
|
41
|
-
{text}
|
|
42
|
-
</span>
|
|
43
|
-
</Truncate>
|
|
44
|
-
) : (
|
|
45
|
-
<>
|
|
46
|
-
<span
|
|
47
|
-
style={{
|
|
48
|
-
color: "#4A4D4D",
|
|
49
|
-
fontSize: "14px",
|
|
50
|
-
}}
|
|
51
|
-
>
|
|
52
|
-
{text}
|
|
53
|
-
</span>{" "}
|
|
54
|
-
{truncated && (
|
|
55
|
-
<span
|
|
56
|
-
onClick={() => setIsExpanded(false)}
|
|
57
|
-
style={{
|
|
58
|
-
cursor: "pointer",
|
|
59
|
-
color: "#00C2C2",
|
|
60
|
-
fontSize: "14px",
|
|
61
|
-
}}
|
|
62
|
-
>
|
|
63
|
-
Show less
|
|
64
|
-
</span>
|
|
65
|
-
)}
|
|
66
|
-
</>
|
|
19
|
+
<TextWrapper isExpanded={isExpanded} ref={textRef}>
|
|
20
|
+
{text}
|
|
21
|
+
</TextWrapper>
|
|
22
|
+
{isClamped && (
|
|
23
|
+
<Toggle onClick={() => setIsExpanded(!isExpanded)}>
|
|
24
|
+
{isExpanded ? "Show less" : "See more"}
|
|
25
|
+
</Toggle>
|
|
67
26
|
)}
|
|
68
27
|
</Container>
|
|
69
28
|
);
|
|
70
29
|
};
|
|
71
30
|
|
|
72
31
|
const Container = styled.div`
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
32
|
+
font-size: 14px;
|
|
33
|
+
color: #4a4d4d;
|
|
34
|
+
`;
|
|
35
|
+
|
|
36
|
+
const TextWrapper = styled.div`
|
|
37
|
+
overflow: hidden;
|
|
38
|
+
display: -webkit-box;
|
|
39
|
+
-webkit-line-clamp: ${(props) => (props.isExpanded ? "unset" : 2)};
|
|
40
|
+
-webkit-box-orient: vertical;
|
|
41
|
+
white-space: normal;
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
const Toggle = styled.span`
|
|
45
|
+
color: #00c2c2;
|
|
46
|
+
font-size: 14px;
|
|
47
|
+
cursor: pointer;
|
|
48
|
+
margin-left: 5px;
|
|
76
49
|
`;
|
|
77
50
|
|
|
78
51
|
export default InlineClampedText;
|
|
@@ -17,7 +17,7 @@ import PenIcon from "../icons/pen";
|
|
|
17
17
|
import Mircophone from "../icons/mircophone";
|
|
18
18
|
import { Se, Tr } from "react-flags-select";
|
|
19
19
|
import Table from "./table";
|
|
20
|
-
import TranslateDropdown from "./translateDropdown";
|
|
20
|
+
// import TranslateDropdown from "./translateDropdown";
|
|
21
21
|
import { Progress } from "rsuite";
|
|
22
22
|
import ClarityItem from "./ClarityItem";
|
|
23
23
|
import InlineClampedText from "./InlineClampedText";
|
|
@@ -119,7 +119,7 @@ const SpeechAnalysis = ({ Aidata }) => {
|
|
|
119
119
|
<span>Grade</span>
|
|
120
120
|
<div className="space-between">
|
|
121
121
|
<span>Feedback</span>
|
|
122
|
-
<TranslateDropdown />
|
|
122
|
+
{/* <TranslateDropdown /> */}
|
|
123
123
|
</div>
|
|
124
124
|
</div>
|
|
125
125
|
<div className="table_row">
|
|
@@ -290,7 +290,7 @@ const SpeechAnalysis = ({ Aidata }) => {
|
|
|
290
290
|
|
|
291
291
|
<div className="space-between">
|
|
292
292
|
<span>Feedback</span>
|
|
293
|
-
<TranslateDropdown />
|
|
293
|
+
{/* <TranslateDropdown /> */}
|
|
294
294
|
</div>
|
|
295
295
|
</div>
|
|
296
296
|
<div className="table_row">
|
|
@@ -127,25 +127,28 @@ const FullAnalysis = ({ data, onClose }) => {
|
|
|
127
127
|
</p>
|
|
128
128
|
</ProgressCircleSection>
|
|
129
129
|
<ul>
|
|
130
|
-
{data?.models?.map((model) =>
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
<
|
|
134
|
-
<
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
130
|
+
{data?.models?.map((model) => {
|
|
131
|
+
if (model?.id === "logic_evaluation") return null;
|
|
132
|
+
return (
|
|
133
|
+
<li key={model?.id}>
|
|
134
|
+
<p>{`${model?.label} point`}</p>
|
|
135
|
+
<div style={{ backgroundColor: model?.bgColor }}>
|
|
136
|
+
<span style={{ color: model?.primaryColor }}>
|
|
137
|
+
{model?.score || 0}%
|
|
138
|
+
</span>
|
|
139
|
+
<Progress.Line
|
|
140
|
+
percent={model?.score || 0}
|
|
141
|
+
strokeWidth={4}
|
|
142
|
+
trailWidth={4}
|
|
143
|
+
strokeColor={model?.primaryColor}
|
|
144
|
+
trailColor={"#fff"}
|
|
145
|
+
showInfo={false}
|
|
146
|
+
style={{ width: "100%" }}
|
|
147
|
+
/>
|
|
148
|
+
</div>
|
|
149
|
+
</li>
|
|
150
|
+
);
|
|
151
|
+
})}
|
|
149
152
|
</ul>
|
|
150
153
|
</ProgressSidebar>
|
|
151
154
|
{selectedModel?.id === "speech_analysis" && (
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import useAxios from "axios-hooks";
|
|
2
|
+
|
|
3
|
+
const useApi = () => {
|
|
4
|
+
const [{ ...addCommentData }, addComment] = useAxios(
|
|
5
|
+
{
|
|
6
|
+
method: "POST",
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
manual: true,
|
|
10
|
+
}
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
const handleAddComment = async (
|
|
14
|
+
question_activity_id,
|
|
15
|
+
test_id,
|
|
16
|
+
data,
|
|
17
|
+
enterprise_id
|
|
18
|
+
) => {
|
|
19
|
+
try {
|
|
20
|
+
const url = enterprise_id
|
|
21
|
+
? `/learn/v1/instructor/${enterprise_id}/tests/${test_id}/add_comment/${question_activity_id}/`
|
|
22
|
+
: `/learn/v1/instructor/tests/${test_id}/add_comment/${question_activity_id}/`;
|
|
23
|
+
return await addComment({
|
|
24
|
+
url,
|
|
25
|
+
data,
|
|
26
|
+
});
|
|
27
|
+
} catch (err) {
|
|
28
|
+
console.log(err);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const [{ ...gradeQuestionData }, gradeQuestion] = useAxios(
|
|
33
|
+
{
|
|
34
|
+
method: "POST",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
manual: true,
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const handleGradeQuestion = async (
|
|
42
|
+
question_activity_id,
|
|
43
|
+
session_id,
|
|
44
|
+
data,
|
|
45
|
+
enterprise_id
|
|
46
|
+
) => {
|
|
47
|
+
try {
|
|
48
|
+
const url = enterprise_id
|
|
49
|
+
? `/learn/v1/instructor/${enterprise_id}/tests/${question_activity_id}/submit_score/${session_id}/`
|
|
50
|
+
: `/learn/v1/instructor/tests/${question_activity_id}/submit_score/${session_id}/`;
|
|
51
|
+
return await gradeQuestion({
|
|
52
|
+
url,
|
|
53
|
+
data: {
|
|
54
|
+
...data,
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
} catch (err) {
|
|
58
|
+
console.log(err);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const [{ ...deleteCommentData }, deleteComment] = useAxios(
|
|
63
|
+
{
|
|
64
|
+
method: "POST",
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
manual: true,
|
|
68
|
+
}
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const handleDeleteComment = async (
|
|
72
|
+
question_activity_id,
|
|
73
|
+
test_id,
|
|
74
|
+
index,
|
|
75
|
+
enterprise_id
|
|
76
|
+
) => {
|
|
77
|
+
try {
|
|
78
|
+
const url = enterprise_id
|
|
79
|
+
? `/learn/v1/instructor/${enterprise_id}/tests/${test_id}/delete_comment/${question_activity_id}/?index=${index}`
|
|
80
|
+
: `/learn/v1/instructor/tests/${test_id}/delete_comment/${question_activity_id}/?index=${index}`;
|
|
81
|
+
return await deleteComment({
|
|
82
|
+
url,
|
|
83
|
+
});
|
|
84
|
+
} catch (err) {
|
|
85
|
+
console.log(err);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
const [{ ...uploadData }, upload] = useAxios(
|
|
89
|
+
{
|
|
90
|
+
method: "POST",
|
|
91
|
+
},
|
|
92
|
+
{ manual: true }
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
const handleUpload = async (data) => {
|
|
96
|
+
return await upload({
|
|
97
|
+
url: "/media/v1/instructor/files/",
|
|
98
|
+
data,
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
addCommentData,
|
|
104
|
+
handleAddComment,
|
|
105
|
+
handleGradeQuestion,
|
|
106
|
+
gradeQuestionData,
|
|
107
|
+
deleteCommentData,
|
|
108
|
+
handleDeleteComment,
|
|
109
|
+
handleUpload,
|
|
110
|
+
uploadData,
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
export default useApi;
|
|
@@ -16,22 +16,38 @@ import DeleteIcon from "../../../../assets/svg/delete-icon";
|
|
|
16
16
|
import moment from "moment";
|
|
17
17
|
import ResponseAudio from "./responseAudio";
|
|
18
18
|
import DeleteModal from "./modals/deleteModal";
|
|
19
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
AudioWaveComponent,
|
|
21
|
+
FullPageLoader,
|
|
22
|
+
OutletContext,
|
|
23
|
+
useAudioPlayer,
|
|
24
|
+
} from "../../..";
|
|
20
25
|
import { CloseIcon } from "../../../header/assets/svg/close";
|
|
21
26
|
import classNames from "classnames";
|
|
22
27
|
import { useRecorder } from "react-microphone-recorder";
|
|
23
28
|
import PlayIcon from "../../../../assets/svg/playIcon";
|
|
24
29
|
import styled from "styled-components";
|
|
25
30
|
import { FaPause } from "react-icons/fa";
|
|
31
|
+
import useApi from "../api";
|
|
26
32
|
/**
|
|
27
33
|
* @param {Object} props
|
|
28
34
|
* @param {boolean} props.editMode
|
|
29
35
|
* @returns {React.ReactNode}
|
|
30
36
|
*/
|
|
31
|
-
const Comment = ({ editMode = false, data,
|
|
37
|
+
const Comment = ({ editMode = false, data, testId, questionData, setData }) => {
|
|
32
38
|
const { affiliateAccount } = useContext(OutletContext);
|
|
33
39
|
const [toggleDelete, setToggleDelete] = useState(false);
|
|
34
40
|
const [showForm, setShowForm] = useState(null);
|
|
41
|
+
const [value, setValue] = useState("");
|
|
42
|
+
const {
|
|
43
|
+
handleAddComment,
|
|
44
|
+
addCommentData,
|
|
45
|
+
handleDeleteComment,
|
|
46
|
+
deleteCommentData,
|
|
47
|
+
handleUpload,
|
|
48
|
+
uploadData,
|
|
49
|
+
} = useApi();
|
|
50
|
+
const enterpriseId = affiliateAccount?.id;
|
|
35
51
|
|
|
36
52
|
const {
|
|
37
53
|
startRecording,
|
|
@@ -41,7 +57,6 @@ const Comment = ({ editMode = false, data, accountType }) => {
|
|
|
41
57
|
resetRecording,
|
|
42
58
|
recordingState,
|
|
43
59
|
} = useRecorder();
|
|
44
|
-
console.log(data);
|
|
45
60
|
|
|
46
61
|
if (!editMode && !data) return;
|
|
47
62
|
|
|
@@ -50,10 +65,76 @@ const Comment = ({ editMode = false, data, accountType }) => {
|
|
|
50
65
|
{ text: "Audio", icon: AudioIcon },
|
|
51
66
|
];
|
|
52
67
|
|
|
68
|
+
const handleComment = async () => {
|
|
69
|
+
if (!enterpriseId || !testId || !questionData?.question_activity_id) return;
|
|
70
|
+
|
|
71
|
+
if (showForm === "Text") {
|
|
72
|
+
const data = { data: { data: { type: "text", text: value } } };
|
|
73
|
+
const res = await handleAddComment(
|
|
74
|
+
questionData?.question_activity_id,
|
|
75
|
+
testId,
|
|
76
|
+
data,
|
|
77
|
+
enterpriseId
|
|
78
|
+
);
|
|
79
|
+
if (res?.data) {
|
|
80
|
+
const comment = res?.data?.data?.answer?.comments?.[0];
|
|
81
|
+
setData(comment);
|
|
82
|
+
setShowForm(null);
|
|
83
|
+
setValue("");
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
const formData = new FormData();
|
|
87
|
+
formData.append("upload", audioFile);
|
|
88
|
+
const resMedia = await handleUpload(formData);
|
|
89
|
+
const media = resMedia?.data?.results?.[0];
|
|
90
|
+
if (media) {
|
|
91
|
+
const data = { data: { data: { type: "audio", audio: media } } };
|
|
92
|
+
const res = await handleAddComment(
|
|
93
|
+
questionData?.question_activity_id,
|
|
94
|
+
testId,
|
|
95
|
+
data,
|
|
96
|
+
enterpriseId
|
|
97
|
+
);
|
|
98
|
+
if (res?.data) {
|
|
99
|
+
const comment = res?.data?.data?.answer?.comments?.[0];
|
|
100
|
+
setData(comment);
|
|
101
|
+
setShowForm(null);
|
|
102
|
+
resetRecording();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const disabled = showForm === "Text" ? !value : !audioFile;
|
|
109
|
+
|
|
110
|
+
const handleDelete = async () => {
|
|
111
|
+
if (!enterpriseId || !testId || !questionData?.question_activity_id) return;
|
|
112
|
+
|
|
113
|
+
const res = await handleDeleteComment(
|
|
114
|
+
questionData?.question_activity_id,
|
|
115
|
+
testId,
|
|
116
|
+
0,
|
|
117
|
+
enterpriseId
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
if (res?.data) {
|
|
121
|
+
setData(null);
|
|
122
|
+
setToggleDelete(false);
|
|
123
|
+
setValue("");
|
|
124
|
+
setShowForm(null);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
console.log(data);
|
|
129
|
+
|
|
53
130
|
return (
|
|
54
131
|
<CommentContainer>
|
|
132
|
+
{(addCommentData?.loading ||
|
|
133
|
+
deleteCommentData?.loading ||
|
|
134
|
+
uploadData?.loading) && <FullPageLoader fixed hasBackground />}
|
|
55
135
|
{toggleDelete && (
|
|
56
136
|
<DeleteModal
|
|
137
|
+
onClick={handleDelete}
|
|
57
138
|
close={() => {
|
|
58
139
|
setToggleDelete(false);
|
|
59
140
|
}}
|
|
@@ -126,7 +207,13 @@ const Comment = ({ editMode = false, data, accountType }) => {
|
|
|
126
207
|
<>
|
|
127
208
|
<CommentContentForm>
|
|
128
209
|
{showForm === "Text" && (
|
|
129
|
-
<textarea
|
|
210
|
+
<textarea
|
|
211
|
+
placeholder="Input comment here"
|
|
212
|
+
value={value}
|
|
213
|
+
onChange={(e) => {
|
|
214
|
+
setValue(e?.target?.value);
|
|
215
|
+
}}
|
|
216
|
+
/>
|
|
130
217
|
)}
|
|
131
218
|
{showForm === "Audio" && (
|
|
132
219
|
<AudioRecordPlayer
|
|
@@ -161,7 +248,13 @@ const Comment = ({ editMode = false, data, accountType }) => {
|
|
|
161
248
|
</li>
|
|
162
249
|
))}
|
|
163
250
|
</ul>
|
|
164
|
-
<button
|
|
251
|
+
<button
|
|
252
|
+
className="sm-btn"
|
|
253
|
+
disabled={disabled}
|
|
254
|
+
onClick={handleComment}
|
|
255
|
+
>
|
|
256
|
+
Send
|
|
257
|
+
</button>
|
|
165
258
|
</CommentContentAction>
|
|
166
259
|
</>
|
|
167
260
|
)}
|
|
@@ -4,7 +4,7 @@ import styled from "styled-components";
|
|
|
4
4
|
import Radio from "../radio";
|
|
5
5
|
import ButtonComponent from "../../../../button";
|
|
6
6
|
|
|
7
|
-
const GradingModal = ({ aiValue, onClose }) => {
|
|
7
|
+
const GradingModal = ({ aiValue, onClose, setScore }) => {
|
|
8
8
|
const [selected, setSelected] = useState("manually");
|
|
9
9
|
const [value, setValue] = useState("");
|
|
10
10
|
|
|
@@ -12,8 +12,18 @@ const GradingModal = ({ aiValue, onClose }) => {
|
|
|
12
12
|
setValue("");
|
|
13
13
|
}, [selected]);
|
|
14
14
|
|
|
15
|
+
const numberValue = Number(value || 0);
|
|
16
|
+
const disable = selected === "manually" && (numberValue > 100 || !value);
|
|
17
|
+
|
|
15
18
|
const isNumbter = typeof aiValue === "number";
|
|
16
19
|
|
|
20
|
+
const handleSetValue = () => {
|
|
21
|
+
setScore?.({
|
|
22
|
+
score_method: selected === "manually" ? "MANUAL" : "AI",
|
|
23
|
+
score: selected === "manually" ? numberValue : aiValue,
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
|
|
17
27
|
return (
|
|
18
28
|
<Container>
|
|
19
29
|
<Wrapper>
|
|
@@ -66,7 +76,11 @@ const GradingModal = ({ aiValue, onClose }) => {
|
|
|
66
76
|
)}
|
|
67
77
|
</div>
|
|
68
78
|
</TopSection>
|
|
69
|
-
<ButtonComponent
|
|
79
|
+
<ButtonComponent
|
|
80
|
+
text="Save score"
|
|
81
|
+
disabled={disable}
|
|
82
|
+
onClick={handleSetValue}
|
|
83
|
+
/>
|
|
70
84
|
</Content>
|
|
71
85
|
</Wrapper>
|
|
72
86
|
</Container>
|
|
@@ -248,8 +248,8 @@ const essayUnscripted = {
|
|
|
248
248
|
};
|
|
249
249
|
|
|
250
250
|
const soundPlay = {
|
|
251
|
-
question_id:
|
|
252
|
-
question_activity_id:
|
|
251
|
+
question_id: 3078,
|
|
252
|
+
question_activity_id: 8384,
|
|
253
253
|
position_index: 0,
|
|
254
254
|
title: "Say the sentence",
|
|
255
255
|
type: "SOUND_PLAY",
|
|
@@ -265,36 +265,42 @@ const soundPlay = {
|
|
|
265
265
|
instruction: "Say the sentence",
|
|
266
266
|
},
|
|
267
267
|
answer: {
|
|
268
|
-
session_id: "
|
|
268
|
+
session_id: "17c9403e6b2c4761a06bf1ac22fffaf2",
|
|
269
269
|
attempt_index: 1,
|
|
270
270
|
token_claimed: 0,
|
|
271
271
|
score: null,
|
|
272
272
|
marked: false,
|
|
273
273
|
expire_at: null,
|
|
274
|
-
created_at: "2025-07-
|
|
274
|
+
created_at: "2025-07-09T11:28:33.281076Z",
|
|
275
275
|
grading_date: null,
|
|
276
276
|
data: {
|
|
277
277
|
type: "SOUND_PLAY",
|
|
278
|
-
session_id: "
|
|
279
|
-
submited_datetime: "2025-07-
|
|
278
|
+
session_id: "b269deece28047f",
|
|
279
|
+
submited_datetime: "2025-07-09T09:57:10.44195Z",
|
|
280
280
|
audio: {
|
|
281
|
-
id: "
|
|
282
|
-
url: "https://dev-117782726-api.learngual.com/media/v1/files/
|
|
281
|
+
id: "1c06b5d866054d9fba5d67d14eeff436",
|
|
282
|
+
url: "https://dev-117782726-api.learngual.com/media/v1/files/1c06b5d866054d9fba5d67d14eeff436/stream/",
|
|
283
283
|
stream_url: null,
|
|
284
284
|
mimetype: "audio/mpeg",
|
|
285
|
-
size:
|
|
286
|
-
created_at: "2025-07-
|
|
287
|
-
updated_at: "2025-07-
|
|
285
|
+
size: 54500.0,
|
|
286
|
+
created_at: "2025-07-09T11:28:23.930419Z",
|
|
287
|
+
updated_at: "2025-07-14T06:00:38.441656Z",
|
|
288
288
|
uploaded_media_url: null,
|
|
289
289
|
convertion_status: "DONE",
|
|
290
290
|
},
|
|
291
291
|
},
|
|
292
|
-
comments:
|
|
292
|
+
comments: [],
|
|
293
293
|
},
|
|
294
|
-
score: 0,
|
|
295
|
-
ai_score:
|
|
296
|
-
grading_data: {
|
|
297
|
-
|
|
294
|
+
score: 100.0,
|
|
295
|
+
ai_score: 100.0,
|
|
296
|
+
grading_data: {
|
|
297
|
+
base_url: "https://dev-117782726-api.learngual.com/",
|
|
298
|
+
grader_id: "e4b92c77e5",
|
|
299
|
+
session_id: "17c9403e6b2c4761a06bf1ac22fffaf2",
|
|
300
|
+
score: 100.0,
|
|
301
|
+
grade_method: "AI",
|
|
302
|
+
},
|
|
303
|
+
grade_method: "AI",
|
|
298
304
|
suggested_score: null,
|
|
299
305
|
};
|
|
300
306
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useEffect, useState } from "react";
|
|
1
|
+
import React, { useContext, useEffect, useState } from "react";
|
|
2
2
|
import constants, {
|
|
3
3
|
aiWordSample,
|
|
4
4
|
sampleResponse,
|
|
@@ -37,6 +37,9 @@ import DialogueUnscripted from "./questions/dialogueUnscripted";
|
|
|
37
37
|
import GradingModal from "./components/modals/gradingModal";
|
|
38
38
|
import classNames from "classnames";
|
|
39
39
|
import FullAnalysis from "../fullAnalysis";
|
|
40
|
+
import useApi from "./api";
|
|
41
|
+
import FullPageLoader from "../../fullPageLoader";
|
|
42
|
+
import { OutletContext } from "../..";
|
|
40
43
|
|
|
41
44
|
/**
|
|
42
45
|
* @param {Object} props
|
|
@@ -52,10 +55,15 @@ const ReportQuestions = ({
|
|
|
52
55
|
data,
|
|
53
56
|
AiData,
|
|
54
57
|
onClose,
|
|
58
|
+
testId,
|
|
55
59
|
}) => {
|
|
56
60
|
const [comment, setComment] = useState(null);
|
|
61
|
+
const [intructorScore, setInstructorScore] = useState(0);
|
|
57
62
|
const [toggleGrade, setToggleGrade] = useState(false);
|
|
58
63
|
const [toggle, setToggle] = useState(null);
|
|
64
|
+
const { affiliateAccount } = useContext(OutletContext);
|
|
65
|
+
const enterpriseId = affiliateAccount?.id;
|
|
66
|
+
const { handleGradeQuestion, gradeQuestionData } = useApi();
|
|
59
67
|
const question = constants.questions.find(
|
|
60
68
|
(question) => question.value === questionType
|
|
61
69
|
);
|
|
@@ -63,7 +71,32 @@ const ReportQuestions = ({
|
|
|
63
71
|
|
|
64
72
|
useEffect(() => {
|
|
65
73
|
if (commentData?.length) setComment(commentData?.[0]);
|
|
66
|
-
}, [commentData]);
|
|
74
|
+
}, [commentData, data?.question_id]);
|
|
75
|
+
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
if (data?.question_id) {
|
|
78
|
+
setInstructorScore(data?.score);
|
|
79
|
+
}
|
|
80
|
+
}, [data?.question_id]);
|
|
81
|
+
|
|
82
|
+
const handleScore = async (value) => {
|
|
83
|
+
if (
|
|
84
|
+
!data?.question_activity_id ||
|
|
85
|
+
!enterpriseId ||
|
|
86
|
+
!data?.answer?.session_id
|
|
87
|
+
)
|
|
88
|
+
return;
|
|
89
|
+
const res = await handleGradeQuestion(
|
|
90
|
+
data?.question_activity_id,
|
|
91
|
+
data?.answer?.session_id,
|
|
92
|
+
value,
|
|
93
|
+
enterpriseId
|
|
94
|
+
);
|
|
95
|
+
if (res?.data) {
|
|
96
|
+
setInstructorScore(value?.score);
|
|
97
|
+
setToggleGrade(false);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
67
100
|
|
|
68
101
|
if (toggle) {
|
|
69
102
|
return (
|
|
@@ -75,10 +108,14 @@ const ReportQuestions = ({
|
|
|
75
108
|
/>
|
|
76
109
|
);
|
|
77
110
|
}
|
|
111
|
+
|
|
78
112
|
return (
|
|
79
113
|
<Container>
|
|
114
|
+
{gradeQuestionData?.loading && <FullPageLoader fixed hasBackground />}
|
|
80
115
|
{toggleGrade && (
|
|
81
116
|
<GradingModal
|
|
117
|
+
aiValue={data?.ai_score}
|
|
118
|
+
setScore={handleScore}
|
|
82
119
|
onClose={() => {
|
|
83
120
|
setToggleGrade(false);
|
|
84
121
|
}}
|
|
@@ -96,7 +133,7 @@ const ReportQuestions = ({
|
|
|
96
133
|
<ScoreHeader>
|
|
97
134
|
{accountType === "personal" ? (
|
|
98
135
|
<ScoreBadge>
|
|
99
|
-
Instructor’s score: <span>{parseInt(
|
|
136
|
+
Instructor’s score: <span>{parseInt(intructorScore || 0)}%</span>
|
|
100
137
|
</ScoreBadge>
|
|
101
138
|
) : (
|
|
102
139
|
<>
|
|
@@ -121,7 +158,8 @@ const ReportQuestions = ({
|
|
|
121
158
|
accountType === "instructor-affiliate"
|
|
122
159
|
}
|
|
123
160
|
>
|
|
124
|
-
Instructor’s score:
|
|
161
|
+
Instructor’s score:{" "}
|
|
162
|
+
<span>{parseInt(intructorScore || 0)}%</span>
|
|
125
163
|
</ScoreBadge>
|
|
126
164
|
{(accountType === "instructor-personal" ||
|
|
127
165
|
accountType === "instructor-affiliate") && (
|
|
@@ -215,6 +253,9 @@ const ReportQuestions = ({
|
|
|
215
253
|
|
|
216
254
|
<Comment
|
|
217
255
|
data={comment}
|
|
256
|
+
testId={testId}
|
|
257
|
+
questionData={data}
|
|
258
|
+
setData={setComment}
|
|
218
259
|
editMode={
|
|
219
260
|
accountType === "instructor-personal" ||
|
|
220
261
|
accountType === "instructor-affiliate"
|
|
@@ -223,7 +264,7 @@ const ReportQuestions = ({
|
|
|
223
264
|
{(accountType === "instructor-personal" ||
|
|
224
265
|
accountType === "instructor-affiliate") && (
|
|
225
266
|
<QuestionFooter>
|
|
226
|
-
<ButtonComponent text="Save" />
|
|
267
|
+
<ButtonComponent text="Save" onClick={onClose} />
|
|
227
268
|
</QuestionFooter>
|
|
228
269
|
)}
|
|
229
270
|
</Content>
|