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

worked on sprint challenge #1

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
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
2 changes: 1 addition & 1 deletion frontend/components/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const resetStore = () => {
store = createStore(reducer, composeEnhancers(applyMiddleware(thunk)))
}
resetStore()

// console.log(store.getState())
export default function App() {
return (
<Provider store={store}>
Expand Down
42 changes: 35 additions & 7 deletions frontend/components/Form.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,52 @@
import React from 'react'
import React, { useEffect, useState } from 'react'
import { connect } from 'react-redux'
import * as actionCreators from '../state/action-creators'
import { object, string, InferType } from "yup";

const formSchema = object().shape({
newQuestion:
string().min(2).trim().required("Must include question!"),
newTrueAnswer:
string().min(2).trim().required("Must include True answer!"),
newFalseAnswer:
string().min(2).trim().required("Must include False answer!")
})


export function Form(props) {

const onChange = evt => {
const checkValues = () => {
if(props.form.newQuestion.trim() && props.form.newTrueAnswer.trim() && props.form.newFalseAnswer.trim()){
return false
}else{
return true
}
}


const onChange = evt => {
props.inputChange(evt)
}

const onSubmit = evt => {
evt.preventDefault();
props.resetForm()
const formData = {
question_text: props.form.newQuestion,
true_answer_text: props.form.newTrueAnswer,
false_answer_text: props.form.newFalseAnswer
}
props.postQuiz(formData)

}

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>
<h2 onClick={() => console.log(props.form)}>Create New Quiz</h2>
<input maxLength={50} onChange={onChange} id="newQuestion" value={props.form.newQuestion} placeholder="Enter question" />
<input maxLength={50} onChange={onChange} id="newTrueAnswer" value={props.form.newTrueAnswer} placeholder="Enter true answer" />
<input maxLength={50} onChange={onChange} id="newFalseAnswer" value={props.form.newFalseAnswer} placeholder="Enter false answer" />
<button id="submitNewQuizBtn" disabled={checkValues()}>Submit new quiz</button>
</form>
)
}
Expand Down
8 changes: 6 additions & 2 deletions frontend/components/Message.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import React from 'react'
import { useSelector } from 'react-redux'

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

return <div id="message">{messages}</div>
}

64 changes: 45 additions & 19 deletions frontend/components/Quiz.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,60 @@
import React from 'react'
import React, {useEffect, useState} from 'react'
import { connect } from 'react-redux'
import { fetchQuiz, selectAnswer, postAnswer } from '../state/action-creators'

export default function Quiz(props) {
export function Quiz(props) {

if(!props.quiz){
useEffect(() => {
props.fetchQuiz()
}, [])

}

const submit = () => {
if(props.selected){
const answer = {
quiz_id: props.quiz.quiz_id,
answer_id: props.selected.answer_id
}
props.postAnswer(answer)
}
}

return (
<div id="wrapper">
{
// quiz already in state? Let's use that, otherwise render "Loading next quiz..."
true ? (
props.quiz ? (
<>
<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,idx) => {
return(
<div className={props.selected === answer ? 'answer selected' : 'answer'} key={idx}>
{answer.text}
<button onClick={() => {props.selectAnswer(answer)}}>
{props.selected === answer ? 'SELECTED' : 'select'}
</button>
</div>
)
})}
</div>

<button id="submitAnswerBtn">Submit answer</button>
<button id="submitAnswerBtn" onClick={() => submit()} disabled={props.selected ? false : true}>Submit answer</button>
</>
) : 'Loading next quiz...'
) :'Loading next quiz...'
}
</div>
)
}
const mapStateToProps = state => {
return {
quiz: state.quiz,
selected: state.selectedAnswer
}

}

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

export default function Wheel(props) {
export function Wheel(props) {
const style = [1,2,3,4,5,6]

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 */}
{style.map((num,idx) => {
return (
<div key={num} className={idx === props.wheel ? 'cog active' : 'cog'} style={{ "--i": `${idx}` }}>{idx === props.wheel ? 'B' : ''}</div>
)
})}
</div>
<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 {
wheel: state.wheel
}
}

export default connect(mapStateToProps,{moveClockwise,moveCounterClockwise})(Wheel)
58 changes: 49 additions & 9 deletions frontend/state/action-creators.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,79 @@
import reducer from "./reducer"
import axios from "axios"

