diff --git a/client/src/App.jsx b/client/src/App.jsx index 3efe80918..a774de9d2 100644 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -6,6 +6,7 @@ import BlocklyPage from './views/BlocklyPage/BlocklyPage'; import BugReport from './views/BugReport/BugReport'; import ContentCreator from './views/ContentCreator/ContentCreator'; import Home from './views/Home/Home'; +import ChallengeCreation from './views/Mentor/Challenges/ChallengeCreation'; import Classroom from './views/Mentor/Classroom/Classroom'; import Dashboard from './views/Mentor/Dashboard/Dashboard'; import NotFound from './views/NotFound'; @@ -20,6 +21,7 @@ import ForgetPassword from './views/TeacherLogin/ForgetPassword'; import ResetPassword from './views/TeacherLogin/ResetPassword'; import TeacherLogin from './views/TeacherLogin/TeacherLogin'; +// FIXME: Challenge creation later has to become a private route const App = () => { return (
@@ -32,6 +34,7 @@ const App = () => { } /> } /> } /> + } /> { +const BlocklyCanvasPanel = ({ activity, isSandbox, setActivity, isChallengeActivity }) => { const [value] = useGlobalState('currUser'); const userRole = value.role; @@ -21,6 +21,7 @@ const BlocklyCanvasPanel = ({ activity, isSandbox, setActivity }) => { setActivity={setActivity} isSandbox={isSandbox} isMentorActivity={!activity.selectedToolbox && !isSandbox} + isChallengeActivity={isChallengeActivity} />; case 'ContentCreator': return ( diff --git a/client/src/components/ActivityPanels/BlocklyCanvasPanel/canvas/MentorCanvas.jsx b/client/src/components/ActivityPanels/BlocklyCanvasPanel/canvas/MentorCanvas.jsx index 7d99ef2be..eda5c198a 100644 --- a/client/src/components/ActivityPanels/BlocklyCanvasPanel/canvas/MentorCanvas.jsx +++ b/client/src/components/ActivityPanels/BlocklyCanvasPanel/canvas/MentorCanvas.jsx @@ -21,7 +21,7 @@ import PlotterLogo from '../Icons/PlotterLogo'; let plotId = 1; -export default function MentorCanvas({ activity, isSandbox, setActivity, isMentorActivity }) { +export default function MentorCanvas({ activity, isSandbox, setActivity, isMentorActivity, isChallengeActivity }) { const [hoverUndo, setHoverUndo] = useState(false); const [hoverRedo, setHoverRedo] = useState(false); const [hoverCompile, setHoverCompile] = useState(false); @@ -261,6 +261,12 @@ export default function MentorCanvas({ activity, isSandbox, setActivity, isMent } } }; + + const handleCreatorChallengeSave = async () => { + // FIXME: Handle saving a challenge to the database or updating it if it already exists + console.log("Saving a challenge to the database not yet implemented"); + } + const menu = ( @@ -274,24 +280,38 @@ export default function MentorCanvas({ activity, isSandbox, setActivity, isMent ); - const menuSave = ( - - - -   Save to template - - - - - ); + const menuSave = (isChallengeActivity) => { + console.log(`Menu save sees that challenge activity is: ${isChallengeActivity}`); + if (isChallengeActivity) { + return ( + + + +   Save challenge activity template + + + ); + } else { + return ( + + + +   Save to template + + + + + ); + } + } return (
@@ -332,7 +352,7 @@ export default function MentorCanvas({ activity, isSandbox, setActivity, isMent className='flex flex-row' id='save-dropdown-container' > - + menuSave(isChallengeActivity)}> diff --git a/client/src/views/BlocklyPage/BlocklyPage.jsx b/client/src/views/BlocklyPage/BlocklyPage.jsx index 584766bd6..bb5aa957b 100644 --- a/client/src/views/BlocklyPage/BlocklyPage.jsx +++ b/client/src/views/BlocklyPage/BlocklyPage.jsx @@ -11,11 +11,13 @@ import { import { useGlobalState } from "../../Utils/userState" export default function BlocklyPage({ isSandbox }) { + const [isChallengeActivity, setIsChallengeActivity] = useState(false); const [value] = useGlobalState("currUser") const [activity, setActivity] = useState({}) const navigate = useNavigate() useEffect(() => { + setIsChallengeActivity(false); const setup = async () => { // if we are in sandbox mode show all toolbox const sandboxActivity = JSON.parse(localStorage.getItem("sandbox-activity")) @@ -48,8 +50,13 @@ export default function BlocklyPage({ isSandbox }) { // else show toolbox based on the activity we are viewing else { const localActivity = JSON.parse(localStorage.getItem("my-activity")) + // FIXME: Remove this debugging console log + console.log(`the following was found for local activity: ${localActivity}`); if (localActivity) { + setIsChallengeActivity(localActivity?.is_challenge == true); + // FIXME: Remove this debugging console log + console.log(`Set is challenge activity to: ${isChallengeActivity}`); if (localActivity.toolbox) { setActivity(localActivity) } else { @@ -59,6 +66,7 @@ export default function BlocklyPage({ isSandbox }) { localStorage.setItem("my-activity", JSON.stringify(loadedActivity)) setActivity(loadedActivity) + setIsChallengeActivity(localActivity?.is_challenge == true); } else { message.error(res.err) } @@ -76,7 +84,7 @@ export default function BlocklyPage({ isSandbox }) {
- +
) diff --git a/client/src/views/Mentor/Challenges/BadgeSelection.jsx b/client/src/views/Mentor/Challenges/BadgeSelection.jsx new file mode 100644 index 000000000..4799aa2e2 --- /dev/null +++ b/client/src/views/Mentor/Challenges/BadgeSelection.jsx @@ -0,0 +1,119 @@ +//Import stuff +import React, { useEffect, useRef, useState, useReducer } from 'react'; +import Badge1 from "../../../Images/Badge1.jpg"; +import Badge2 from "../../../Images/Badge2.jpg"; + +//Function component to select/view badges +function BadgeSelection ({onBadgeSelect}) +{ + //State variable to keep track of current badge using ID + const [currentBadgeID, setBadgeID] = useState(0); + //Array of badge images - will add more later as I draw them + const badgeImages = [Badge1, Badge2]; + + //Style for the badge carousel + const sliderStyles = { + height: "300px", + position: "relative", + } + + //Style to display each badge + const badgeStyles = { + width: "300px", + height: "300px", + borderRadius: "10px", + backgroundPosition: "center", + backgroundSize: "cover", + //Set badge image based on the current badge ID + backgroundImage: `url(${badgeImages[currentBadgeID]})`, + zIndex: 10, + + } + + //Left arrow style to navigate from each badge + const leftArrowStyles = { + position: "absolute", + top: "50%", + transform: "translate(-50%, -50%)", + left: "16px", + fontSize: '45px', + color: "black", + zIndex: 1000, + cursor: "pointer", + + } + + //Right arrow style to navigate from each badge + const rightArrowStyles = { + position: "absolute", + top: "50%", + transform: "translate(-50%, -50%)", + right: "32px", + fontSize: '45px', + color: 'black', + zIndex: 1000, + cursor: "pointer", + + } + + //Function to navigate to previous badge + const goToPrevious = () => { + const isFirstBadge = currentBadgeID === 0; + const newIndex = isFirstBadge ? badgeImages.length - 1 : currentBadgeID - 1; + setBadgeID(newIndex); + } + + //Function to navigate to next badge + const goToNext = () => { + const isLastBadge = currentBadgeID === badgeImages.length - 1; + const newIndex = isLastBadge ? 0 : currentBadgeID + 1; + setBadgeID(newIndex); + } + + //Function to select current badge, and pass to parent component, to use + const selectBadge = () => { + //Console log to show button is working + console.log("Button pressed"); + onBadgeSelect(currentBadgeID); + } + + //Make button appear over other things + const buttonStyle = { + zIndex: 2000, + + + } + //Fixing sonarcloud bug + const keyboardListener = (event) => { + //Left and right arrows + if (event.key === 'leftArrow') + { + goToPrevious(); + } + else if (event.key === 'rightArrow') + { + goToNext(); + } + } + + //Render the badge selection on page + //*Needed to change the way of displaying arrows, use unicode + return ( +
+
+
+
+
+
+
+ +
+
+ + + ) + +} + +export default BadgeSelection; + diff --git a/client/src/views/Mentor/Challenges/ChallengeCreation.jsx b/client/src/views/Mentor/Challenges/ChallengeCreation.jsx new file mode 100644 index 000000000..c7bb9e39b --- /dev/null +++ b/client/src/views/Mentor/Challenges/ChallengeCreation.jsx @@ -0,0 +1,119 @@ +import React, { useState } from 'react'; +import { Form, Input } from "antd" +import './ChallengeCreation.less'; +import NavBar from '../../../components/NavBar/NavBar'; +import { useGlobalState } from '../../../Utils/userState'; +import { useNavigate } from 'react-router-dom'; +import { + getActivityToolboxAll, +} from "../../../Utils/requests" +import BadgeSelection from '../../../views/Mentor/Challenges/BadgeSelection.jsx' + +export default function ChallengeCreation() { + const defaultChallengeData = { + name: '', + badge: 0, + description: '', + }; + + const [challengeData, setChallengeData] = useState(defaultChallengeData); + const [value] = useGlobalState('currUser'); + const navigate = useNavigate(); + const [selectedBadge, setSelectedBadge] = useState(null); + + const handleViewActivityTemplate = async () => { + // FIXME: Navigate with specific SELECTED information + console.log("Navigating to activity template page not yet implemented"); + + const allToolBoxRes = await getActivityToolboxAll(); + const selectedToolBoxRes = await getActivityToolboxAll(); + let activity = { + selectedToolbox: selectedToolBoxRes.data.toolbox, + toolbox: allToolBoxRes.data.toolbox, + lesson_module_name: challengeData.name, + is_challenge: true, + } + localStorage.setItem("my-activity", JSON.stringify(activity)); + navigate("/activity"); + } + + const handleSave = () => { + // FIXME: Save information to database + console.log("Saving challenge to database not yet implemented") + } + + const navigateToAssignChallenge = () => { + // FIXME: Navigate to assign challenge page + console.log("Navigating to assign challenge page not yet implemented") + } + + return ( +
+ +
Edit challenge details
+
+
+

+ +
+ + + + + setChallengeData({...challengeData, name: e.target.value})} + value={challengeData.name} + required + placeholder="Enter challenge title..." + > + + + + + setChallengeData({...challengeData, description: e.target.value})} + value={challengeData.description} + required + placeholder="Enter challenge description..." + > + + + + + + + + + + + + + + + +
+
+
+
+ ); +} diff --git a/client/src/views/Mentor/Challenges/ChallengeCreation.less b/client/src/views/Mentor/Challenges/ChallengeCreation.less new file mode 100644 index 000000000..0d6d45da5 --- /dev/null +++ b/client/src/views/Mentor/Challenges/ChallengeCreation.less @@ -0,0 +1,72 @@ +@import '../../../assets/style.less'; + +#challenge-detail-editor { + textarea { + display: block; + margin: 0px 5px 0px; + background: none; + border: 1px solid; + border-color: #colors[secondary]; + padding: 10px 10px; + width: 95%; + outline: none; + color: #colors[text-primary]; + border-radius: 4px; + transition: 0.25s; + } + + button { + width: 25%; + height: auto; + font-size: 1rem; + font-weight: 500; + border-radius: 30px; + margin: 10% auto auto auto; + background: #colors[quaternary]; + border: none; + color: #colors[text-primary]; + transition: 0.25s; + cursor: pointer; + box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.377); + + &:hover { + width: 26%; + background: #colors[quinary]; + } + } + +} + +#creation-container-grid { + display: grid; + place-items: center; +} + +#creation-container { + background-color: #colors[tertiary]; + border-radius: 25px; + width: 90%; + padding-bottom: 20px; +} + +#card-button-container { + button { + width: 25%; + height: auto; + font-size: 1rem; + font-weight: 500; + border-radius: 30px; + margin: 10% auto auto auto; + background: #colors[quaternary]; + border: none; + color: #colors[text-primary]; + transition: 0.25s; + cursor: pointer; + box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.377); + + &:hover { + width: 26%; + background: #colors[quinary]; + } + } +} diff --git a/server/extensions/documentation/documentation/1.0.0/full_documentation.json b/server/extensions/documentation/documentation/1.0.0/full_documentation.json index 49963424f..9882e3185 100755 --- a/server/extensions/documentation/documentation/1.0.0/full_documentation.json +++ b/server/extensions/documentation/documentation/1.0.0/full_documentation.json @@ -14,7 +14,7 @@ "name": "Apache 2.0", "url": "https://www.apache.org/licenses/LICENSE-2.0.html" }, - "x-generation-date": "10/12/2023 1:28:43 PM" + "x-generation-date": "11/02/2023 8:02:39 PM" }, "x-strapi-config": { "path": "/documentation",