Skip to content

Commit

Permalink
Finished The Client side React App
Browse files Browse the repository at this point in the history
  • Loading branch information
Kilvny committed Feb 16, 2023
1 parent 72c2878 commit e4cbf72
Show file tree
Hide file tree
Showing 25 changed files with 1,151 additions and 94 deletions.
326 changes: 326 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@reduxjs/toolkit": "^1.9.2",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"axios": "^1.3.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-redux": "^8.0.5",
"react-router-dom": "^6.8.1",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
Expand Down
38 changes: 0 additions & 38 deletions src/App.css

This file was deleted.

25 changes: 0 additions & 25 deletions src/App.js

This file was deleted.

8 changes: 0 additions & 8 deletions src/App.test.js

This file was deleted.

39 changes: 39 additions & 0 deletions src/components/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import '../styles/App.css';
import {createBrowserRouter,RouterProvider} from 'react-router-dom'
import Root from './Root';
import Quiz from './Quiz';
import Result from './Result';
import { Provider } from 'react-redux';
import store from '../redux/store';
import { CheckUserAuth } from '../hooks/helpers'; // provide route protection



/**React routes */
const router = createBrowserRouter([
{
path: '/',
// element: <CheckUserAuth><Root /></CheckUserAuth>
element: <Root />
},
{
path: '/quiz',
element: <CheckUserAuth><Quiz /></CheckUserAuth>
// element: <Quiz />
},
{
path: '/result',
// element: <Result />
element: <CheckUserAuth><Result /></CheckUserAuth>
}
])

function App() {
return (
<Provider store={store}>
<RouterProvider router={router} />
</Provider>
);
}