import { MOVE_CLOCKWISE,
MOVE_COUNTERCLOCKWISE,
SET_QUIZ_INTO_STATE,
SET_SELECTED_ANSWER,
SET_INFO_MESSAGE,
INPUT_CHANGE,
RESET_FORM,} from "./action-types"


// ❗ You don't need to add extra action creators to achieve MVP
export function moveClockwise() { }
export const moveClockwise = () => {
return ({type: MOVE_CLOCKWISE})
}

export function moveCounterClockwise() { }
export const moveCounterClockwise = () => {
return ({type: MOVE_COUNTERCLOCKWISE})
}

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

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

export function setQuiz() { }
export function setQuiz() {
}

export function inputChange() { }
export function inputChange(evt) {
return ({type:INPUT_CHANGE, payload: evt.target})
}

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

// ❗ Async action creators
export function fetchQuiz() {
return function (dispatch) {
dispatch({type: SET_QUIZ_INTO_STATE})
axios.get('http://localhost:9000/api/quiz/next')
.then(({data}) => {
dispatch ({type: SET_QUIZ_INTO_STATE, payload: data})
})


// 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 function postAnswer() {
export function postAnswer(answer) {
return function (dispatch) {
axios.post('http://localhost:9000/api/quiz/answer', answer)
.then(({data}) => dispatch({type: SET_INFO_MESSAGE, payload: data.message}))
.then(res => dispatch({type: SET_QUIZ_INTO_STATE}))
.catch(err => dispatch({SET_INFO_MESSAGE, payload: err}))
// 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
}
}
export function postQuiz() {
export function postQuiz(quiz) {
return function (dispatch) {
axios.post('http://localhost:9000/api/quiz/new', quiz)
.then(({data}) => dispatch({type: SET_INFO_MESSAGE, payload: `Congrats: "${quiz.question_text}" is a great question!`}))
.catch(err => dispatch({type: SET_INFO_MESSAGE, payload: 'ERROR POSTING NEW QUIZ'}))
// On successful POST:
// - Dispatch the correct message to the the appropriate state
// - Dispatch the resetting of the form
}

}
// ❗ On promise rejections, use log statements or breakpoints, and put an appropriate error message in state
65 changes: 59 additions & 6 deletions frontend/state/reducer.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,67 @@
// ❗ You don't need to add extra reducers to achieve MVP
import { INPUT_CHANGE, MOVE_CLOCKWISE,MOVE_COUNTERCLOCKWISE, RESET_FORM, SET_INFO_MESSAGE, SET_QUIZ_INTO_STATE, SET_SELECTED_ANSWER } from './action-types'
import { combineReducers } from 'redux'
import axios from 'axios'


const initialWheelState = 0
function wheel(state = initialWheelState, action) {
return state
const wheel = (state = initialWheelState, action) => {
switch(action.type){
case MOVE_CLOCKWISE:
if(state === 5){
return state = initialWheelState
}else{
return state + 1
}
case MOVE_COUNTERCLOCKWISE:
if(state === 0){
return state = 5
}else{
return state - 1
}
default:
return state
}
}

const initialQuizState = null
function quiz(state = initialQuizState, action) {
return state
switch(action.type){
case SET_QUIZ_INTO_STATE:
if(action.payload === undefined){
return( state = initialQuizState)}
case SET_QUIZ_INTO_STATE:
if(action.payload){
return ( state = action.payload)
}
default:
return state
}

}

const initialSelectedAnswerState = null
function selectedAnswer(state = initialSelectedAnswerState, action) {
return state
switch(action.type){
case SET_SELECTED_ANSWER:
return state = action.payload
default:
return state
}
}

const initialMessageState = ''
function infoMessage(state = initialMessageState, action) {
return state
switch(action.type){
case SET_INFO_MESSAGE:
if(action.payload === undefined){
return state = initialMessageState
}
case SET_INFO_MESSAGE:
return state = action.payload
default:
return state
}
}

const initialFormState = {
Expand All @@ -27,7 +70,17 @@ const initialFormState = {
newFalseAnswer: '',
}
function form(state = initialFormState, action) {
return state
switch(action.type){
case INPUT_CHANGE:
return {
...state,
[action.payload.id] : action.payload.value
}
case RESET_FORM:
return state = initialFormState
default:
return state
}
}

export default combineReducers({ wheel, quiz, selectedAnswer, infoMessage, form })