Commit 0efc9c9a authored by Nagendra Yallabandi's avatar Nagendra Yallabandi

first commit

parents
#
# NPM
#
node_modules/
package-lock.json
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/testmyself-TMS-1.iml" filepath="$PROJECT_DIR$/testmyself-TMS-1.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="d3936bbc-68c6-437a-8286-0c78729c11d8" name="Default Changelist" comment="" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="ProjectId" id="2Fc7x0LTjrercXwJGSBiTcAKtYI" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showExcludedFiles" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
</component>
<component name="SvnConfiguration">
<configuration />
</component>
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="d3936bbc-68c6-437a-8286-0c78729c11d8" name="Default Changelist" comment="" />
<created>1664779760537</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1664779760537</updated>
</task>
<servers />
</component>
<component name="WindowStateProjectService">
<state x="519" y="408" key="com.intellij.ide.util.TipDialog" timestamp="1664782027979">
<screen x="0" y="38" width="1728" height="1079" />
</state>
<state x="519" y="408" key="com.intellij.ide.util.TipDialog/0.38.1728.1079@0.38.1728.1079" timestamp="1664782027979" />
</component>
</project>
\ No newline at end of file
{
"name": "test-my-self",
"version": "0.1.0",
"private": true,
"dependencies": {
"@reduxjs/toolkit": "^1.8.5",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-redux": "^8.0.4",
"react-router-dom": "^6.4.1",
"react-scripts": "5.0.1",
"redux": "^4.2.0",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
import './App.css';
import QuizComponent from './containers/QuizComponent';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
function App() {
return (
<div className="App">
<Router>
<h1>Test MySelf</h1>
<Routes>
<Route path="/quiz/:quizId" exact element= { <QuizComponent/> }/>
<Route>404 Not found!</Route>
</Routes>
</Router>
</div>
);
}
export default App;
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});
import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { useParams } from 'react-router-dom';
import { setQuiz, setCurrentQuestion, setSelectedOption, setCurrentIndex, toggleSubmit, setOptionStatus } from '../redux/actions/quizActions';
import '../css/QuizCss.css';
const QuestionsList = () => {
const currentQuestion = useSelector((state) => state.question.currentQuestion);
const currentIndex = useSelector((state) => state.question.currentIndex);
const quizData = useSelector((state) => state.quiz.questionsList);
const questionsLength = useSelector((state) => state.quiz.questionsLength);
const checkedOptionId = useSelector((state) => state.question.checkedOptionId);
const submitDisabled = useSelector((state) => state.question.submitDisabled);
const questionStatus = useSelector((state) => state.question.questionStatus);
const { quizId } = useParams();
const dispatch = useDispatch();
useEffect(() => {
const { data } = require('../data/quizData.json');
const quiz = data.filter( quiz => quiz.id == quizId);
dispatch(setQuiz(quiz[0]));
dispatch(setCurrentQuestion(quiz[0].questions[0]));
}, []);
function nextQuestion() {
if(currentIndex < (questionsLength-1)){
dispatch(setCurrentQuestion(quizData.questions[currentIndex+1]));
dispatch(setCurrentIndex(currentIndex+1));
dispatch(setSelectedOption(0));
}
if(currentIndex < (questionsLength)){
dispatch(setCurrentIndex(currentIndex+1));
}
}
function checkAnswer(){
if(checkedOptionId == currentQuestion.correctOptionId){
dispatch(setOptionStatus({status:'correct',id:checkedOptionId}));
}
else{
dispatch(setOptionStatus({status:'incorrect',id:checkedOptionId}));
}
dispatch(toggleSubmit(!submitDisabled));
}
function selectedOption(event) {
dispatch(setSelectedOption(Number(event.target.value)));
dispatch(toggleSubmit(false));
}
let optionsList = currentQuestion.options ? currentQuestion.options.map((optionItem) => {
return (
<div key={optionItem.id}>
<div className='option-title'>
<label className='option-label'>
<input disabled={optionItem.status != 'unset'} className='option-input' type="radio" name="option_title" value={optionItem.id} checked={checkedOptionId == optionItem.id} onChange={selectedOption}/>{ optionItem.option }
</label>
{
optionItem.status === 'correct' ? <p className='option-result correct-option'>Correct</p> : ``
}
{
optionItem.status === 'incorrect' ? <p className='option-result incorrect-option'>Incorrect</p> : ``
}
</div>
</div>
);
}): ``;
return (
<div>
{
currentIndex < questionsLength ?
<div className='quiz-container'>
<div className='question-container'>
<p className='question-index'>Question { currentIndex < questionsLength ? (currentIndex+1) : questionsLength }/{ questionsLength }</p>
<p className='question-title'>{ currentQuestion.title }</p>
<div className='options-container'>{ optionsList }</div>
</div>
<div className='buttons-container'>
{
(checkedOptionId != 0 && submitDisabled && questionStatus != 'disable') ?
<p>Select another option to try again or move on to next question.</p>
: ``
}
{
(checkedOptionId != 0 && submitDisabled) ?
<button className='quiz-button' onClick={ nextQuestion }>{currentIndex >= (questionsLength-1) ? 'Done' :'Next Question'}</button>
: ``
}
{
!submitDisabled ?
<button className='quiz-button' onClick={ checkAnswer }>Submit</button>
: ``
}
</div>
</div>
:
<div>Completed !!</div>
}
</div>
);
};
export default QuestionsList;
\ No newline at end of file
import React from 'react';
import QuestionsList from './QuestionsList';
const QuizComponent = () => {
return (
<div>
<QuestionsList/>
</div>
);
};
export default QuizComponent;
\ No newline at end of file
.question-container{
border: 2px solid #658c99;
width: 70%;
margin: 20px auto;
}
.options-container{
background-color: #e6ecf1;
}
.option-title{
margin: 0px;
padding: 15px 20px;
text-align: left;
border-top: 1px solid #658c99;
font-size: 14px;
}
.option-label{
display: flex;
align-items: center;
}
.question-index{
font-size: 14px;
text-align: left;
margin: 0px;
padding: 15px 20px 0px 20px;
color: #545757;
}
.question-title{
font-size: 16px;
text-align: left;
margin: 0px;
padding: 5px 20px 15px 20px;
font-weight: 600;
}
.option-input{
content: url('../icons/oval.png');
height: 16px;
width: 16px;
margin: 0px 10px 0px 0px;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
.option-input:checked{
content: url('../icons/button.png');
}
.buttons-container{
display: flex;
width: 70%;
margin: auto;
justify-content: end;
}
.quiz-button{
background-color: #315662;
border: 0;
padding: 10px 20px;
margin-left: 20px;
border-radius: 5px;
cursor: pointer;
color: white;
font-size: 16px;
font-weight: 600;
}
.quiz-button:disabled{
border: 2px solid #315662;
background-color: white;
color: #315662;
cursor: not-allowed;
font-size: 16px;
font-weight: 600;
}
.option-result{
margin: 0;
text-align: left;
padding: 5px 0px 0px 26px;
font-weight: 600;
}
.correct-option{
color: green;
}
.incorrect-option{
color: red;
}
\ No newline at end of file
{
"data":[
{
"id":1,
"questions": [
{
"id":1,
"title":"Quiz1 Question1",
"options":[
{
"id":1,
"option":"Question1 option1",
"status":"unset"
},
{
"id":2,
"option":"Question1 option2",
"status":"unset"
},
{
"id":3,
"option":"Question1 option3",
"status":"unset"
}
],
"correctOptionId":1
},
{
"id":2,
"title":"Quiz1 Question2",
"options":[
{
"id":1,
"option":"Question2 option1",
"status":"unset"
},
{
"id":2,
"option":"Question2 option2",
"status":"unset"
},
{
"id":3,
"option":"Question2 option3",
"status":"unset"
}
],
"correctOptionId":2
},
{
"id":3,
"title":"Quiz1 Question3",
"options":[
{
"id":1,
"option":"Question3 option1",
"status":"unset"
},
{
"id":2,
"option":"Question3 option2",
"status":"unset"
},
{
"id":3,
"option":"Question3 option3",
"status":"unset"
}
],
"correctOptionId":3
},
{
"id":4,
"title":"Quiz1 Question4",
"options":[
{
"id":1,
"option":"Question4 option1",
"status":"unset"
},
{
"id":2,
"option":"Question4 option2",
"status":"unset"
},
{
"id":3,
"option":"Question4 option3",
"status":"unset"
}
],
"correctOptionId":1
},
{
"id":5,
"title":"Quiz1 Question5",
"options":[
{
"id":1,
"option":"Question5 option1",
"status":"unset"
},
{
"id":2,
"option":"Question5 option2",
"status":"unset"
},
{
"id":3,
"option":"Question5 option3",
"status":"unset"
}
],
"correctOptionId":2
},
{
"id":6,
"title":"Quiz1 Question6",
"options":[
{
"id":1,
"option":"Question6 option1",
"status":"unset"
},
{
"id":2,
"option":"Question6 option2",
"status":"unset"
},
{
"id":3,
"option":"Question6 option3",
"status":"unset"
}
],
"correctOptionId":3
}
]
},
{
"id":2,
"questions": [
{
"id":4,
"title":"Quiz2 Question1",
"options":[
{
"id":1,
"option":"Question1 option1",
"status":"unset"
},
{
"id":2,
"option":"Question1 option2",
"status":"unset"
},
{
"id":3,
"option":"Question1 option3",
"status":"unset"
}
],
"correctOptionId":1
},
{
"id":5,
"title":"Quiz2 Question2",
"options":[
{
"id":1,
"option":"Question2 option1",
"status":"unset"
},
{
"id":2,
"option":"Question2 option2",
"status":"unset"
},
{
"id":3,
"option":"Question2 option3",
"status":"unset"
}
],
"correctOptionId":2
},
{
"id":6,
"title":"Quiz2 Question3",
"options":[
{
"id":1,
"option":"Question3 option1",
"status":"unset"
},
{
"id":2,
"option":"Question3 option2",
"status":"unset"
},
{
"id":3,
"option":"Question3 option3",
"status":"unset"
}
],
"correctOptionId":3
}
]
}
]
}
\ No newline at end of file
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
import React from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import store from './redux/store';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
import { ActionTypes } from "../constants/action-types";
export const setQuiz = (questions) => {
return {
type: ActionTypes.SET_QUIZ,
payload: questions,
};
};
export const setCurrentQuestion = (question) => {
return {
type: ActionTypes.SET_CURRENT_QUESTION,
payload: question,
};
};
export const setQuizScore = (score) => {
return {
type: ActionTypes.SET_QUIZ_SCORE,
payload: score,
};
};
export const setSelectedOption = (option) => {
return {
type: ActionTypes.SET_SELECTED_OPTION,
payload: option,
}
}
export const setCurrentIndex = (index) => {
return {
type: ActionTypes.SET_CURRENT_INDEX,
payload: index,
}
}
export const toggleSubmit = (value) => {
return {
type: ActionTypes.TOGGLE_SUBMIT,
payload: value,
}
}
export const setOptionStatus = (status) => {
return {
type: ActionTypes.SET_OPTION_STATUS,
payload: status,
}
}
\ No newline at end of file
export const ActionTypes = {
SET_QUIZ : "SET_QUIZ",
SET_QUIZ_SCORE : "SET_QUIZ_SCORE",
SET_CURRENT_QUESTION: "SET_CURRENT_QUESTION",
SET_SELECTED_OPTION: "SET_SELECTED_OPTION",
SET_CURRENT_INDEX: "SET_CURRENT_INDEX",
TOGGLE_SUBMIT: "TOGGLE_SUBMIT",
SET_OPTION_STATUS: "SET_OPTION_STATUS",
};
\ No newline at end of file
import { combineReducers } from 'redux';
import { quizReducer, questionReducer } from "./quizReducer";
const reducers = combineReducers({
quiz: quizReducer,
question: questionReducer,
});
export default reducers;
\ No newline at end of file
import { ActionTypes } from '../constants/action-types';
const quizInitialState = {
questionsList:{},
questionsLength:0,
quizScores:[],
}
const questionInitialState = {
currentQuestion:{},
currentIndex:0,
checkedOptionId:0,
submitDisabled:true,
questionStatus:'unset',
}
export const quizReducer = (state = quizInitialState, {type, payload}) => {
switch (type) {
case ActionTypes.SET_QUIZ:
return {...state, questionsList: payload, questionsLength: payload.questions.length};
default:
return state;
}
};
export const questionReducer = (state = questionInitialState, {type, payload}) => {
switch (type) {
case ActionTypes.SET_CURRENT_QUESTION:
return {...state, currentQuestion: payload};
case ActionTypes.SET_CURRENT_INDEX:
return {...state, currentIndex: payload}
case ActionTypes.SET_SELECTED_OPTION:
return {...state, checkedOptionId: payload};
case ActionTypes.TOGGLE_SUBMIT:
return {...state, submitDisabled: payload};
case ActionTypes.SET_OPTION_STATUS:
let {currentQuestion} = state;
let setStatus = 'unset';
if(payload.status == 'correct'){
setStatus = 'disable';
}
const newOptions = currentQuestion.options.map(option => {
if(option.id == payload.id){
return {...option, status: payload.status}
}
else{
if(option.status == 'unset')
return {...option, status: setStatus}
else
return option;
// return {...option, status: 'disable'}
}
});
let newQuestion = {...currentQuestion, options:newOptions}
return {...state, currentQuestion: newQuestion, questionStatus:setStatus}
default:
return state;
}
};
\ No newline at end of file
import { createStore } from 'redux';
import reducers from "./reducers/index";
const store = createStore(
reducers,
{},
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
export default store;
\ No newline at end of file
const reportWebVitals = onPerfEntry => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
});
}
};
export default reportWebVitals;
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment