Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
db6c3e9
Rename Dashboard component to match filename
RichDom2185 Feb 3, 2024
e802953
Use `useDispatch` in achievement dashboard
RichDom2185 Feb 3, 2024
a79fdb1
Use `useSelector` for achievement dashboard
RichDom2185 Feb 3, 2024
62b4a24
Remove unused props and components
RichDom2185 Feb 3, 2024
16c54e6
Update typing of AchievementControl component
RichDom2185 Feb 3, 2024
2f0c6d8
Refactor AchievementControl
RichDom2185 Feb 3, 2024
c5f15d9
Use `useDispatch` in AchievementControl
RichDom2185 Feb 3, 2024
d1ddaea
Use `useSelector` in AchievementControl
RichDom2185 Feb 3, 2024
61f2bd2
Remove unused types and components
RichDom2185 Feb 3, 2024
088e6b6
Use `useDispatch` in GradingEditor
RichDom2185 Feb 3, 2024
d07460d
Remove unused types and components
RichDom2185 Feb 3, 2024
d1cedfa
Refactor `DefaultChapterSelect`
RichDom2185 Feb 3, 2024
a11d6ea
Use `useDispatch` in DefaultChapterSelect
RichDom2185 Feb 3, 2024
eb05830
Use `useSession` in DefaultChapterSelect
RichDom2185 Feb 3, 2024
96eb495
Remove unused types and components
RichDom2185 Feb 3, 2024
4f43bac
Fix incorrect `sourceChapter` type in app state
RichDom2185 Feb 3, 2024
bafe1ac
Refactor `MissionCreator`
RichDom2185 Feb 3, 2024
bebe6f9
Use `useDispatch` in MissionCreator
RichDom2185 Feb 3, 2024
bd3e973
Remove console log statements
RichDom2185 Feb 3, 2024
1900957
Remove unused types and components
RichDom2185 Feb 3, 2024
1e0463c
Merge branch 'master' into no-connect-hoc-1
RichDom2185 Feb 3, 2024
3e8211c
Merge branch 'master' into no-connect-hoc-1
RichDom2185 Feb 5, 2024
300d416
Merge branch 'master' into no-connect-hoc-1
RichDom2185 Feb 5, 2024
c9e4dde
Merge branch 'master' into no-connect-hoc-1
RichDom2185 Feb 5, 2024
b88b223
Merge branch 'master' into no-connect-hoc-1
RichDom2185 Feb 5, 2024
d3aed72
Merge branch 'master' of https://github.com/source-academy/frontend i…
RichDom2185 Feb 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/commons/application/types/SessionTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export type SessionState = {
readonly enableAchievements?: boolean;
readonly enableSourcecast?: boolean;
readonly enableStories?: boolean;
readonly sourceChapter?: number;
readonly sourceChapter?: Chapter;
readonly sourceVariant?: Variant;
readonly moduleHelpText?: string;
readonly assetsPrefix?: string;
Expand Down
37 changes: 18 additions & 19 deletions src/commons/missionCreator/MissionCreator.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { FileInput } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import * as React from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import { useDispatch } from 'react-redux';
import { parseString } from 'xml2js';

import { updateAssessment } from '../application/actions/SessionActions';
import {
Assessment,
AssessmentOverview,
Expand All @@ -17,27 +19,26 @@ import {
storeLocalAssessmentOverview
} from '../XMLParser/XMLParserHelper';

type MissionCreatorProps = DispatchProps & OwnProps;

export type DispatchProps = {
newAssessment: (assessment: Assessment) => void;
};

type OwnProps = {
type Props = {
updateEditingOverview: (overview: AssessmentOverview) => void;
};

function MissionCreator(props: MissionCreatorProps) {
const [fileInputText, setFileInputText] = React.useState('Import XML');
const MissionCreator: React.FC<Props> = props => {
const [fileInputText, setFileInputText] = useState('Import XML');
let fileReader: FileReader | undefined = undefined;

React.useEffect(() => {
const dispatch = useDispatch();
const newAssessment = useCallback(
(assessment: Assessment) => dispatch(updateAssessment(assessment)),
[dispatch]
);

useEffect(() => {
const assessment = retrieveLocalAssessment();
if (assessment) {
props.newAssessment(assessment);
newAssessment(assessment);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [props.newAssessment]);
}, [newAssessment]);

const handleFileRead = (file: any) => (e: any) => {
if (!fileReader) {
Expand All @@ -46,18 +47,16 @@ function MissionCreator(props: MissionCreatorProps) {
const content = fileReader.result;
if (content) {
parseString(content, (err: any, result: any) => {
console.dir(file);
try {
const entireAssessment: [AssessmentOverview, Assessment] = makeEntireAssessment(result);
entireAssessment[0].fileName = file.name.slice(0, -4);
storeLocalAssessmentOverview(entireAssessment[0]);
props.updateEditingOverview(entireAssessment[0]);

storeLocalAssessment(entireAssessment[1]);
props.newAssessment(entireAssessment[1]);
newAssessment(entireAssessment[1]);
setFileInputText('Success!');
} catch (err) {
console.log(err);
setFileInputText('Invalid XML!');
}
});
Expand All @@ -77,7 +76,7 @@ function MissionCreator(props: MissionCreatorProps) {
storeLocalAssessmentOverview(overviewTemplate());
props.updateEditingOverview(overviewTemplate());
storeLocalAssessment(assessmentTemplate());
props.newAssessment(assessmentTemplate());
newAssessment(assessmentTemplate());
};

return (
Expand All @@ -95,6 +94,6 @@ function MissionCreator(props: MissionCreatorProps) {
</div>
</div>
);
}
};

export default MissionCreator;
19 changes: 0 additions & 19 deletions src/commons/missionCreator/MissionCreatorContainer.ts

This file was deleted.

41 changes: 27 additions & 14 deletions src/pages/academy/grading/subcomponents/GradingEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,15 @@ import {
Pre
} from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import React, { useEffect, useState } from 'react';
import React, { useEffect, useMemo, useState } from 'react';
import ReactMde, { ReactMdeProps } from 'react-mde';
import { useDispatch } from 'react-redux';

import {
reautogradeAnswer,
submitGrading,
submitGradingAndContinue
} from '../../../../commons/application/actions/SessionActions';
import ControlButton from '../../../../commons/ControlButton';
import Markdown from '../../../../commons/Markdown';
import { Prompt } from '../../../../commons/ReactRouterPrompt';
Expand All @@ -24,22 +30,14 @@ import {
} from '../../../../commons/utils/notifications/NotificationsHelper';
import { convertParamToInt } from '../../../../commons/utils/ParamParseHelper';

type GradingEditorProps = DispatchProps & OwnProps;

type GradingSaveFunction = (
submissionId: number,
questionId: number,
xpAdjustment: number | undefined,
comments?: string
) => void;

export type DispatchProps = {
handleGradingSave: GradingSaveFunction;
handleGradingSaveAndContinue: GradingSaveFunction;
handleReautogradeAnswer: (submissionId: number, questionId: number) => void;
};

type OwnProps = {
type Props = {
solution: number | string | null;
questionId: number;
submissionId: number;
Expand All @@ -55,7 +53,22 @@ type OwnProps = {

const gradingEditorButtonClass = 'grading-editor-button';

const GradingEditor: React.FC<GradingEditorProps> = props => {
const GradingEditor: React.FC<Props> = props => {
const dispatch = useDispatch();
const { handleGradingSave, handleGradingSaveAndContinue, handleReautogradeAnswer } = useMemo(
() =>
({
handleGradingSave: (...args) => dispatch(submitGrading(...args)),
handleGradingSaveAndContinue: (...args) => dispatch(submitGradingAndContinue(...args)),
handleReautogradeAnswer: (...args) => dispatch(reautogradeAnswer(...args))
}) satisfies {
handleGradingSave: GradingSaveFunction;
handleGradingSaveAndContinue: GradingSaveFunction;
handleReautogradeAnswer: (submissionId: number, questionId: number) => void;
},
[dispatch]
);

/**
* A potentially null string which defines the
* result for the number XP input. This property being null
Expand Down Expand Up @@ -140,7 +153,7 @@ const GradingEditor: React.FC<GradingEditorProps> = props => {
comments?: string
) => {
const callback = (): void => {
props.handleGradingSaveAndContinue(submissionId, questionId, xpAdjustment, comments!);
handleGradingSaveAndContinue(submissionId, questionId, xpAdjustment, comments!);
};
setCurrentlySaving(true);
// TODO: Check (not sure how) if this results in a regression.
Expand All @@ -159,7 +172,7 @@ const GradingEditor: React.FC<GradingEditorProps> = props => {
positiveIntent: 'danger'
});
if (confirm) {
props.handleReautogradeAnswer(props.submissionId, props.questionId);
handleReautogradeAnswer(props.submissionId, props.questionId);
}
};

Expand Down Expand Up @@ -300,7 +313,7 @@ const GradingEditor: React.FC<GradingEditorProps> = props => {
<ControlButton
label="Save Changes"
icon={IconNames.FLOPPY_DISK}
onClick={validateXpBeforeSave(props.handleGradingSave)}
onClick={validateXpBeforeSave(handleGradingSave)}
options={saveButtonOpts}
/>
</div>
Expand Down
23 changes: 0 additions & 23 deletions src/pages/academy/grading/subcomponents/GradingEditorContainer.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ import { SideContentTab, SideContentType } from '../../../../commons/sideContent
import Workspace, { WorkspaceProps } from '../../../../commons/workspace/Workspace';
import { WorkspaceLocation, WorkspaceState } from '../../../../commons/workspace/WorkspaceTypes';
import { AnsweredQuestion } from '../../../../features/grading/GradingTypes';
import GradingEditor from './GradingEditorContainer';
import GradingEditor from './GradingEditor';

type GradingWorkspaceProps = {
submissionId: number;
Expand Down
2 changes: 1 addition & 1 deletion src/pages/academy/groundControl/GroundControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
AssessmentOverview
} from '../../../commons/assessment/AssessmentTypes';
import ContentDisplay from '../../../commons/ContentDisplay';
import DefaultChapterSelect from './subcomponents/DefaultChapterSelectContainer';
import DefaultChapterSelect from './subcomponents/DefaultChapterSelect';
import DeleteCell from './subcomponents/GroundControlDeleteCell';
import Dropzone from './subcomponents/GroundControlDropzone';
import EditCell from './subcomponents/GroundControlEditCell';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,57 +1,59 @@
import { Button, Classes, Dialog, Intent, Menu, MenuItem } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import { ItemListRenderer, ItemRenderer, Select } from '@blueprintjs/select';
import { Chapter, Variant } from 'js-slang/dist/types';
import * as React from 'react';
import { Variant } from 'js-slang/dist/types';
import React, { useCallback, useState } from 'react';
import { useDispatch } from 'react-redux';
import Constants from 'src/commons/utils/Constants';
import { useSession } from 'src/commons/utils/Hooks';

import {
SALanguage,
sourceLanguages,
styliseSublanguage
} from '../../../../commons/application/ApplicationTypes';
import ControlButton from '../../../../commons/ControlButton';
import { changeSublanguage } from '../../../../commons/workspace/WorkspaceActions';

export type DefaultChapterSelectProps = DispatchProps & StateProps;
const DefaultChapterSelect: React.FC = () => {
const [chosenSublang, setSublanguage] = useState<SALanguage>(sourceLanguages[0]);
const [isDialogOpen, setDialogState] = useState(false);

export type DispatchProps = {
handleUpdateSublanguage: (sublang: SALanguage) => void;
};

export type StateProps = {
sourceChapter: Chapter;
sourceVariant: Variant;
};
const {
// Temporarily load the defaults when the course configuration fetch has yet to return
sourceChapter = Constants.defaultSourceChapter,
sourceVariant = Constants.defaultSourceVariant
} = useSession();

const DefaultChapterSelect: React.FunctionComponent<DefaultChapterSelectProps> = props => {
const { handleUpdateSublanguage } = props;
const { sourceChapter, sourceVariant } = props;

const [chosenSublang, setSublanguage] = React.useState<SALanguage>(sourceLanguages[0]);
const [isDialogOpen, setDialogState] = React.useState<boolean>(false);
const dispatch = useDispatch();
const handleUpdateSublanguage = useCallback(
(sublang: SALanguage) => dispatch(changeSublanguage(sublang)),
[dispatch]
);

const handleOpenDialog = React.useCallback(
const handleOpenDialog = useCallback(
(choice: SALanguage) => {
setDialogState(true);
setSublanguage(choice);
},
[setDialogState, setSublanguage]
);
const handleCloseDialog = React.useCallback(() => {
const handleCloseDialog = useCallback(() => {
setDialogState(false);
}, [setDialogState]);
const handleConfirmDialog = React.useCallback(() => {
const handleConfirmDialog = useCallback(() => {
setDialogState(false);
handleUpdateSublanguage(chosenSublang);
}, [chosenSublang, setDialogState, handleUpdateSublanguage]);

const chapterRenderer: ItemRenderer<SALanguage> = React.useCallback(
const chapterRenderer: ItemRenderer<SALanguage> = useCallback(
(lang, { handleClick }) => (
<MenuItem key={lang.displayName} onClick={handleClick} text={lang.displayName} />
),
[]
);

const chapterListRenderer: ItemListRenderer<SALanguage> = React.useCallback(
const chapterListRenderer: ItemListRenderer<SALanguage> = useCallback(
({ itemsParentRef, renderItem, items }) => {
const defaultChoices = items.filter(({ variant }) => variant === Variant.DEFAULT);
const variantChoices = items.filter(({ variant }) => variant !== Variant.DEFAULT);
Expand Down

This file was deleted.

4 changes: 2 additions & 2 deletions src/pages/achievement/Achievement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { useTypedSelector } from 'src/commons/utils/Hooks';

import { Role } from '../../commons/application/ApplicationTypes';
import NotFound from '../notFound/NotFound';
import AchievementControl from './control/AchievementControlContainer';
import AchievementDashboard from './subcomponents/AchievementDashboardContainer';
import AchievementControl from './control/AchievementControl';
import AchievementDashboard from './subcomponents/AchievementDashboard';

const Achievement: React.FC = () => {
const role = useTypedSelector(state => state.session.role!);
Expand Down
Loading