Skip to content

Commit

Permalink
Merge pull request #1499 from antonDedyaev/hide-solution
Browse files Browse the repository at this point in the history
Fix for #1348 Add a timer to the tab with the solution
  • Loading branch information
fey authored Mar 17, 2023
2 parents c17c16c + 4eb0db3 commit 3399840
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 3 deletions.
39 changes: 39 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@
"cm6-theme-basic-dark": "^0.2.0",
"cm6-theme-basic-light": "^0.2.0",
"codemirror": "^6.0.1",
"date-fns": "^2.29.3",
"highlight.js": "^11.x",
"i18next": "^21.5.4",
"jquery": "^3.6.0",
"jquery-ujs": "^1.2.3",
"lodash": "^4.17.21",
"react": "^17.0.2",
"react-bootstrap": "^2.7.0",
"react-countdown": "^2.3.5",
"react-dom": "^17.0.2",
"react-i18next": "^11.14.3",
"react-redux": "^7.2.6",
Expand Down
Binary file added resources/assets/images/waiting_clock.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
62 changes: 59 additions & 3 deletions resources/js/components/TeacherSolution.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,63 @@
import React from 'react';
import { useSelector } from 'react-redux';
import { useSelector, useDispatch } from 'react-redux';
import Countdown from 'react-countdown';
import { format } from 'date-fns';
import Highlight from 'react-syntax-highlighter';
import { vs, monokaiSublime } from 'react-syntax-highlighter/dist/esm/styles/hljs';
import { useTranslation } from 'react-i18next';

import { changeShowStatus } from '../slices/solutionSlice';
import waitingClock from '../../assets/images/waiting_clock.png';
import theme from '../common/currentTheme';

const TeacherSolution = () => {
const dispatch = useDispatch();
const { t } = useTranslation();
const { hasTeacherSolution, teacherSolutionCode } = useSelector((state) => state.exerciseInfo);
const {
displaySolutionState,
startTime,
waitingTime,
} = useSelector((state) => state.showSolution);

const handleShowSolution = () => {
dispatch(changeShowStatus('isShown'));
};

const renderShowButton = () => (
<>
<p>{t('solutionNotice')}</p>
<div className="text-center">
<button
type="button"
className="btn btn-secondary px-4"
onClick={handleShowSolution}
>
{t('showSolution')}
</button>
</div>
</>
);

const renderCountdown = (countdownData) => {
const { completed } = countdownData;

if (completed || displaySolutionState === 'canBeShown') {
return renderShowButton();
}

return hasTeacherSolution ? (
const remainingTime = format(new Date(countdownData.total), 'mm:ss');

return (
<div className="text-center">
<p className="lead">{t('solutionInstructions')}</p>
<div className="display-4">{ remainingTime }</div>
<img className="img-fluid px-5" src={waitingClock} alt="waiting_clock" />
</div>
);
};

const renderShowSolution = () => (displaySolutionState === 'isShown' ? (
<div className="d-flex h-100">
<Highlight
className="h-100 w-100"
Expand All @@ -18,7 +68,13 @@ const TeacherSolution = () => {
{teacherSolutionCode}
</Highlight>
</div>
) : null;
) : (
<div className="p-3">
<Countdown date={startTime + waitingTime} renderer={renderCountdown} />
</div>
));

return hasTeacherSolution ? renderShowSolution() : null;
};

export default TeacherSolution;
2 changes: 2 additions & 0 deletions resources/js/components/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { configureStore } from '@reduxjs/toolkit';
import editorReducer from '../slices/editorSlice.js';
import tabsBoxReducer from '../slices/tabsBoxSlice.js';
import checkResultReducer from '../slices/checkResultSlice.js';
import solutionReducer from '../slices/solutionSlice.js';
import exerciseInfoReducer from '../slices/exerciseInfoSlice.js';
import notificationReducer from '../slices/notificationSlice.js';

Expand All @@ -11,6 +12,7 @@ export default () => {
editor: editorReducer,
tabsBox: tabsBoxReducer,
checkResult: checkResultReducer,
showSolution: solutionReducer,
exerciseInfo: exerciseInfoReducer,
notification: notificationReducer,
},
Expand Down
3 changes: 3 additions & 0 deletions resources/js/locales/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export default {
tests: 'Tests',
loading: 'Loading...',
teacherSolution: 'Solution',
solutionInstructions: "Teacher's solution will be available in:",
solutionNotice: "It's best to solve the problem yourself, but if you're stuck for a long time, feel free to check out the solution. But make sure to study it thoroughly to truly understand it.",
showSolution: 'Show solution',
editorContent: {
withTemplate: 'Write your solution here',
withoutTemplate: 'This exercise has no tests.\nAny solution is a right answer.',
Expand Down
3 changes: 3 additions & 0 deletions resources/js/locales/ru.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export default {
tests: 'Тесты',
loading: 'Загрузка...',
teacherSolution: 'Решение',
solutionInstructions: 'Решение учителя откроется через:',
solutionNotice: 'Желательно решить задачу самостоятельно, но если вы застряли и долгое время ничего не получается, посмотрите решение учителя. Но обязательно разберитесь в нём и повторите по памяти',
showSolution: 'Показать решение',
editorContent: {
withTemplate: 'Введите свое решение',
withoutTemplate: 'Для этого упражнения нет проверок.\nЛюбое решение будет считаться успешным ответом.',
Expand Down
36 changes: 36 additions & 0 deletions resources/js/slices/solutionSlice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/* eslint-disable no-param-reassign */

/* TODO: issue https://github.com/Hexlet/hexlet-sicp/issues/1526
Упростить логику, убрав стейт из редакса и сделав локальный стейт в Teacher's Solution!
*/
import { createSlice } from '@reduxjs/toolkit';
import { handleNewCheckResult } from './checkResultSlice';

const solutionSlice = createSlice({
name: 'showSolution',
initialState: {
startTime: Date.now(),
waitingTime: 1200000,
displaySolutionState: 'notShown',
},
reducers: {
setStartTime(state, { payload }) {
state.startTime = payload.startTime;
},
changeShowStatus(state, { payload }) {
state.displaySolutionState = payload;
},
},
extraReducers: (builder) => {
builder.addCase(handleNewCheckResult, (state, action) => {
const { resultStatus } = action.payload;
console.log(resultStatus);
if (resultStatus === 'success') {
state.displaySolutionState = 'isShown';
}
});
},
});

export const { setStartTime, changeShowStatus } = solutionSlice.actions;
export default solutionSlice.reducer;

0 comments on commit 3399840

Please sign in to comment.