export default App;
65 changes: 65 additions & 0 deletions src/components/Question.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React, { useEffect, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { useFetchQuestion } from '../hooks/FetchQuestion'
import { updateAnswer } from '../hooks/helpers'

function Question({ onSelected }) {
const [selected ,setSelected] = useState(undefined)
const state = useSelector(state => state)
const { queus , trace } = state.questions
const score = state.result.score
// eslint-disable-next-line
const [{isLoading, apiData, serverError}] = useFetchQuestion() // const [getdata,setGetData] = useFetchQuestion() , but we destructered and we don't need setGetData
const dispatch = useDispatch()

useSelector(state=> console.log(state))

useEffect(()=>{
// console.log(` the state ${state}`)
dispatch(updateAnswer({trace,selected}))
console.log({trace,selected})
},[selected])

const onSelect = (value) => {
setSelected(value) // this is wrong and caused infinite loop
// console.log(selected)
// pushAnswer(selected)
onSelected(value)
dispatch(updateAnswer({trace,selected}))
}
const question = queus[trace] // we want to set the question from the state and the trace is the indicator to access that array to we know which question to render on screen based on click on next and prv buttons


if (isLoading) return <h3 className='text-light'>Loading...</h3>
if (serverError) return <h3 className='text-light'>{serverError || 'Error occured'}</h3>
return (
<div className="questions">
<h2 key={question?.id} className="text-light">
{question?.question}
</h2>

<ul>
{question?.options.map((q, i) => (
<li key={i}
// onClick={e=>{onSelect(i)}}
>
<input
type="radio"
name="options"
id={`q${i}-option`}
value={false}
onChange={()=>onSelect(i)}
/>
<label htmlFor={`q${i}-option`} className="text-primary">
{q}
</label>
{/* <div className={`check ${score[trace] == i? 'checked' : "" }`}></div> */}
<div className={`check`}></div>
</li>
))}
</ul>
</div>
);
}

export default Question
71 changes: 71 additions & 0 deletions src/components/Quiz.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React, { useEffect, useState } from 'react'
import Question from './Question'
import { useDispatch, useSelector } from 'react-redux'
import { paginateNextQuestion, paginatePrevQuestion, pushAnswer } from '../hooks/helpers'
import { Navigate } from 'react-router-dom'

const Quiz = () => {

const [answer, setAnswer] = useState(undefined)
const state = useSelector(state => state)
const score = useSelector(state => state.result.score)
const dispatch = useDispatch()

const { queus , trace } = state.questions

// useEffect(()=>{
// console.log('the score is:',score)
// // console.log(questions,result)
// // console.log(apiData)

// })

const onPrev = () => {
console.log('prev button clicked')
if(trace > 0) {
dispatch(paginatePrevQuestion())
}

}
const onNext = () => {
console.log('next button clicked')
if ( queus.length > trace && answer !== undefined) {
dispatch(paginateNextQuestion())
if(trace >= score.length){
dispatch(pushAnswer(answer))
}
}

// setAnswer(undefined)
}

const onSelected = (ans) => {
// console.log(ans)
setAnswer(ans)
}

// user reached the end of the questions
if (score.length > 0){
if(score && score.length >= queus.length ){
return <Navigate to={'/result'} replace={true}></Navigate>
}
}

return (
<div className='container'>
<h2 className='title text-light'>Quiz Application</h2>

{/* The Questions here */}
<Question onSelected={onSelected}/>

<div className='grid'>
{trace > 0 ? <button className='btn prev' onClick={onPrev}>Prev</button>
: <div></div>}
<button className='btn next' onClick={onNext}>Next</button>
</div>

</div>
)
}

export default Quiz
72 changes: 72 additions & 0 deletions src/components/Result.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import React, { useEffect } from 'react'
import '../styles/Result.css'
import {Link} from 'react-router-dom'
import ResultTable from './ResultTable'
import { useDispatch, useSelector } from 'react-redux'
import { resetAction } from '../redux/questionsReducer'
import { resetResult } from '../redux/resultReducer'
import { attemptsNumber, checkPassed, correctAnswers } from '../hooks/helpers'

const Result = () => {

const dispatch = useDispatch()
const {questions: {queus, answers} , result: {score, userId}} = useSelector(state => state)
const totalScore = queus.length * 10
const attempts = attemptsNumber(score)
const userScore = correctAnswers(score,answers, 10)
const threshold = checkPassed(totalScore, userScore)

useEffect(()=> {
console.log(score)
console.log(threshold)
},[])

const onRestart = () => {
dispatch(resetAction())
dispatch(resetResult())
}

return (
<div className='container'>
<h1 className="title text-light">Quiz Application</h1>

<div className="flex-center">
<div className="flex">
<span className="bold">UserName</span>
<span>{userId}</span>
</div>
<div className="flex">
<span className="bold">Total Score</span>
<span>{totalScore || 0}</span>
</div>
<div className="flex">
<span className="bold">No. Of Questions</span>
<span>{queus.length || 0}</span>
</div>
{/* <div className="flex">
<span className="bold">Total Attempts</span>
<span>{attempts}</span>
</div> */}
<div className="flex">
<span className="bold">User Score</span>
<span>{userScore}</span>
</div>
<div className="flex">
<span className="bold">Quiz Result</span>
<span style={{ color: `${threshold ? '#2aff95' : '#ff2a66'}`}}>{threshold ? 'Passed' : 'Faild'}</span>
</div>
</div>

<div className="start">
<Link to='/' className='btn' onClick={onRestart}>Restart</Link>
</div>

<div className='container'>
{/* ResultTable Component */}
<ResultTable />
</div>
</div>
)
}

export default Result
28 changes: 28 additions & 0 deletions src/components/ResultTable.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react'

const ResultTable = () => {
return (
<div className='conatiner'>
<table>
<thead className='table-header'>
<tr className='table-row'>
<td>Name</td>
<td>Attempts</td>
<td>Earn Points</td>
<td>Result</td>
</tr>
</thead>
<tbody>
<tr className='table-body'>
<td>Kilvny</td>
<td>03</td>
<td>20</td>
<td>Passed</td>
</tr>
</tbody>
</table>
</div>
)
}

export default ResultTable
Loading

0 comments on commit e4cbf72

Please sign in to comment.