Skip to content

Commit af4a008

Browse files
authored
Merge pull request #42 from CPSECapstone/studentOverviewBreakdown
Student overview breakdown
2 parents ca27af2 + b3ea0ce commit af4a008

File tree

6 files changed

+451
-48
lines changed

6 files changed

+451
-48
lines changed

src/Components/CourseHome/CourseHome.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@ function CourseHome() {
9393
<InputLabel>View As</InputLabel>
9494
<Select
9595
inputProps={{ 'data-testid': 'courseHomeViewSelector' }}
96-
// data-testid="courseHomeViewSelector"
9796
value={viewType}
9897
onChange={handleChange}
9998
classes={{ root: classes.menuItem }}

src/Components/StudentOverview/LTStudentViewTable.tsx

Lines changed: 97 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,44 @@
1+
/* eslint-disable @typescript-eslint/no-explicit-any */
2+
/* eslint-disable array-callback-return */
3+
/* eslint-disable @typescript-eslint/restrict-template-expressions */
4+
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
5+
/* eslint-disable no-param-reassign */
6+
/* eslint-disable @typescript-eslint/no-unsafe-call */
7+
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
8+
/* eslint-disable no-restricted-syntax */
19
import { useHistory } from 'react-router-dom';
10+
import { useQuery } from '@apollo/client';
11+
import React, { useState } from 'react';
12+
import { ToggleButton, ToggleButtonGroup } from '@material-ui/lab';
213
import TableComponent from '../TableComponent/TableComponent';
3-
import { useProgressOverviewQuery, UserProgress } from '../../__generated__/types';
14+
import {
15+
CmStudentFieldsFragment,
16+
Target,
17+
useClassMissionMasteryQuery,
18+
} from '../../__generated__/types';
19+
import { LIST_TARGETS_BY_COURSE } from '../../hooks/ListTargetsByCourse';
20+
import SelectedLTStudentViewTable from './SelectedLTStudentViewTable';
421

522
function LTStudentViewTable() {
6-
const { data: progressData } = useProgressOverviewQuery({
7-
variables: {
8-
course: 'Integrated Science',
9-
},
10-
});
23+
const { data: missionMasteryData } = useClassMissionMasteryQuery();
24+
25+
const [selectedLT, setSlectedLT] = useState<string | null>(null);
26+
27+
const handleLTSelection = (
28+
event: React.MouseEvent<HTMLElement>,
29+
newSelectedLT: string | null
30+
) => {
31+
setSlectedLT(newSelectedLT);
32+
};
1133

1234
const history = useHistory();
1335

36+
const { data: courseTargets } = useQuery(LIST_TARGETS_BY_COURSE);
37+
38+
if (!courseTargets) {
39+
return <div />;
40+
}
41+
1442
const rowClicked = (userName: string) => {
1543
history.push({
1644
pathname: '/singleStudentMasteryOverview',
@@ -19,31 +47,30 @@ function LTStudentViewTable() {
1947
};
2048

2149
const data: any[] = [];
22-
progressData?.progressOverview.userProgress.map((userProgress: UserProgress) =>
23-
data.push({
24-
row: {
25-
section: 1,
26-
name: userProgress.userName,
27-
recent: {
28-
status:
29-
userProgress.progress.length !== 0
30-
? userProgress.progress[userProgress.progress.length - 1].taskId
31-
: '',
32-
style: {
33-
backgroundColor:
34-
userProgress.progress.length !== 0
35-
? userProgress.progress[userProgress.progress.length - 1].status
36-
? '#00b300'
37-
: '#ff6666'
38-
: '#a6a6a6',
39-
},
50+
missionMasteryData?.classMissionMastery?.studentMissionMasteryList.map(
51+
(studentMissionMastery: CmStudentFieldsFragment) =>
52+
data.push({
53+
row: {
54+
section: '1',
55+
name: `${studentMissionMastery.student.lastName} ${studentMissionMastery.student.firstName}`,
56+
team: studentMissionMastery.student.team,
57+
recent: studentMissionMastery.currentTaskName,
58+
average: '',
59+
progress: `${(studentMissionMastery.progress * 100).toFixed(1)}%`,
4060
},
41-
average: '',
42-
progress: '%',
43-
},
44-
})
61+
})
4562
);
4663

64+
// TODO remove when names are populated
65+
data.forEach((dataEntry) => {
66+
if (dataEntry.row.name.indexOf('null') !== -1) {
67+
dataEntry.row.name = 'Mary Lee';
68+
}
69+
if (dataEntry.row.name.length > 25) {
70+
dataEntry.row.name = dataEntry.row.name.substring(0, 25);
71+
}
72+
});
73+
4774
console.log(data);
4875

4976
const tableColumns = [
@@ -58,13 +85,13 @@ function LTStudentViewTable() {
5885
Header: 'Student',
5986
accessor: 'row.name',
6087
},
88+
{
89+
Header: 'Team',
90+
accessor: 'row.team',
91+
},
6192
{
6293
Header: 'Recent',
6394
accessor: 'row.recent',
64-
Cell: ({ value }: { value: any }) => {
65-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
66-
return <>{value.status} </>;
67-
},
6895
},
6996
{
7097
Header: 'Average',
@@ -83,27 +110,50 @@ function LTStudentViewTable() {
83110
columns: [],
84111
};
85112

113+
// Set handles the case of two learing targets with the same name
86114
const learningTargetSet = new Set();
87115

88-
if (progressData !== undefined) {
89-
for (const target of progressData?.progressOverview.targets) {
90-
data.map((row) => {
91-
row.row[target.targetName] = '';
116+
courseTargets.targets.map((target: Target) => {
117+
data.map((row: any) => {
118+
row.row[target.targetName] = '';
119+
});
120+
if (!learningTargetSet.has(target.targetName)) {
121+
learningTargetSet.add(target.targetName);
122+
learningTargetGroup.columns.push({
123+
Header: target.description,
124+
accessor: `row.${target.targetName}`,
92125
});
93-
if (!learningTargetSet.has(target.targetName)) {
94-
learningTargetSet.add(target.targetName);
95-
learningTargetGroup.columns.push({
96-
Header: target.targetName,
97-
accessor: `row.${target.targetName}`,
98-
});
99-
}
100126
}
101-
tableColumns.push(learningTargetGroup);
102-
}
127+
});
128+
tableColumns.push(learningTargetGroup);
103129

104130
return (
105-
<div className="base-table">
106-
<TableComponent columns={tableColumns} data={data} rowClickFunction={rowClicked} />
131+
<div>
132+
<ToggleButtonGroup
133+
value={selectedLT}
134+
style={{ paddingLeft: '20px' }}
135+
exclusive
136+
onChange={handleLTSelection}
137+
>
138+
{courseTargets.targets.map((target: Target) => {
139+
return (
140+
<ToggleButton value={target.targetId} style={{ width: '100px' }}>
141+
{target.targetName}
142+
</ToggleButton>
143+
);
144+
})}
145+
</ToggleButtonGroup>
146+
147+
{selectedLT === null ? (
148+
<div className="base-table">
149+
<TableComponent columns={tableColumns} data={data} rowClickFunction={rowClicked} />
150+
</div>
151+
) : (
152+
<SelectedLTStudentViewTable
153+
classMissionMastery={missionMasteryData?.classMissionMastery}
154+
selectedLTId={selectedLT}
155+
/>
156+
)}
107157
</div>
108158
);
109159
}
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
/* eslint-disable @typescript-eslint/no-unsafe-return */
2+
/* eslint-disable no-plusplus */
3+
/* eslint-disable array-callback-return */
4+
/* eslint-disable no-param-reassign */
5+
/* eslint-disable react/destructuring-assignment */
6+
/* eslint-disable @typescript-eslint/restrict-template-expressions */
7+
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
8+
/* eslint-disable @typescript-eslint/no-explicit-any */
9+
/* eslint-disable @typescript-eslint/no-unsafe-call */
10+
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
11+
import TableComponent from '../TableComponent/TableComponent';
12+
import {
13+
CmStudentFieldsFragment,
14+
CtmObjectiveMasteryFieldsFragment,
15+
CtmStudentObjectiveMasteryFieldsFragment,
16+
Objective,
17+
useClassTargetMasteryQuery,
18+
} from '../../__generated__/types';
19+
20+
function getUniqueObjectives(objectives: Objective[]): Objective[] {
21+
const uniqueObjectives: Objective[] = [];
22+
const objectiveNameSet = new Set();
23+
objectives.forEach((objective) => {
24+
if (!objectiveNameSet.has(objective.objectiveName)) {
25+
objectiveNameSet.add(objective.objectiveName);
26+
uniqueObjectives.push(objective);
27+
}
28+
});
29+
30+
return uniqueObjectives;
31+
}
32+
33+
function genObjectiveGroup(targetMasteryData: any): any {
34+
const objectiveGorup: any = {
35+
Header: 'Objectives',
36+
columns: [],
37+
};
38+
39+
const uniqueObjectives = getUniqueObjectives(
40+
targetMasteryData.classTargetMastery.target.objectives
41+
);
42+
43+
uniqueObjectives.forEach((objective) => {
44+
objectiveGorup.columns.push({
45+
Header: objective.objectiveName,
46+
accessor: `row.${objective.objectiveId}`,
47+
Cell: ({ value }: { value: any }) => {
48+
return <>{value.status} </>;
49+
},
50+
});
51+
});
52+
53+
return objectiveGorup;
54+
}
55+
56+
function SelectedLTStudentViewTable(classMissionMastery: any, selectedLTId: string | null) {
57+
const { data: targetMasteryData } = useClassTargetMasteryQuery({
58+
variables: {
59+
targetId: classMissionMastery.selectedLTId,
60+
},
61+
});
62+
63+
if (!targetMasteryData) {
64+
return <div />;
65+
}
66+
67+
// const history = useHistory();
68+
69+
// const rowClicked = (userName: string) => {
70+
// history.push({
71+
// pathname: '/singleStudentMasteryOverview',
72+
// state: { id: '', firstName: userName, lastName: ' ' },
73+
// });
74+
// };
75+
76+
const data: any[] = [];
77+
classMissionMastery?.classMissionMastery?.studentMissionMasteryList.map(
78+
(studentMissionMastery: CmStudentFieldsFragment) =>
79+
data.push({
80+
row: {
81+
section: '1',
82+
name: `${studentMissionMastery.student.lastName} ${studentMissionMastery.student.firstName}`,
83+
team: studentMissionMastery.student.team,
84+
recent: studentMissionMastery.currentTaskName,
85+
average: '',
86+
progress: `${(studentMissionMastery.progress * 100).toFixed(1)}%`,
87+
},
88+
})
89+
);
90+
91+
// // TODO remove when names are populated
92+
data.forEach((dataEntry) => {
93+
if (dataEntry.row.name.indexOf('null') !== -1) {
94+
dataEntry.row.name = 'Mary Lee';
95+
}
96+
if (dataEntry.row.name.length > 25) {
97+
dataEntry.row.name = dataEntry.row.name.substring(0, 25);
98+
}
99+
});
100+
101+
const tableColumns = [
102+
{
103+
Header: 'Student Information',
104+
columns: [
105+
{
106+
Header: 'Section',
107+
accessor: 'row.section',
108+
},
109+
{
110+
Header: 'Student',
111+
accessor: 'row.name',
112+
},
113+
{
114+
Header: 'Team',
115+
accessor: 'row.team',
116+
},
117+
{
118+
Header: 'Recent',
119+
accessor: 'row.recent',
120+
},
121+
{
122+
Header: 'Average',
123+
accessor: 'row.average',
124+
},
125+
{
126+
Header: 'Progress',
127+
accessor: 'row.progress',
128+
},
129+
],
130+
},
131+
];
132+
133+
const objectiveGroup = genObjectiveGroup(targetMasteryData);
134+
tableColumns.push(objectiveGroup);
135+
136+
// TODO This makes two massive assumptions:
137+
// One that classMissionMastery and classTargetMastery are in the exact same student order
138+
// Two a student either has entries for objective progress on all 5 objectives or none
139+
let index = 0;
140+
141+
const colorMap = new Map();
142+
colorMap.set('NOT_MASTERED', 'rgb(234, 153, 153)');
143+
colorMap.set('MASTERED', 'rgb(182, 215, 168)');
144+
colorMap.set('NOT_GRADED', 'rgb(191, 191, 191)');
145+
colorMap.set('NEARLY_MASTERED', 'rgb(230, 230, 0)');
146+
targetMasteryData.classTargetMastery.studentObjectiveMasteryList.map(
147+
(studentObjectiveMastery: CtmStudentObjectiveMasteryFieldsFragment) => {
148+
if (studentObjectiveMastery.objectiveMasteryList.length === 0) {
149+
objectiveGroup.columns.forEach((column: any) => {
150+
data[index].row[column.accessor.substring(4)] = '';
151+
});
152+
} else {
153+
studentObjectiveMastery.objectiveMasteryList.map(
154+
(objectiveMastery: CtmObjectiveMasteryFieldsFragment) => {
155+
data[index].row[objectiveMastery.objectiveId] = {
156+
status: objectiveMastery.mastery,
157+
style: {
158+
backgroundColor: colorMap.get(objectiveMastery.mastery),
159+
},
160+
};
161+
}
162+
);
163+
}
164+
index++;
165+
}
166+
);
167+
168+
return (
169+
<div>
170+
<div className="base-table">
171+
<TableComponent columns={tableColumns} data={data} />
172+
</div>
173+
</div>
174+
);
175+
}
176+
177+
export default SelectedLTStudentViewTable;

0 commit comments

Comments
 (0)