Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finished Wheel functionality #2

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
28 changes: 20 additions & 8 deletions frontend/components/Form.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,38 @@
import React from 'react'
import { connect } from 'react-redux'
import * as actionCreators from '../state/action-creators'
import { inputChange, postQuiz, setMessage, resetForm } from '../state/action-creators'

export function Form(props) {

const onChange = evt => {

props.inputChange(evt)
}

const onSubmit = evt => {

evt.preventDefault();
let message = `Congrats: "${props.newQuestion}" is a great question!`
props.postQuiz(props.newQuestion, props.newTrueAnswer, props.newFalseAnswer, message)
props.resetForm();
}

return (
<form id="form" onSubmit={onSubmit}>
<h2>Create New Quiz</h2>
<input maxLength={50} onChange={onChange} id="newQuestion" placeholder="Enter question" />
<input maxLength={50} onChange={onChange} id="newTrueAnswer" placeholder="Enter true answer" />
<input maxLength={50} onChange={onChange} id="newFalseAnswer" placeholder="Enter false answer" />
<button id="submitNewQuizBtn">Submit new quiz</button>
<input maxLength={50} onChange={onChange} id="newQuestion" placeholder="Enter question" value={props.newQuestion} />
<input maxLength={50} onChange={onChange} id="newTrueAnswer" placeholder="Enter true answer" value={props.newTrueAnswer} />
<input maxLength={50} onChange={onChange} id="newFalseAnswer" placeholder="Enter false answer" value={props.newFalseAnswer} />
<button onClick={(evt) => onSubmit(evt)} id="submitNewQuizBtn" disabled={props.newQuestion.trim() && props.newFalseAnswer.trim() && props.newTrueAnswer.trim() ? false : true}>Submit new quiz</button>
</form>
)
}

export default connect(st => st, actionCreators)(Form)
const mapStateToProps = state => {
return {
newQuestion: state.form.newQuestion,
newTrueAnswer: state.form.newTrueAnswer,
newFalseAnswer: state.form.newFalseAnswer,
}
}


export default connect(mapStateToProps, { inputChange, postQuiz, setMessage, resetForm })(Form)
13 changes: 11 additions & 2 deletions frontend/components/Message.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import React from 'react'
import { connect } from 'react-redux'

