Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions KeyCtrl/src/App.js
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -155,7 +155,7 @@ function App() {
<div className="main-window">
{loading ? <LoadingSpinner /> : null}

<Routes>
<Routes>
<Route exact path="/project-keyctrl" element={
<TypingTest
setUpdateOnce={setUpdateOnce}
Expand All @@ -173,7 +173,23 @@ function App() {
grossWPM={grossWPM}
/>
} />
<Route exact path="/training" element={<Training />} />
<Route exact path="/training" element={
<Training
setUpdateOnce={setUpdateOnce}
setIndex={setIndex}
index={index}
accountInfo={accountInfo}
setAccountInfo={setAccountInfo}
loggedIn={loggedIn}
incrementMissed={incrementMissed}
updateAccInfo={updateAccInfo}
numEntries={numEntries}
setNumEntries={setNumEntries}
WPMTime={WPMTime}
setWPMTime={setWPMTime}
grossWPM={grossWPM}
/>
} />
<Route exact path="/multiplayer" element={<Multiplayer />} />
<Route exact path="/account" element={(loggedIn ? <Account accountInfo={accountInfo} /> : <OfflineAccount />)} />
<Route exact path="/settings" element={<Settings setShowThemeOptions={setShowThemeOptions} accountInfo={accountInfo} logout={logout} loggedIn={loggedIn} />} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}

/**
Expand Down Expand Up @@ -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
};

Expand Down
4 changes: 2 additions & 2 deletions KeyCtrl/src/components/SettingsPage/AccountTile.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ const AccountTile = ({ accountInfo, logout }) => {

<div className="base">
<div className="account-photo">
<img src={Image} />
<img src={accountInfo.photo} />
</div>
<div className="account-info">
<div className="acc-name">Colin Harker</div>
<div className="acc-name">{accountInfo.user_email}</div>
</div>
<div>
<div onClick={logout} className="logout">
Expand Down
296 changes: 290 additions & 6 deletions KeyCtrl/src/components/TrainingPage/Training.js
Original file line number Diff line number Diff line change
@@ -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 (
<div className="tr-base">
<div>
New Mode Coming Soon!
<div className="container">
<div className="timer-wrapper">
<div style={timerActive && !inCountdown ? { color: 'var(--selection-color)', textShadow: ' 0px 0px 9px var(--selection-color)' } : { color: 'var(--text-color)' }} className="timer">
{timer}s
</div>

<div className="right-elements">
<div className="timer-select">
<div onClick={() => setCount(15)} style={staticCountdown === 15 ? { color: 'var(--selection-color)', textShadow: ' 0px 0px 9px var(--selection-color)' } : null} className="time-button">
15
</div>
<div onClick={() => setCount(30)} style={staticCountdown === 30 ? { color: 'var(--selection-color)', textShadow: ' 0px 0px 9px var(--selection-color)' } : null} className="time-button">
30
</div>
<div onClick={() => setCount(45)} style={staticCountdown === 45 ? { color: 'var(--selection-color)', textShadow: ' 0px 0px 9px var(--selection-color)' } : null} className="time-button">
45
</div>
<div onClick={() => setCount(60)} style={staticCountdown === 60 ? { color: 'var(--selection-color)', textShadow: ' 0px 0px 9px var(--selection-color)' } : null} className="time-button">
60
</div>
</div>
</div>
</div>

<div className="word-base">
{timerActive ? null : <div className="start-signal-wrapper">
Correct Entries: {props.numEntries} <br />
Your WPM: {props.grossWPM()} <br /> <br />
<input type="file" accept=".txt" onChange={(e) => showFile(e)} />
<div className="start-signal">
Press Enter To Start!
</div>
</div>}
{timerActive && inCountdown && countdownToggleChecked ?
<div className="countdown">
Get Ready!
</div>
: null}
<div className="test-line-container">
{choppedCurrentLine.split("").map(function (char, idx) {
return (
<span key={idx}
className={(idx < lineIndex) ? 'correct' : 'default'}
>
{(idx === lineIndex) ? <span className="cursor" ></span> : <span />}
{char}
</span>
)
})}
</div>

<div className="test-line-container next-up">
{nextUpRandomWords}
</div>
</div>
</div>
)
}

Training.propTypes = {
timerActive: PropTypes.bool
}

export default Training
2 changes: 1 addition & 1 deletion KeyCtrl/src/components/TypingTestPage/TypingTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
Loading