Skip to content

Commit c8e5c30

Browse files
Frontend MVP for Source Academy Rook (#1878)
Co-authored-by: YaleChen299 <[email protected]>
1 parent d158dbe commit c8e5c30

File tree

138 files changed

+6373
-2315
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

138 files changed

+6373
-2315
lines changed

.env.example

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1+
REACT_APP_DEPLOYMENT_NAME=Source Academy
2+
13
REACT_APP_BACKEND_URL=http://localhost:4000
24
REACT_APP_USE_BACKEND=TRUE
35
REACT_APP_PLAYGROUND_ONLY=FALSE
4-
REACT_APP_ENABLE_GAME=TRUE
5-
REACT_APP_ENABLE_ACHIEVEMENTS=TRUE
66
REACT_APP_ENABLE_GITHUB_ASSESSMENTS=TRUE
77

88
REACT_APP_URL_SHORTENER_SIGNATURE=
@@ -24,7 +24,7 @@ REACT_APP_OAUTH2_PROVIDER3_ENDPOINT=http://localhost:8000/login?provider=test&co
2424

2525
## LumiNUS example
2626
## the provider ID, must be URL-friendly (must match the backend configuration)
27-
# REACT_APP_OAUTH2_PROVIDER1=nusnet_id
27+
# REACT_APP_OAUTH2_PROVIDER1=luminus
2828
## the name shown on the login screen: "Log in with ..."
2929
# REACT_APP_OAUTH2_PROVIDER1_NAME=LumiNUS
3030
## the OAuth2 endpoint (which must include a client_id, as part of the OAuth2 specification)

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,8 @@ The frontend can be configured to disable itself (based on user's system time) d
8383

8484
#### Other configuration
8585

86+
1. `REACT_APP_DEPLOYMENT_NAME`: The name of the Source Academy deployment. This will be shown in the `/welcome` route. Defaults to 'Source Academy'.
8687
1. `REACT_APP_PLAYGROUND_ONLY`: Whether to build the "playground-only" version, which disables the Academy components, so only the Playground is available. This is what we deploy onto [GitHub Pages](https://source-academy.github.io).
87-
1. `REACT_APP_ENABLE_GAME`: Whether to enable the game. Off by default.
88-
1. `REACT_APP_ENABLE_ACHIEVEMENTS`: Whether to enable the incentives/achievements system. Off by default.
8988
1. `REACT_APP_ENABLE_GITHUB_ASSESSMENTS`: Whether to enable the GitHub Assessments feature. Off by default.
9089

9190
## Development

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
"react-konva": "^17.0.2-4",
6969
"react-latex-next": "^2.0.0",
7070
"react-mde": "^11.5.0",
71+
"react-papaparse": "^3.16.1",
7172
"react-redux": "^7.2.4",
7273
"react-responsive": "^8.2.0",
7374
"react-router": "^5.2.0",

src/commons/XMLParser/XMLParserHelper.ts

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import { Builder } from 'xml2js';
33
import { ExternalLibraryName } from '../application/types/ExternalTypes';
44
import {
55
Assessment,
6-
AssessmentCategories,
76
AssessmentOverview,
87
AssessmentStatuses,
8+
AssessmentType,
99
BaseQuestion,
1010
GradingStatuses,
1111
IMCQQuestion,
@@ -60,24 +60,18 @@ export const storeLocalAssessmentOverview = (overview: AssessmentOverview): void
6060

6161
export const makeEntireAssessment = (result: any): [AssessmentOverview, Assessment] => {
6262
const assessmentArr = makeAssessment(result);
63-
const overview = makeAssessmentOverview(result, assessmentArr[1], assessmentArr[2]);
63+
const overview = makeAssessmentOverview(result, assessmentArr[1]);
6464
return [overview, assessmentArr[0]];
6565
};
6666

67-
const makeAssessmentOverview = (
68-
result: any,
69-
maxGradeVal: number,
70-
maxXpVal: number
71-
): AssessmentOverview => {
67+
const makeAssessmentOverview = (result: any, maxXpVal: number): AssessmentOverview => {
7268
const task: XmlParseStrTask = result.CONTENT.TASK[0];
7369
const rawOverview: XmlParseStrOverview = task.$;
7470
return {
75-
category: capitalizeFirstLetter(rawOverview.kind) as AssessmentCategories,
71+
type: capitalizeFirstLetter(rawOverview.kind) as AssessmentType,
7672
closeAt: rawOverview.duedate,
7773
coverImage: rawOverview.coverimage,
78-
grade: 1,
7974
id: EDITING_ID,
80-
maxGrade: maxGradeVal,
8175
maxXp: maxXpVal,
8276
number: rawOverview.number || '',
8377
openAt: rawOverview.startdate,
@@ -91,13 +85,13 @@ const makeAssessmentOverview = (
9185
};
9286
};
9387

94-
const makeAssessment = (result: any): [Assessment, number, number] => {
88+
const makeAssessment = (result: any): [Assessment, number] => {
9589
const task: XmlParseStrTask = result.CONTENT.TASK[0];
9690
const rawOverview: XmlParseStrOverview = task.$;
9791
const questionArr = makeQuestions(task);
9892
return [
9993
{
100-
category: capitalizeFirstLetter(rawOverview.kind) as AssessmentCategories,
94+
type: capitalizeFirstLetter(rawOverview.kind) as AssessmentType,
10195
id: EDITING_ID,
10296
globalDeployment: makeLibrary(task.DEPLOYMENT),
10397
graderDeployment: makeLibrary(task.GRADERDEPLOYMENT),
@@ -106,8 +100,7 @@ const makeAssessment = (result: any): [Assessment, number, number] => {
106100
questions: questionArr[0],
107101
title: rawOverview.title
108102
},
109-
questionArr[1],
110-
questionArr[2]
103+
questionArr[1]
111104
];
112105
};
113106

@@ -147,8 +140,7 @@ const makeLibrary = (deploymentArr: XmlParseStrDeployment[] | undefined): Librar
147140
}
148141
};
149142

150-
const makeQuestions = (task: XmlParseStrTask): [Question[], number, number] => {
151-
let maxGrade = 0;
143+
const makeQuestions = (task: XmlParseStrTask): [Question[], number] => {
152144
let maxXp = 0;
153145
const questions: Array<IProgrammingQuestion | IMCQQuestion> = [];
154146
task.PROBLEMS[0].PROBLEM.forEach((problem: XmlParseStrProblem, curId: number) => {
@@ -161,11 +153,8 @@ const makeQuestions = (task: XmlParseStrTask): [Question[], number, number] => {
161153
graderLibrary: makeLibrary(problem.GRADERDEPLOYMENT),
162154
type: problem.$.type,
163155
xp: 0,
164-
grade: 0,
165-
maxGrade: parseInt(problem.$.maxgrade, 10),
166156
maxXp: localMaxXp
167157
};
168-
maxGrade += parseInt(problem.$.maxgrade, 10);
169158
maxXp += localMaxXp;
170159
if (question.type === 'programming') {
171160
questions.push(makeProgramming(problem as XmlParseStrPProblem, question));
@@ -174,7 +163,7 @@ const makeQuestions = (task: XmlParseStrTask): [Question[], number, number] => {
174163
questions.push(makeMCQ(problem as XmlParseStrCProblem, question));
175164
}
176165
});
177-
return [questions, maxGrade, maxXp];
166+
return [questions, maxXp];
178167
};
179168

180169
const makeMCQ = (problem: XmlParseStrCProblem, question: BaseQuestion): IMCQQuestion => {
@@ -306,7 +295,7 @@ export const assessmentToXml = (
306295
const rawOverview: XmlParseStrOverview = {
307296
coverimage: overview.coverImage,
308297
duedate: overview.closeAt,
309-
kind: overview.category.toLowerCase(),
298+
kind: overview.type.toLowerCase(),
310299
number: overview.number || '',
311300
startdate: overview.openAt,
312301
story: overview.story,
@@ -331,8 +320,7 @@ export const assessmentToXml = (
331320
assessment.questions.forEach((question: Question) => {
332321
const problem = {
333322
$: {
334-
type: question.type,
335-
maxgrade: question.maxGrade
323+
type: question.type
336324
},
337325
SNIPPET: {
338326
SOLUTION: question.answer

src/commons/achievement/AchievementManualEditor.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ type AchievementManualEditorProps = {
1212
studio: string;
1313
users: AchievementUser[];
1414
getUsers: () => void;
15-
updateGoalProgress: (studentId: number, progress: GoalProgress) => void;
15+
updateGoalProgress: (studentCourseRegId: number, progress: GoalProgress) => void;
1616
};
1717

1818
const GoalSelect = Select.ofType<AchievementGoal>();
@@ -24,10 +24,13 @@ function AchievementManualEditor(props: AchievementManualEditorProps) {
2424
const { studio, getUsers, updateGoalProgress } = props;
2525
const users =
2626
studio === 'Staff'
27-
? [...props.users].sort((user1, user2) => user1.name.localeCompare(user2.name))
27+
? // The name can be null for users who have yet to log in. We push these to the back of the array.
28+
[...props.users].sort((user1, user2) =>
29+
user1.name ? user1.name.localeCompare(user2.name) : 1
30+
)
2831
: props.users
2932
.filter(user => user.group === studio)
30-
.sort((user1, user2) => user1.name.localeCompare(user2.name));
33+
.sort((user1, user2) => (user1.name ? user1.name.localeCompare(user2.name) : 1));
3134

3235
useEffect(getUsers, [getUsers]);
3336

@@ -42,7 +45,7 @@ function AchievementManualEditor(props: AchievementManualEditorProps) {
4245

4346
const UserSelect = Select.ofType<AchievementUser>();
4447
const userRenderer: ItemRenderer<AchievementUser> = (user, { handleClick }) => (
45-
<MenuItem key={user.userId} onClick={handleClick} text={user.name} />
48+
<MenuItem key={user.courseRegId} onClick={handleClick} text={user.name} />
4649
);
4750

4851
const updateGoal = () => {
@@ -53,7 +56,7 @@ function AchievementManualEditor(props: AchievementManualEditorProps) {
5356
targetCount: goal.targetCount,
5457
completed: count >= goal.targetCount
5558
};
56-
updateGoalProgress(selectedUser.userId, progress);
59+
updateGoalProgress(selectedUser.courseRegId, progress);
5760
}
5861
};
5962

src/commons/achievement/utils/InsertFakeAchievements.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ function insertFakeAchievements(
2424
inferencer.insertFakeGoalDefinition(
2525
{
2626
uuid: idString + '0',
27-
text: `Submitted ${assessmentOverview.category.toLowerCase()}`,
27+
text: `Submitted ${assessmentOverview.type}`,
2828
achievementUuids: [idString],
2929
meta: {
3030
type: GoalType.ASSESSMENT,
@@ -38,7 +38,7 @@ function insertFakeAchievements(
3838
inferencer.insertFakeGoalDefinition(
3939
{
4040
uuid: idString + '1',
41-
text: `Graded ${assessmentOverview.category.toLowerCase()}`,
41+
text: `Graded ${assessmentOverview.type}`,
4242
achievementUuids: [idString],
4343
meta: {
4444
type: GoalType.ASSESSMENT,
@@ -53,7 +53,7 @@ function insertFakeAchievements(
5353
uuid: idString,
5454
title: assessmentOverview.title,
5555
ability:
56-
assessmentOverview.category === 'Mission' || assessmentOverview.category === 'Path'
56+
assessmentOverview.type === 'Missions' || assessmentOverview.type === 'Paths'
5757
? AchievementAbility.CORE
5858
: AchievementAbility.EFFORT,
5959
xp:
@@ -71,7 +71,7 @@ function insertFakeAchievements(
7171
view: {
7272
coverImage: `${coverImageUrl}/default.png`,
7373
description: assessmentOverview.shortSummary,
74-
completionText: `Grade: ${assessmentOverview.grade} / ${assessmentOverview.maxGrade}`
74+
completionText: `XP: ${assessmentOverview.xp} / ${assessmentOverview.maxXp}`
7575
}
7676
});
7777
}

0 commit comments

Comments
 (0)