diff --git a/KeyCtrl/src/App.js b/KeyCtrl/src/App.js index 33a4ea3..f1a31fc 100644 --- a/KeyCtrl/src/App.js +++ b/KeyCtrl/src/App.js @@ -1,12 +1,12 @@ import React, { useState, useEffect} from 'react'; import TypingTest from './components/TypingTestPage/TypingTest.js'; +import Training from './components/TrainingPage/Training.js'; import SignInModal from './components/Base/TitleBar/SignInModal/SignInModal.js'; import TitleBar from './components/Base/TitleBar/TitleBar.js'; import TaskBar from './components/Base/TaskBar/TaskBar.js'; import './App.css'; import Account from './components/AccountPage/Account.js'; import OfflineAccount from './components/AccountPage/OfflineAccount.js'; -import Training from './components/TrainingPage/Training.js'; import Settings from './components/SettingsPage/Settings.js'; import LoadingSpinner from './components/Base/LoadingSpinner/LoadingSpinner.js'; import * as api from './utils/apiUtils.js' @@ -155,7 +155,7 @@ function App() {
{loading ? : null} - + } /> - } /> + + } /> } /> : )} /> } /> diff --git a/KeyCtrl/src/components/Base/TitleBar/SignInModal/SignInModal.js b/KeyCtrl/src/components/Base/TitleBar/SignInModal/SignInModal.js index 6803b20..f8ad7e5 100644 --- a/KeyCtrl/src/components/Base/TitleBar/SignInModal/SignInModal.js +++ b/KeyCtrl/src/components/Base/TitleBar/SignInModal/SignInModal.js @@ -51,10 +51,10 @@ const SignInModal = ({ onLogin, showSignIn, setShowSignIn }) => { @description Api call to log in but the email is HASHED and passes result to onLogin(). THIS IS A WORKING METHOD TO BE USED IN THE FUTURE */ - const login = () => { - var hash = sha256(values.email) + const login = (email, photo) => { + var hash = sha256(email) console.log(hash.toString() + " " + hash.toString().length) - onLogin(api.callLogin(hash.toString())); + onLogin(api.callLogin(hash.toString(), photo)); } /** @@ -124,8 +124,9 @@ const SignInModal = ({ onLogin, showSignIn, setShowSignIn }) => { const responseGoogle = response => { console.log(response); + console.log(response.profileObj.imageUrl) console.log(response.profileObj.email) - login(response.profileObj.email) + login(response.profileObj.email, response.profileObj.imageUrl) //after login in on google login, we call login }; diff --git a/KeyCtrl/src/components/SettingsPage/AccountTile.js b/KeyCtrl/src/components/SettingsPage/AccountTile.js index 5d3e2f9..e082adc 100644 --- a/KeyCtrl/src/components/SettingsPage/AccountTile.js +++ b/KeyCtrl/src/components/SettingsPage/AccountTile.js @@ -21,10 +21,10 @@ const AccountTile = ({ accountInfo, logout }) => {
- +
-
Colin Harker
+
{accountInfo.user_email}
diff --git a/KeyCtrl/src/components/TrainingPage/Training.js b/KeyCtrl/src/components/TrainingPage/Training.js index b691b30..e971972 100644 --- a/KeyCtrl/src/components/TrainingPage/Training.js +++ b/KeyCtrl/src/components/TrainingPage/Training.js @@ -1,14 +1,298 @@ -import React from 'react' -import '../../styles/Training.css' +import { useState, useEffect, useRef } from "react"; +import '../../styles/TypingTest.css' +import PropTypes from "prop-types" +import styled from "styled-components" +import * as api from '../../utils/apiUtils.js' +import { wait } from "@testing-library/react"; + +const Training = (props) => { + + const [staticCountdown, setStaticCountdown] = useState(15); + const [countdown, setCountdown] = useState(1); + const [choppedCurrentLine, setChoppedCurrentLine] = useState(""); //setting its use state + const [lineIndex, setLineIndex] = useState(0) + const [timer, setTimer] = useState(15); + const [timerActive, setTimerActive] = useState(false); + const [countdownToggleChecked, setCountdownToggleChecked] = useState(true); + const [inCountdown, setInCountdown] = useState(false) + const [currentLineLength, setCurrentLineLength] = useState(0); + + const [randomWords, setCurrentRandomWords] = useState(" "); //setting its use state + const [nextUpRandomWords, setNextUpRandomWords] = useState(" "); + var randWordsFunc = require('random-words'); //Must require random-words + + //Custom input states----------------------------------------------- + const [wordBank, setWordBank] = useState([]);//Contains all the lines that will be used for custom words + + const showFile = async (e) => {//takes in and chops text of min 1 and max 60 into chopped + e.preventDefault() + const reader = new FileReader() + reader.onload = async (e) => { + if (e.target.result != null) { + var textTemp = e.target.result + textTemp = textTemp.replace(/\s\s+/g, ' ');//remove all multiple spaces with single space + console.log(textTemp) + //var parts = textTemp.match(/.{1,60}/g) || [];//chop 60 per arr + var parts = textTemp.split(" ")//split words by space + console.log(parts) + setWordBank(parts) + } + }; + reader.readAsText(e.target.files[0]) + + } + + function customWordsFunc(amount) { + var words = wordBank[Math.floor(Math.random() * wordBank.length)] + console.log(wordBank) + for (let i = 0; i < amount - 1; i++) { + words = words + " " + wordBank[Math.floor(Math.random() * wordBank.length)] + } + console.log(words) + return words + } + + //-------------------------------------------------------------------- + + + async function newWords() { + var startingLine + var nextUpLine + + startingLine = getNewWordsLine() + nextUpLine = getNewWordsLine() + setCurrentRandomWords(startingLine) + setNextUpRandomWords(chopLineToLength(nextUpLine)) + + console.log(startingLine) + } + + useEffect(() => { //using another useEffect so random words does not refresh everytime. + newWords(); //Setting how many words given for the test right here. + }, [wordBank]) + + /** + * @function reset + * @description resets information variables related to running the typing test + */ + + function reset() { + setTimerActive(false); + props.setIndex(0); + setLineIndex(0) + setTimer(staticCountdown); + setCountdown(1); + newWords(); + } + + /** + * + * @param {any} callback used to callback to previous referance of page + * @param {any} delay amount to be delayed + * @function useInterval + * @description Used to set a delay/countdown that is persistant over react renders + */ + function useInterval(callback, delay) { + + const savedCallback = useRef(); + + // Remember the latest callback. + useEffect(() => { + savedCallback.current = callback; + }, [callback]); + + // Set up the interval. + useEffect(() => { + function tick() { + savedCallback.current(); + } + if (delay !== null) { + let id = setInterval(tick, delay); + return () => clearInterval(id); + } + }, [delay]); + } + + const setCount = (count) => { + if (!timerActive) { + setStaticCountdown(count); + setTimer(count); + } + }; + + function chopLineToLength(wordString) { + var trimmedString = wordString.substring(0, 60) + + // If we do not chop perfectly at end of word + if (wordString[60] !== " ") { + var lastIndex = trimmedString.lastIndexOf(" ") + trimmedString = trimmedString.substring(0, lastIndex) + } + return trimmedString + } + + function getNewWordsLine() { + var words = [] + var letters = "" + if (wordBank.length > 0) {// if there are words in wordbank, use it + words = customWordsFunc(20) + letters = words.length; + console.log("Custom letter", letters, "words", words); + } else {//default + words = randWordsFunc({ exactly: 20, join: ' ' }); + letters = words.length; + console.log("letter", letters, "words", words); + } + return words + } + + async function onLineChange() { + setCurrentRandomWords(nextUpRandomWords) + setNextUpRandomWords(chopLineToLength(getNewWordsLine())) + setLineIndex(0) + } + + useEffect(() => { + + document.addEventListener('keydown', onKeyPress); + + if (timer === 0 && !timerActive) { + props.setUpdateOnce(true); + } + + if (!props.timerActive) { + setChoppedCurrentLine(chopLineToLength(randomWords)) + setCurrentLineLength(choppedCurrentLine.length) + } else if (lineIndex === choppedCurrentLine.length - 1) { + reset() + } + + return () => { + document.removeEventListener('keydown', onKeyPress); + }; + }, [randomWords, nextUpRandomWords, lineIndex, timerActive, inCountdown]) + + const onKeyPress = (event) => { + + switch (event.key) { + + case "Enter": + // setUpdateOnce(true); + if (!timerActive) { + setTimerActive(true); + if (countdownToggleChecked) + setInCountdown(true); + else + setInCountdown(false); + } + break; + + case "Escape": + console.log("correct"); + break; + //EDITED TO MAKE LETTER MISSES UPDATE + default: + if (timerActive && !inCountdown) { + console.log(event.key + " " + randomWords[lineIndex]) + if (event.key === randomWords[lineIndex]) { + + setLineIndex((lineIndex) => lineIndex + 1) + props.setIndex((index) => index + 1); + + if (lineIndex === currentLineLength - 1) { + onLineChange() + } + + } else if (event.key != randomWords[lineIndex] && props.loggedIn) { + props.incrementMissed(randomWords[lineIndex]); + // console.log(randomWords[index]); + // console.log(accountInfo.letter_misses); + } + } + break; + } + }; + + useInterval(() => { + if (!inCountdown && timer === 0) { + reset(); + + } else if (inCountdown) { + if (countdown === 1) { + setInCountdown(false); + props.setNumEntries(0); + props.setWPMTime(staticCountdown); + } else { + setCountdown(countdown => countdown - 1) + } + } else { + setTimer(timer => timer - 1); + props.setNumEntries(props.index); + } + }, timerActive ? 1000 : null); -const Training = () => { return ( -
-
- New Mode Coming Soon! +
+
+
+ {timer}s +
+ +
+
+
setCount(15)} style={staticCountdown === 15 ? { color: 'var(--selection-color)', textShadow: ' 0px 0px 9px var(--selection-color)' } : null} className="time-button"> + 15 +
+
setCount(30)} style={staticCountdown === 30 ? { color: 'var(--selection-color)', textShadow: ' 0px 0px 9px var(--selection-color)' } : null} className="time-button"> + 30 +
+
setCount(45)} style={staticCountdown === 45 ? { color: 'var(--selection-color)', textShadow: ' 0px 0px 9px var(--selection-color)' } : null} className="time-button"> + 45 +
+
setCount(60)} style={staticCountdown === 60 ? { color: 'var(--selection-color)', textShadow: ' 0px 0px 9px var(--selection-color)' } : null} className="time-button"> + 60 +
+
+
+
+ +
+ {timerActive ? null :
+ Correct Entries: {props.numEntries}
+ Your WPM: {props.grossWPM()}

+ showFile(e)} /> +
+ Press Enter To Start! +
+
} + {timerActive && inCountdown && countdownToggleChecked ? +
+ Get Ready! +
+ : null} +
+ {choppedCurrentLine.split("").map(function (char, idx) { + return ( + + {(idx === lineIndex) ? : } + {char} + + ) + })} +
+ +
+ {nextUpRandomWords} +
) } +Training.propTypes = { + timerActive: PropTypes.bool +} + export default Training diff --git a/KeyCtrl/src/components/TypingTestPage/TypingTest.js b/KeyCtrl/src/components/TypingTestPage/TypingTest.js index 2af4b52..c1cb8d7 100644 --- a/KeyCtrl/src/components/TypingTestPage/TypingTest.js +++ b/KeyCtrl/src/components/TypingTestPage/TypingTest.js @@ -137,7 +137,7 @@ export const TypingTest = (props) => { function getNewWordsLine() { const words = randWordsFunc({ exactly: 20, join: ' ' }); const letters = words.length; - console.log("letter", letters, "words", 13); + console.log("letter", letters, "words", words); return words } diff --git a/KeyCtrl/src/utils/apiUtils.js b/KeyCtrl/src/utils/apiUtils.js index 726211f..2e31b74 100644 --- a/KeyCtrl/src/utils/apiUtils.js +++ b/KeyCtrl/src/utils/apiUtils.js @@ -14,13 +14,14 @@ var account = { }; -export function callLogin(email) { +export function callLogin(email, photoUrl) { account = { account_id: -1, display_name: "", user_email: "", - photo: -1 + photo: photoUrl }; + console.log(email) var options = { url: 'https://9x38qblue2.execute-api.us-east-1.amazonaws.com/dev/login?email=' @@ -35,11 +36,11 @@ export function callLogin(email) { account.account_id = info[0].account_id; account.display_name = info[0].display_name; account.user_email = info[0].user_email; - account.photo = info[0].photo; + //account.photo = info[0].photo; console.log(account); - getStats(account.account_id); + //getStats(account.account_id); }else{ - callRegisterAccount(email);// if it returns invalid login recentials, it registers the account + callRegisterAccount(email, photoUrl);// if it returns invalid login recentials, it registers the account } }) .finally(function(){ @@ -52,12 +53,12 @@ export function callLogin(email) { } -export function callRegisterAccount(email) { +export function callRegisterAccount(email, photoUrl) { account = { account_id: -1, display_name: "", user_email: "", - photo: -1 + photo: photoUrl }; var options = { method: 'POST', @@ -75,8 +76,8 @@ export function callRegisterAccount(email) { account.account_id = info[0].account_id; account.display_name = info[0].display_name; account.user_email = info[0].user_email; - account.photo = info[0].photo; - getStats(account.account_id); + //account.photo = info[0].photo; + //getStats(account.account_id); console.log(account); }) .finally(function(){