From 3d968de88681922e01fa5ba1079101e5c582f563 Mon Sep 17 00:00:00 2001 From: Hao Long Li Date: Sun, 20 Mar 2022 17:59:07 -0400 Subject: [PATCH 1/3] Display user's email image in settings Display user's email image in settings. However this is not final as we will have requests that allows us to send the user's email image to the DB, and be retrieved with the user's name to be used in the settings in the future. --- .../Base/TitleBar/SignInModal/SignInModal.js | 9 +++++---- .../components/SettingsPage/AccountTile.js | 4 ++-- KeyCtrl/src/utils/apiUtils.js | 19 ++++++++++--------- 3 files changed, 17 insertions(+), 15 deletions(-) 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/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(){ From 656ec89dc1eaa205e4c1eff5200b1c875a73344b Mon Sep 17 00:00:00 2001 From: Hao Long Li Date: Thu, 24 Mar 2022 16:16:40 -0400 Subject: [PATCH 2/3] Training test 1 Currently have some bugs --- KeyCtrl/src/App.js | 22 +- .../src/components/TrainingPage/Training.js | 301 +++++++++++++++++- .../components/TypingTestPage/TypingTest.js | 2 +- 3 files changed, 315 insertions(+), 10 deletions(-) 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/TrainingPage/Training.js b/KeyCtrl/src/components/TrainingPage/Training.js index b691b30..9b9ea4d 100644 --- a/KeyCtrl/src/components/TrainingPage/Training.js +++ b/KeyCtrl/src/components/TrainingPage/Training.js @@ -1,14 +1,303 @@ -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 [choppedArr, setchopped] = useState([]);//Contains all the lines that will be used for custom words + const [customIndx, setCustomIndx] = useState(0);//custom index records what line we are a + + 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(/(\r\n|\n|\r)/gm, ""); + console.log(textTemp) + var parts = textTemp.match(/.{1,60}/g) || []; + console.log(parts) + setchopped(parts) + } + }; + reader.readAsText(e.target.files[0]) + + } + //-------------------------------------------------------------------- + + + async function newWords() { + var startingLine + var nextUpLine + var useCustom = false + var indx = customIndx + + console.log(choppedArr.length) + if (choppedArr.length > 0) { useCustom = true } + console.log(useCustom) + if (useCustom) { + startingLine = choppedArr[indx] + if (indx + 1 >= choppedArr.length) { indx = 0 } else { indx++ } + nextUpLine = choppedArr[indx] + if (indx + 1 >= choppedArr.length) { indx = 0 } else { indx++ } + setCustomIndx(indx) + setCurrentRandomWords(startingLine) + setNextUpRandomWords(nextUpLine) + } else {//use custom = false then use get randoms + 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. + }, [choppedArr]) + + /** + * @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() { + const words = randWordsFunc({ exactly: 20, join: ' ' }); + const letters = words.length; + console.log("letter", letters, "words", words); + + return words + } + + async function onLineChange() { + var indx = customIndx + var useCustom = false + setCurrentRandomWords(nextUpRandomWords) + if (useCustom) { + var nextUpLine = choppedArr[indx] + if (indx + 1 >= choppedArr.length) { indx = 0 } else { indx++ } + setCustomIndx(indx) + setNextUpRandomWords(nextUpLine) + } else { + 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 } From 5bd2c10ee2e710b7f265ce30d9af905d9ff66901 Mon Sep 17 00:00:00 2001 From: Hao Long Li Date: Mon, 28 Mar 2022 18:28:17 -0400 Subject: [PATCH 3/3] Training works with custom word bank Removed previous concept of directly importing a text file word for word in the same order, replaced it with a word bank. You can now import a text file with words separated by spaces(multiple spaces in a row will be replaced with a single space, including next line), and all the words will be added into a word bank array. When word bank is not empty, custom word bank will be used instead of default for generating random words. --- .../src/components/TrainingPage/Training.js | 75 +++++++++---------- 1 file changed, 35 insertions(+), 40 deletions(-) diff --git a/KeyCtrl/src/components/TrainingPage/Training.js b/KeyCtrl/src/components/TrainingPage/Training.js index 9b9ea4d..e971972 100644 --- a/KeyCtrl/src/components/TrainingPage/Training.js +++ b/KeyCtrl/src/components/TrainingPage/Training.js @@ -22,8 +22,7 @@ const Training = (props) => { var randWordsFunc = require('random-words'); //Must require random-words //Custom input states----------------------------------------------- - const [choppedArr, setchopped] = useState([]);//Contains all the lines that will be used for custom words - const [customIndx, setCustomIndx] = useState(0);//custom index records what line we are a + 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() @@ -31,48 +30,46 @@ const Training = (props) => { reader.onload = async (e) => { if (e.target.result != null) { var textTemp = e.target.result - textTemp = textTemp.replace(/(\r\n|\n|\r)/gm, ""); + textTemp = textTemp.replace(/\s\s+/g, ' ');//remove all multiple spaces with single space console.log(textTemp) - var parts = textTemp.match(/.{1,60}/g) || []; + //var parts = textTemp.match(/.{1,60}/g) || [];//chop 60 per arr + var parts = textTemp.split(" ")//split words by space console.log(parts) - setchopped(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 - var useCustom = false - var indx = customIndx - - console.log(choppedArr.length) - if (choppedArr.length > 0) { useCustom = true } - console.log(useCustom) - if (useCustom) { - startingLine = choppedArr[indx] - if (indx + 1 >= choppedArr.length) { indx = 0 } else { indx++ } - nextUpLine = choppedArr[indx] - if (indx + 1 >= choppedArr.length) { indx = 0 } else { indx++ } - setCustomIndx(indx) - setCurrentRandomWords(startingLine) - setNextUpRandomWords(nextUpLine) - } else {//use custom = false then use get randoms - startingLine = getNewWordsLine() - nextUpLine = getNewWordsLine() - setCurrentRandomWords(startingLine) - setNextUpRandomWords(chopLineToLength(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. - }, [choppedArr]) + }, [wordBank]) /** * @function reset @@ -135,25 +132,23 @@ const Training = (props) => { } function getNewWordsLine() { - const words = randWordsFunc({ exactly: 20, join: ' ' }); - const letters = words.length; - console.log("letter", letters, "words", words); - + 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() { - var indx = customIndx - var useCustom = false setCurrentRandomWords(nextUpRandomWords) - if (useCustom) { - var nextUpLine = choppedArr[indx] - if (indx + 1 >= choppedArr.length) { indx = 0 } else { indx++ } - setCustomIndx(indx) - setNextUpRandomWords(nextUpLine) - } else { - setNextUpRandomWords(chopLineToLength(getNewWordsLine())) - } + setNextUpRandomWords(chopLineToLength(getNewWordsLine())) setLineIndex(0) }