diff --git a/package-lock.json b/package-lock.json index 2a73dd16f..77e5e6252 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "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", @@ -26,6 +27,7 @@ "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", @@ -4426,6 +4428,18 @@ "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", "dev": true }, + "node_modules/date-fns": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", + "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, "node_modules/debug": { "version": "4.3.4", "dev": true, @@ -9273,6 +9287,18 @@ } } }, + "node_modules/react-countdown": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/react-countdown/-/react-countdown-2.3.5.tgz", + "integrity": "sha512-K26ENYEesMfPxhRRtm1r+Pf70SErrvW3g4CArLi/x6MPFjgfDFYePT4UghEj8p2nI0cqVV7/JjDgjyr//U60Og==", + "dependencies": { + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "react": ">= 15", + "react-dom": ">= 15" + } + }, "node_modules/react-dom": { "version": "17.0.2", "license": "MIT", @@ -14650,6 +14676,11 @@ "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", "dev": true }, + "date-fns": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", + "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==" + }, "debug": { "version": "4.3.4", "dev": true, @@ -17773,6 +17804,14 @@ "warning": "^4.0.3" } }, + "react-countdown": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/react-countdown/-/react-countdown-2.3.5.tgz", + "integrity": "sha512-K26ENYEesMfPxhRRtm1r+Pf70SErrvW3g4CArLi/x6MPFjgfDFYePT4UghEj8p2nI0cqVV7/JjDgjyr//U60Og==", + "requires": { + "prop-types": "^15.7.2" + } + }, "react-dom": { "version": "17.0.2", "requires": { diff --git a/package.json b/package.json index 58ec246c5..25a7323b2 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "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", @@ -36,6 +37,7 @@ "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", diff --git a/resources/assets/images/waiting_clock.png b/resources/assets/images/waiting_clock.png new file mode 100644 index 000000000..8ba71a627 Binary files /dev/null and b/resources/assets/images/waiting_clock.png differ diff --git a/resources/js/components/TeacherSolution.jsx b/resources/js/components/TeacherSolution.jsx index 6cd7b780b..4cd0f9522 100644 --- a/resources/js/components/TeacherSolution.jsx +++ b/resources/js/components/TeacherSolution.jsx @@ -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 = () => ( + <> +
{t('solutionNotice')}
+{t('solutionInstructions')}
+