made the quiz functional
Signed-off-by: Alex Stan <alex.stan.2010@proton.me> Fixed merge conflicts
This commit is contained in:
parent
48efcce544
commit
1c6c5327c3
6 changed files with 127 additions and 32 deletions
|
@ -177,4 +177,4 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
|
|
61
app/components/question_component.tsx
Normal file
61
app/components/question_component.tsx
Normal file
|
@ -0,0 +1,61 @@
|
|||
import { ReactComponentElement, ReactNode } from "react";
|
||||
import { AnswerType, Question } from "../lib/question";
|
||||
import { SessionState } from "../lib/session";
|
||||
|
||||
const QuestionView = ({ question, setState, state }: { question: Question, setState: any, state: SessionState }) => {
|
||||
|
||||
const handleOpenClick = () => {
|
||||
setState( (prevState: SessionState) => ({
|
||||
...prevState,
|
||||
opened: {
|
||||
...prevState.opened,
|
||||
[question.id]: !prevState.opened[ question.id ]
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
const handleAnswerClick = (right: boolean) => {
|
||||
setState( (prevState: SessionState) => ({
|
||||
...prevState,
|
||||
answer: {
|
||||
...prevState.answer,
|
||||
[question.id]: right ? AnswerType.Right : AnswerType.Wrong
|
||||
}
|
||||
}))
|
||||
question.answered = right ? AnswerType.Right : AnswerType.Wrong;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-2xl py-32 sm:py-48 lg:py-56">
|
||||
<div className="text-center">
|
||||
<h1 className="text-4xl font-bold tracking-tight text-gray-50">
|
||||
{question.text}
|
||||
</h1>
|
||||
{state.opened[ question.id ] ? (
|
||||
<p className="mt-6 text-lg leading-8 text-gray-200">
|
||||
{question.answer}
|
||||
</p>
|
||||
) : null}
|
||||
<button className="text-sm font-semibold leading-6 text-gray-200" onClick={handleOpenClick}>
|
||||
Show answer
|
||||
</button>
|
||||
<div className="mt-10 flex items-center justify-center gap-x-6">
|
||||
<button
|
||||
onClick={() => { handleAnswerClick( true )}}
|
||||
className="rounded-md bg-indigo-600 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
|
||||
>
|
||||
I knew that!
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {handleAnswerClick( false )}}
|
||||
className="text-sm font-semibold leading-6 text-gray-300"
|
||||
>
|
||||
I didn't know that!
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default QuestionView;
|
|
@ -1,5 +1,5 @@
|
|||
import { PlayIcon } from '@heroicons/react/24/outline'
|
||||
const TopicCard = ({ title, children, link }) => {
|
||||
const TopicCard = ({ title, children, link }: { title: string, children: any, link: string }) => {
|
||||
return(
|
||||
<div className="mx-auto mt-16 max-w-2xl rounded-3xl sm:mt-20 lg:mx-0 lg:flex lg:max-w-none relative isolate overflow-hidden bg-gray-900 px-6 pt-16 shadow-2xl sm:rounded-3xl sm:px-16 md:pt-24 lg:flex lg:gap-x-20 lg:px-24 lg:pt-0" style={{marginTop: '20px', paddingTop: '0px', paddingBottom: '24px'}}>
|
||||
<svg
|
||||
|
|
|
@ -8,7 +8,51 @@ import { CheckIcon } from '@heroicons/react/20/solid';
|
|||
|
||||
const Page = ({ params }: { params: { category: string }}) => {
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
|
||||
const [state, setState]: [SessionState, any] = useState<SessionState>( {
|
||||
answered: 0,
|
||||
wrong: 0,
|
||||
right: 0,
|
||||
category: '',
|
||||
opened: [],
|
||||
answer: []
|
||||
} );
|
||||
|
||||
// const category = params.category;
|
||||
|
||||
// const [all_questions, set_all_questions] = useState<Question[]>([]);
|
||||
const [questions, setQuestions] = useState<Question[]>([]);
|
||||
|
||||
useEffect( () => {
|
||||
// console.log( params.category );
|
||||
const fetch_all_questions = async () => {
|
||||
let result = await getQuestions();
|
||||
console.log( `all_questions: ${ JSON.stringify( result ) }` );
|
||||
// set_all_questions( result );
|
||||
result = result.filter( q => q.category === params.category)
|
||||
.map(it=>({...it, answered: AnswerType.Unset}));
|
||||
//result = result.filter
|
||||
setQuestions( result );
|
||||
console.log( `q12 uestions: ${ JSON.stringify( questions ) }`, result );
|
||||
}
|
||||
fetch_all_questions();
|
||||
|
||||
var ans: AnswerType[];
|
||||
questions?.forEach(q => {
|
||||
ans[ q.id ] = AnswerType.Unset;
|
||||
});
|
||||
|
||||
/*
|
||||
setState( (prevState: SessionState) => ({
|
||||
...prevState,
|
||||
answer: ans
|
||||
}));
|
||||
*/
|
||||
}, [ params.category ]);
|
||||
|
||||
console.log( "questions16", questions );
|
||||
|
||||
|
||||
console.log( "state15", state );
|
||||
return (
|
||||
<div>
|
||||
|
||||
|
@ -27,35 +71,11 @@ const Page = ({ params }: { params: { category: string }}) => {
|
|||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="mx-auto max-w-2xl py-32 sm:py-48 lg:py-56">
|
||||
<div className="text-center">
|
||||
<h1 className="text-4xl font-bold tracking-tight text-gray-50">
|
||||
[insert question about {params.category}]
|
||||
</h1>
|
||||
<p className="mt-6 text-lg leading-8 text-gray-200">
|
||||
[Insert hidden answer]
|
||||
</p>
|
||||
<a href="#" className="text-sm font-semibold leading-6 text-gray-200">
|
||||
Show answer
|
||||
</a>
|
||||
<div className="mt-10 flex items-center justify-center gap-x-6">
|
||||
<a
|
||||
href="#"
|
||||
className="rounded-md bg-indigo-600 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
|
||||
>
|
||||
<CheckIcon width={'100px'}></CheckIcon>
|
||||
I did know
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
className="rounded-md bg-gray-600 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-gray-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
|
||||
>
|
||||
<XMarkIcon width={'100px'}></XMarkIcon>
|
||||
I didn't know
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{paddingTop: '72px'}}></div>
|
||||
<Logo/>
|
||||
{/* <QuestionView key = {questions[0].id} question={questions[0]} state={state} setState={setState}/> */}
|
||||
{questions.map( (q) => (q.answered == AnswerType.Unset) ? <QuestionView key = {q.id} question={q} state={state} setState={setState}/> : <></>)}
|
||||
|
||||
<div
|
||||
className="absolute inset-x-0 top-[calc(100%-13rem)] -z-10 transform-gpu overflow-hidden blur-3xl sm:top-[calc(100%-30rem)]"
|
||||
aria-hidden="true"
|
||||
|
|
|
@ -7,18 +7,29 @@ export const enum QuizQuestion {
|
|||
DR
|
||||
};
|
||||
|
||||
export const enum AnswerType {
|
||||
Unset,
|
||||
Right,
|
||||
Wrong
|
||||
};
|
||||
|
||||
export type Question = {
|
||||
id: number;
|
||||
category: string | null;
|
||||
type: string | null; // TODO: make a TS type for every question type
|
||||
type?: string; // TODO: make a TS type for every question type
|
||||
text: string;
|
||||
answer: string | boolean | QuizQuestion;
|
||||
answered?: AnswerType;
|
||||
}
|
||||
|
||||
export const getQuestion = async (id: number): Promise<Question> => {
|
||||
return makeGetRequest( `questions/${id}/` );
|
||||
}
|
||||
|
||||
export const getQuestions = async (): Promise<Question[]> => {
|
||||
return makeGetRequest( `questions/` );
|
||||
}
|
||||
|
||||
export const addQuestion = async (question: Question): Promise<Question> => {
|
||||
console.log( `adding question ${JSON.stringify( question)}` );
|
||||
return makePostRequest( `questions`, question );
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { makeGetRequest, makePostRequest } from "./api";
|
||||
import { AnswerType } from "./question";
|
||||
|
||||
export type Session = {
|
||||
id: number;
|
||||
|
@ -13,6 +14,8 @@ export type SessionState = {
|
|||
wrong: number;
|
||||
right: number;
|
||||
category: string;
|
||||
opened: boolean[];
|
||||
answer: AnswerType[];
|
||||
}
|
||||
|
||||
export const getSession = async (id: number): Promise<Session> => {
|
||||
|
|
Loading…
Reference in a new issue