Skip to content

Commit

Permalink
feat(client,server): revamp course chapter submission mechanism
Browse files Browse the repository at this point in the history
  • Loading branch information
fushar committed Sep 5, 2023
1 parent 051a6f1 commit c2c09dd
Show file tree
Hide file tree
Showing 80 changed files with 1,332 additions and 1,514 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ public SubmissionSummaryResponse getSubmissionSummary(
@QueryParam("containerJid") String containerJid,
@QueryParam("problemJid") Optional<String> problemJid,
@QueryParam("username") Optional<String> username,
@QueryParam("problemAlias") Optional<String> problemAlias,
@QueryParam("language") Optional<String> language) {

String actorJid = actorChecker.check(authHeader);
Expand All @@ -211,8 +212,11 @@ public SubmissionSummaryResponse getSubmissionSummary(
List<String> problemJids;
if (problemJid.isPresent()) {
problemJids = ImmutableList.of(problemJid.get());
submissions = submissionStore
.getLatestSubmissionsByUserForProblemInContainer(containerJid, problemJid.get(), userJid);
submissions = submissionStore.getLatestSubmissionsByUserForProblemInContainer(containerJid, problemJid.get(), userJid);
} else if (problemAlias.isPresent()) {
String problemJidFromAlias = getProblemJidByAlias(containerJid, problemAlias.get()).orElse("");
problemJids = List.of(problemJidFromAlias);
submissions = submissionStore.getLatestSubmissionsByUserForProblemInContainer(containerJid, problemJidFromAlias, userJid);
} else {
problemJids = chapterProblemStore.getBundleProblemJids(containerJid);
submissions = submissionStore.getLatestSubmissionsByUserInContainer(containerJid, userJid);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@ import { Redirect, Switch, withRouter } from 'react-router';

import { Topbar } from '../Topbar/Topbar';

function ContentAndTopbar({ className, contentHeader, topbarElement, contentElement }) {
function ContentAndTopbar({ className, topbarElement, contentElement }) {
return (
<div className={classNames('content-with-topbar', className)}>
{contentHeader}
{topbarElement}
<hr />
{contentElement}
</div>
);
Expand All @@ -19,7 +17,7 @@ function resolveUrl(parentPath, childPath) {
return (parentPath + '/' + actualChildPath).replace(/\/\/+/g, '/');
}

function ContentWithTopbar({ match, location, className, contentHeader, items }) {
function ContentWithTopbar({ match, location, className, items }) {
const renderTopbar = () => {
const topbarItems = items
.filter(item => !item.disabled)
Expand All @@ -46,12 +44,10 @@ function ContentWithTopbar({ match, location, className, contentHeader, items })
const redirect = items[0].id !== '@' && <Redirect exact from={match.url} to={resolveUrl(match.url, items[0].id)} />;

return (
<div>
<Switch>
{redirect}
{components}
</Switch>
</div>
<Switch>
{redirect}
{components}
</Switch>
);
};

Expand All @@ -69,14 +65,7 @@ function ContentWithTopbar({ match, location, className, contentHeader, items })
return currentPath.substring(match.url.length + 1, nextSlashPos);
};

return (
<ContentAndTopbar
className={className}
contentHeader={contentHeader}
topbarElement={renderTopbar()}
contentElement={renderContent()}
/>
);
return <ContentAndTopbar className={className} topbarElement={renderTopbar()} contentElement={renderContent()} />;
}

export default withRouter(ContentWithTopbar);
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
@import '../../styles/base';

.layout-full-width-page {
max-width: 1260px;
min-height: 100vh;
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export function ProblemStatementCard({
statement,
onAnswerItem,
latestSubmissions,
reasonNotAllowedToSubmit,
disabled,
}) {
const generateOnAnswer = itemJid => {
return async answer => {
Expand All @@ -40,7 +40,7 @@ export function ProblemStatementCard({
{...item}
itemNumber={item.number}
initialAnswer={initialAnswer}
disabled={!!reasonNotAllowedToSubmit}
disabled={disabled}
/>
);
};
Expand All @@ -56,7 +56,7 @@ export function ProblemStatementCard({
{...item}
itemNumber={item.number}
initialAnswer={initialAnswer}
disabled={!!reasonNotAllowedToSubmit}
disabled={disabled}
/>
);
};
Expand All @@ -72,7 +72,7 @@ export function ProblemStatementCard({
{...item}
itemNumber={item.number}
initialAnswer={initialAnswer}
disabled={!!reasonNotAllowedToSubmit}
disabled={disabled}
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Callout, Intent } from '@blueprintjs/core';
import { BanCircle } from '@blueprintjs/icons';

import { ContentCard } from '../../../ContentCard/ContentCard';
import { ButtonLink } from '../../../ButtonLink/ButtonLink';

export function ProblemSubmissionCard({ reasonNotAllowedToSubmit, resultsUrl }) {
const renderSubmissionForm = () => {
if (reasonNotAllowedToSubmit) {
return (
<Callout icon={<BanCircle />} className="secondary-info">
<span data-key="reason-not-allowed-to-submit">{reasonNotAllowedToSubmit}</span>
</Callout>
);
}
return (
<ButtonLink intent={Intent.PRIMARY} to={resultsUrl}>
Finish and show results
</ButtonLink>
);
};

return <ContentCard>{renderSubmissionForm()}</ContentCard>;
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import { ProblemStatementCard } from './ProblemStatementCard/ProblemStatementCard';
import { ProblemSubmissionCard } from './ProblemSubmissionCard/ProblemSubmissionCard';

import './ProblemWorksheetCard.scss';

export function ProblemWorksheetCard({
alias,
worksheet: { statement, items, reasonNotAllowedToSubmit },
latestSubmissions,
onAnswerItem,
}) {
export function ProblemWorksheetCard({ alias, worksheet, latestSubmissions, onAnswerItem, resultsUrl, disabled }) {
const { statement, items, reasonNotAllowedToSubmit } = worksheet;
return (
<div className="bundle-problem-worksheet">
<ProblemStatementCard
Expand All @@ -16,8 +13,9 @@ export function ProblemWorksheetCard({
onAnswerItem={onAnswerItem}
items={items}
latestSubmissions={latestSubmissions}
reasonNotAllowedToSubmit={reasonNotAllowedToSubmit}
disabled={disabled || !!reasonNotAllowedToSubmit}
/>
<ProblemSubmissionCard reasonNotAllowedToSubmit={reasonNotAllowedToSubmit} resultsUrl={resultsUrl} />
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ export function ProblemWorksheetCard({
};

const renderSubmission = () => {
if (!onSubmit) {
return null;
}
return (
<ProblemSubmissionCard
config={submissionConfig}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { ContentCard } from '../../../ContentCard/ContentCard';
import { FormattedAnswer } from '../FormattedAnswer/FormattedAnswer';
import { VerdictTag } from '../VerdictTag/VerdictTag';

import './ProblemSubmissionCard.scss';
import './SubmissionDetails.scss';

export function ProblemSubmissionCard({
export function SubmissionDetails({
name,
alias,
itemJids,
Expand Down Expand Up @@ -63,7 +63,7 @@ export function ProblemSubmissionCard({
};

return (
<ContentCard className="bundle-problem-submission">
<ContentCard className="bundle-submission-details">
<div className="card-header">
<h4>
{alias ? `${alias} . ` : ''}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@import '../../../../styles/table';

.bundle-problem-submission {
.bundle-submission-details {
.card-header {
display: flex;
align-items: baseline;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,20 +80,24 @@ export function SubmissionDetails({
<UserRef profile={profile} />
</td>
</tr>
<tr>
<td>Problem</td>
<td>
{!!problemUrl ? (
<Link to={problemUrl}>{constructProblemName(problemName, problemAlias)}</Link>
) : (
constructProblemName(problemName, problemAlias)
)}
</td>
</tr>
<tr>
<td>{containerTitle}</td>
<td>{containerName}</td>
</tr>
{problemName && (
<tr>
<td>Problem</td>
<td>
{!!problemUrl ? (
<Link to={problemUrl}>{constructProblemName(problemName, problemAlias)}</Link>
) : (
constructProblemName(problemName, problemAlias)
)}
</td>
</tr>
)}
{containerName && (
<tr>
<td>{containerTitle}</td>
<td>{containerName}</td>
</tr>
)}
<tr>
<td>Language</td>
<td>{getGradingLanguageName(gradingLanguage)}</td>
Expand Down
7 changes: 1 addition & 6 deletions judgels-client/src/components/Topbar/Topbar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,5 @@

.topbar {
font-family: $accent-font;
}

@media only screen and (max-width: 600px) {
.topbar__item {
display: none;
}
margin-bottom: 10px;
}
4 changes: 2 additions & 2 deletions judgels-client/src/modules/api/jerahmeel/submissionBundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ export const submissionBundleAPI = {
return post(`${baseSubmissionsURL}/`, token, data);
},

getSubmissionSummary: (token, containerJid, problemJid, username, language) => {
const params = stringify({ containerJid, problemJid, username, language });
getSubmissionSummary: (token, containerJid, problemJid, username, problemAlias, language) => {
const params = stringify({ containerJid, problemJid, username, problemAlias, language });
return get(`${baseSubmissionsURL}/summary?${params}`, token);
},

Expand Down
2 changes: 1 addition & 1 deletion judgels-client/src/modules/api/sandalphon/lesson.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export function getLessonName(lesson, language) {
return lesson.titlesByLanguage[language] || lesson.titlesByLanguage[lesson.defaultLanguage];
return (language && lesson.titlesByLanguage[language]) || lesson.titlesByLanguage[lesson.defaultLanguage];
}

export function constructLessonName(title, alias) {
Expand Down
2 changes: 1 addition & 1 deletion judgels-client/src/modules/api/sandalphon/problem.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export const ProblemType = {
};

export function getProblemName(problem, language) {
return problem.titlesByLanguage[language] || problem.titlesByLanguage[problem.defaultLanguage];
return (language && problem.titlesByLanguage[language]) || problem.titlesByLanguage[problem.defaultLanguage];
}

export function constructProblemName(title, alias) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { UserRef } from '../../../../../../../components/UserRef/UserRef';
import { selectStatementLanguage } from '../../../../../../../modules/webPrefs/webPrefsSelectors';
import { selectContest } from '../../../../modules/contestSelectors';

import { ProblemSubmissionCard } from '../../../../../../../components/SubmissionDetails/Bundle/ProblemSubmissionsCard/ProblemSubmissionCard';
import { SubmissionDetails } from '../../../../../../../components/SubmissionDetails/Bundle/SubmissionDetails/SubmissionDetails';
import * as contestSubmissionActions from '../modules/contestSubmissionActions';

class SubmissionSummaryPage extends Component {
Expand Down Expand Up @@ -51,7 +51,7 @@ class SubmissionSummaryPage extends Component {
Summary for <UserRef profile={this.state.profile} />
</ContentCard>
{this.state.problemSummaries.map(props => (
<ProblemSubmissionCard key={props.alias} {...props} />
<SubmissionDetails key={props.alias} {...props} />
))}
</ContentCard>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { ChevronDown } from '@blueprintjs/icons';
import classNames from 'classnames';
import { Component } from 'react';
import { connect } from 'react-redux';
Expand All @@ -8,7 +7,6 @@ import { Link } from 'react-router-dom';
import { ProgressTag } from '../../../../../components/ProgressTag/ProgressTag';
import { ProgressBar } from '../../../../../components/ProgressBar/ProgressBar';
import { selectCourse } from '../../modules/courseSelectors';
import { selectCourseChapter } from '../chapters/modules/courseChapterSelectors';
import * as courseChapterActions from '../chapters/modules/courseChapterActions';

import './CourseChaptersSidebar.scss';
Expand All @@ -24,44 +22,49 @@ class CourseChaptersSidebar extends Component {
}

render() {
const { course, chapter } = this.props;
const { course, match } = this.props;
const { response } = this.state;
if (!course || !response) {
return null;
}

const { data: courseChapters, chaptersMap, chapterProgressesMap } = response;
const activeChapterJid = chapter && chapter.jid;

return (
<div className="course-chapters-sidebar">
<Link
className={classNames('course-chapters-sidebar__item', 'course-chapters-sidebar__title', {
'course-chapters-sidebar__item--selected': !activeChapterJid,
})}
to={`/courses/${course.slug}`}
>
<ChevronDown />
<h4>{course.name}</h4>
</Link>
<div
className={classNames('course-chapters-sidebar', {
'course-chapters-sidebar--compact': this.isInProblemPath(),
})}
>
{courseChapters.map(courseChapter => (
<Link
className={classNames('course-chapters-sidebar__item', {
'course-chapters-sidebar__item--selected': courseChapter.chapterJid === activeChapterJid,
'course-chapters-sidebar__item--selected': this.isInChapterPath(courseChapter.alias),
})}
to={`/courses/${course.slug}/chapters/${courseChapter.alias}`}
to={`${match.url}/chapters/${courseChapter.alias}`}
>
<div className="course-chapters-sidebar__item-title">
{courseChapter.alias}. {chaptersMap[courseChapter.chapterJid].name}
{courseChapter.alias}{' '}
{this.isInProblemPath() ? <>&nbsp;</> : <>. {chaptersMap[courseChapter.chapterJid].name}</>}
{this.renderProgress(chapterProgressesMap[courseChapter.chapterJid])}
</div>
{this.renderProgressBar(chapterProgressesMap[courseChapter.chapterJid])}
{!this.isInProblemPath() && this.renderProgressBar(chapterProgressesMap[courseChapter.chapterJid])}
</Link>
))}
</div>
);
}

isInChapterPath = chapterAlias => {
return (this.props.location.pathname + '/')
.replace('//', '/')
.startsWith(this.props.match.url + '/chapters/' + chapterAlias);
};

isInProblemPath = () => {
return this.props.location.pathname.includes('/problems/');
};

renderProgress = progress => {
if (!progress || progress.totalProblems === 0) {
return null;
Expand All @@ -85,7 +88,6 @@ class CourseChaptersSidebar extends Component {

const mapStateToProps = state => ({
course: selectCourse(state),
chapter: selectCourseChapter(state),
});

const mapDispatchToProps = {
Expand Down
Loading

0 comments on commit c2c09dd

Please sign in to comment.