made the quiz functional

Signed-off-by: Alex Stan <alex.stan.2010@proton.me>

Fixed merge conflicts
This commit is contained in:
Alex Stan 2024-06-01 21:36:06 +03:00
parent 48efcce544
commit 1c6c5327c3
6 changed files with 127 additions and 32 deletions

View 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;

View file

@ -1,5 +1,5 @@
import { PlayIcon } from '@heroicons/react/24/outline' import { PlayIcon } from '@heroicons/react/24/outline'
const TopicCard = ({ title, children, link }) => { const TopicCard = ({ title, children, link }: { title: string, children: any, link: string }) => {
return( 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'}}> <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 <svg

View file

@ -8,7 +8,51 @@ import { CheckIcon } from '@heroicons/react/20/solid';
const Page = ({ params }: { params: { category: string }}) => { const Page = ({ params }: { params: { category: string }}) => {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false) 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 ( return (
<div> <div>
@ -27,35 +71,11 @@ const Page = ({ params }: { params: { category: string }}) => {
}} }}
/> />
</div> </div>
<div className="mx-auto max-w-2xl py-32 sm:py-48 lg:py-56"> <div style={{paddingTop: '72px'}}></div>
<div className="text-center"> <Logo/>
<h1 className="text-4xl font-bold tracking-tight text-gray-50"> {/* <QuestionView key = {questions[0].id} question={questions[0]} state={state} setState={setState}/> */}
[insert question about {params.category}] {questions.map( (q) => (q.answered == AnswerType.Unset) ? <QuestionView key = {q.id} question={q} state={state} setState={setState}/> : <></>)}
</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 <div
className="absolute inset-x-0 top-[calc(100%-13rem)] -z-10 transform-gpu overflow-hidden blur-3xl sm:top-[calc(100%-30rem)]" 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" aria-hidden="true"

View file

@ -7,18 +7,29 @@ export const enum QuizQuestion {
DR DR
}; };
export const enum AnswerType {
Unset,
Right,
Wrong
};
export type Question = { export type Question = {
id: number; id: number;
category: string | null; 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; text: string;
answer: string | boolean | QuizQuestion; answer: string | boolean | QuizQuestion;
answered?: AnswerType;
} }
export const getQuestion = async (id: number): Promise<Question> => { export const getQuestion = async (id: number): Promise<Question> => {
return makeGetRequest( `questions/${id}/` ); return makeGetRequest( `questions/${id}/` );
} }
export const getQuestions = async (): Promise<Question[]> => {
return makeGetRequest( `questions/` );
}
export const addQuestion = async (question: Question): Promise<Question> => { export const addQuestion = async (question: Question): Promise<Question> => {
console.log( `adding question ${JSON.stringify( question)}` ); console.log( `adding question ${JSON.stringify( question)}` );
return makePostRequest( `questions`, question ); return makePostRequest( `questions`, question );

View file

@ -1,4 +1,5 @@
import { makeGetRequest, makePostRequest } from "./api"; import { makeGetRequest, makePostRequest } from "./api";
import { AnswerType } from "./question";
export type Session = { export type Session = {
id: number; id: number;
@ -13,6 +14,8 @@ export type SessionState = {
wrong: number; wrong: number;
right: number; right: number;
category: string; category: string;
opened: boolean[];
answer: AnswerType[];
} }
export const getSession = async (id: number): Promise<Session> => { export const getSession = async (id: number): Promise<Session> => {