export default function Message(props) {
return <div id="message">Nice job!</div>
const Message = (props) => {
return <div id="message">{props.infoMessage}</div>
}

const mapStateToProps = state => {
return {
infoMessage: state.infoMessage.infoMessage
}
}

export default connect(mapStateToProps)(Message);
46 changes: 27 additions & 19 deletions frontend/components/Quiz.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,42 @@
import React from 'react'

export default function Quiz(props) {
import { connect } from 'react-redux'
import { fetchQuiz, selectAnswer, postAnswer } from '../state/action-creators'
function Quiz(props) {
if (!props.isFetching) {
props.fetchQuiz();
}
//NEXT STEP HANDLE CLICK
return (
<div id="wrapper">

{
// quiz already in state? Let's use that, otherwise render "Loading next quiz..."
true ? (
props.isFetching ? (
<>
<h2>What is a closure?</h2>

<h2>{props.quiz.question}</h2>
<div id="quizAnswers">
<div className="answer selected">
A function
<button>
SELECTED
</button>
</div>

<div className="answer">
An elephant
<button>
Select
</button>
</div>
{props.quiz.answers.map((answer, ind) => {
return <div key={answer.text} className={props.quiz.answers[ind].answerHighlight ? "answer selected" : "answer"}>{answer.text}
<button onClick={() => props.selectAnswer(answer.answer_id)}>{props.quiz.answers[ind].selectValue}</button>
</div>
})}
</div>

<button id="submitAnswerBtn">Submit answer</button>
<button id="submitAnswerBtn" disabled={props.buttonState} onClick={() => props.postAnswer(props.quiz)}>Submit answer</button>
</>
) : 'Loading next quiz...'
}
</div>
)
}

const mapStateToProps = state => {
return {
quiz: state.quiz.quiz,
isFetching: state.quiz.isFetching,
error: state.quiz.error,
buttonState: state.quiz.buttonState
}
}

export default connect(mapStateToProps, { fetchQuiz, selectAnswer, postAnswer })(Quiz);
27 changes: 18 additions & 9 deletions frontend/components/Wheel.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
import React from 'react'
import { connect } from 'react-redux'
import { moveClockwise, moveCounterClockwise } from '../state/action-creators'

export default function Wheel(props) {

const Wheel = (props) => {
return (
<div id="wrapper">
<div id="wheel">
<div className="cog active" style={{ "--i": 0 }}>B</div>
<div className="cog" style={{ "--i": 1 }}></div>
<div className="cog" style={{ "--i": 2 }}></div>
<div className="cog" style={{ "--i": 3 }}></div>
<div className="cog" style={{ "--i": 4 }}></div>
<div className="cog" style={{ "--i": 5 }}></div>{/* --i is a custom CSS property, no need to touch that nor the style object */}
{props.wheelState.map(item => {
return <div key={item.wheelIndex} className={item.cogState} style={{ "--i": item.wheelIndex }}>{item.wheelValue}</div>
})}
</div>
{/* --i is a custom CSS property, no need to touch that nor the style object */}

<div id="keypad">
<button id="counterClockwiseBtn" >Counter clockwise</button>
<button id="clockwiseBtn">Clockwise</button>
<button id="counterClockwiseBtn" onClick={() => props.moveCounterClockwise()}>Counter clockwise</button>
<button id="clockwiseBtn" onClick={() => props.moveClockwise()}>Clockwise</button>
</div>
</div>
)
}
const mapStateToProps = state => {
return {
wheelState: state.wheel.wheelState
}
}

export default connect(mapStateToProps, {moveClockwise, moveCounterClockwise})(Wheel);
123 changes: 101 additions & 22 deletions frontend/state/action-creators.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,118 @@
// ❗ You don't need to add extra action creators to achieve MVP
export function moveClockwise() { }
import {
MOVE_CLOCKWISE,
MOVE_COUNTERCLOCKWISE,
SET_QUIZ_INTO_STATE,
SET_SELECTED_ANSWER,
SET_INFO_MESSAGE,
INPUT_CHANGE,
RESET_FORM,
SET_IS_FETCHING,
SET_ERROR,
RESET_SELECTED_STATE,
CLEAR_INFO_MESSAGE
}
from './action-types'
import axios from 'axios'

//wheel functionality finished
export function moveClockwise() {
return ({ type: MOVE_CLOCKWISE })
}

export function moveCounterClockwise() { }
export function moveCounterClockwise() {
return ({ type: MOVE_COUNTERCLOCKWISE })
}
//wheel functionality finished

export function selectAnswer() { }
export const selectAnswer = (id) => {
return { type: SET_SELECTED_ANSWER, payload: id }
}

export function setMessage() { }
export function setMessage(message) {
return {
type: SET_INFO_MESSAGE, payload: message
}
}

export function setQuiz() { }

export function inputChange() { }
export const inputChange = (data) => {
return {
type: INPUT_CHANGE, payload: data
}
}


export function resetForm() { }
export function resetForm() {
return {
type: RESET_FORM
}
}

// ❗ Async action creators
export function fetchQuiz() {
return function (dispatch) {
// First, dispatch an action to reset the quiz state (so the "Loading next quiz..." message can display)
// On successful GET:
// - Dispatch an action to send the obtained quiz to its state
export const fetchQuiz = () => dispatch => {
dispatch(setIsFetching(false));
// First, dispatch an action to reset the quiz state (so the "Loading next quiz..." message can display)
// On successful GET:
// - Dispatch an action to send the obtained quiz to its state
axios.get(`http://localhost:9000/api/quiz/next`)
.then(res => {
dispatch(setQuizIntoState(res.data))
}, (error) => {
dispatch(setError(error.message))
})
}

const setIsFetching = (isFetching) => {
return {
type: SET_IS_FETCHING, payload: isFetching
}
}
export function postAnswer() {
return function (dispatch) {
// On successful POST:
// - Dispatch an action to reset the selected answer state
// - Dispatch an action to set the server message to state
// - Dispatch the fetching of the next quiz

const setError = (error) => {
return {
type: SET_ERROR, payload: error
}
}
export function postQuiz() {
return function (dispatch) {
// On successful POST:
// - Dispatch the correct message to the the appropriate state
// - Dispatch the resetting of the form

const setQuizIntoState = (data) => {
return {
type: SET_QUIZ_INTO_STATE, payload: data
}
}

const resetSelectedState = () => {
return {
type: RESET_SELECTED_STATE
}
}

export const postAnswer = (data) => dispatch => {
// On successful POST:
// - Dispatch an action to reset the selected answer state
// - Dispatch an action to set the server message to state
// - Dispatch the fetching of the next quiz
const answer_id = data.answers.filter((elem) => elem.selectValue === "SELECTED")[0].answer_id
axios.post(`http://localhost:9000/api/quiz/answer`, { "quiz_id": data.quiz_id, "answer_id": answer_id }).then(res => {
dispatch(setMessage(res.data.message))
dispatch(resetSelectedState());
dispatch(fetchQuiz())
})
}
export const postQuiz = (question, rightAnswer, wrongAnswer, message) => dispatch => {

// On successful POST:
// - Dispatch the correct message to the the appropriate state
// - Dispatch the resetting of the form
axios.post(`http://localhost:9000/api/quiz/new`, {
"question_text": question, "true_answer_text": rightAnswer,
"false_answer_text": wrongAnswer
}).then(res => {
console.log(res)
dispatch(setMessage(message))
}).catch(err => {
dispatch(setError(err))
})
}
// ❗ On promise rejections, use log statements or breakpoints, and put an appropriate error message in state
4 changes: 4 additions & 0 deletions frontend/state/action-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ export const SET_SELECTED_ANSWER = 'SET_SELECTED_ANSWER'
export const SET_INFO_MESSAGE = 'SET_INFO_MESSAGE'
export const INPUT_CHANGE = 'INPUT_CHANGE'
export const RESET_FORM = 'RESET_FORM'
export const SET_IS_FETCHING = "SET_IS_FETCHING"
export const SET_ERROR = "SET_ERROR"
export const RESET_SELECTED_STATE = "RESET_SELECTED_STATE "
export const CLEAR_INFO_MESSAGE = "CLEAR_INFO_MESSAGE"
Loading