quiz page adjustments
This commit is contained in:
parent
15ac1ca1c7
commit
a4eae0e528
|
|
@ -1,19 +1,21 @@
|
|||
'use client';
|
||||
"use client";
|
||||
|
||||
import { Queries } from '@/api/queries';
|
||||
import Loader from '@/components/Loader';
|
||||
import QuizQuestion from '@/components/quiz/QuizQuestion';
|
||||
import QuizQuestionList from '@/components/quiz/QuizQuestionList';
|
||||
import QuizSearch from '@/components/quiz/QuizSearch';
|
||||
import QuizTable from '@/components/quiz/QuizTable';
|
||||
import QuizWinnerTable from '@/components/quiz/QuizWinnerTable';
|
||||
import GradientTitle from '@/components/vote/GradientTitle';
|
||||
import { IQuizQuestions, Question } from '@/models/quizQuestions.model';
|
||||
import QuizProvider from '@/providers/QuizProvider';
|
||||
import { Validator } from '@/utils/validator';
|
||||
import Image from 'next/image';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useMediaQuery } from 'usehooks-ts';
|
||||
import { Queries } from "@/api/queries";
|
||||
import Loader from "@/components/Loader";
|
||||
import QuizQuestion from "@/components/quiz/QuizQuestion";
|
||||
import QuizQuestionList from "@/components/quiz/QuizQuestionList";
|
||||
import QuizSearch from "@/components/quiz/QuizSearch";
|
||||
import QuizTable from "@/components/quiz/QuizTable";
|
||||
import QuizWinnerTable from "@/components/quiz/QuizWinnerTable";
|
||||
import GradientTitle from "@/components/vote/GradientTitle";
|
||||
import QuizContext from "@/context/QuizContext";
|
||||
import { IQuizQuestions, Question } from "@/models/quizQuestions.model";
|
||||
import QuizProvider from "@/providers/QuizProvider";
|
||||
import { useQuizSearchActive } from "@/store/store";
|
||||
import { Validator } from "@/utils/validator";
|
||||
import Image from "next/image";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { useMediaQuery } from "usehooks-ts";
|
||||
|
||||
interface IParams {
|
||||
params: {
|
||||
|
|
@ -24,6 +26,7 @@ interface IParams {
|
|||
const page = ({ params }: IParams) => {
|
||||
const [quizFinished, setQuizFinished] = useState<boolean>(false);
|
||||
const [data, setData] = useState<IQuizQuestions>();
|
||||
const { active } = useQuizSearchActive();
|
||||
|
||||
// const { data, error, isFetching } = useQuery(
|
||||
// ['quiz_questions'],
|
||||
|
|
@ -38,7 +41,8 @@ const page = ({ params }: IParams) => {
|
|||
Queries.getQuizQuestions().then((res) => {
|
||||
setData(res);
|
||||
res
|
||||
? res.data.questions[res.data.questions.length - 1].status === 'closed'
|
||||
? res.data.questions[res.data.questions.length - 1].status ===
|
||||
"closed"
|
||||
? setQuizFinished(true)
|
||||
: setQuizFinished(false)
|
||||
: null;
|
||||
|
|
@ -47,7 +51,8 @@ const page = ({ params }: IParams) => {
|
|||
Queries.getQuiz(params.quiz_id).then((res) => {
|
||||
setData(res);
|
||||
res
|
||||
? res.data.questions[res.data.questions.length - 1]?.status === 'closed'
|
||||
? res.data.questions[res.data.questions.length - 1]?.status ===
|
||||
"closed"
|
||||
? setQuizFinished(true)
|
||||
: setQuizFinished(false)
|
||||
: null;
|
||||
|
|
@ -55,7 +60,7 @@ const page = ({ params }: IParams) => {
|
|||
}
|
||||
}, []);
|
||||
|
||||
const mobile = useMediaQuery('(max-width: 768px)');
|
||||
const mobile = useMediaQuery("(max-width: 768px)");
|
||||
|
||||
if (data) {
|
||||
if (!data.data) {
|
||||
|
|
@ -70,7 +75,7 @@ const page = ({ params }: IParams) => {
|
|||
|
||||
return (
|
||||
<main className="pt-[60px] pb-[200px]">
|
||||
{typeof data !== 'string' ? (
|
||||
{typeof data !== "string" ? (
|
||||
<div className="container flex flex-col md:gap-[200px] gap-[80px]">
|
||||
<QuizProvider>
|
||||
<div className="flex flex-col gap-[100px]">
|
||||
|
|
@ -95,7 +100,7 @@ const page = ({ params }: IParams) => {
|
|||
? data.data.banner_mobile
|
||||
: data.data.banner
|
||||
}
|
||||
alt={'banner'}
|
||||
alt={"banner"}
|
||||
unoptimized
|
||||
unselectable="off"
|
||||
fill
|
||||
|
|
@ -104,7 +109,7 @@ const page = ({ params }: IParams) => {
|
|||
) : (
|
||||
<Image
|
||||
src={data?.data.banner}
|
||||
alt={'banner'}
|
||||
alt={"banner"}
|
||||
unoptimized
|
||||
unselectable="off"
|
||||
fill
|
||||
|
|
@ -116,14 +121,15 @@ const page = ({ params }: IParams) => {
|
|||
</div>
|
||||
|
||||
{data?.data.rules && data.data.notes ? (
|
||||
<QuizTable rules={data?.data.rules} notes={data?.data.notes} />
|
||||
<QuizTable
|
||||
rules={data?.data.rules}
|
||||
notes={data?.data.notes}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
{data?.data.id && quizFinished ? <QuizSearch quizId={data?.data.id} /> : null}
|
||||
|
||||
<div className="flex flex-col md:gap-[160px] gap-[80px]">
|
||||
{data?.data ? (
|
||||
{data?.data && !active ? (
|
||||
<QuizQuestionList
|
||||
paramsId={params.quiz_id}
|
||||
initialQuestionsData={data}
|
||||
|
|
@ -132,6 +138,10 @@ const page = ({ params }: IParams) => {
|
|||
/>
|
||||
) : null}
|
||||
|
||||
{data?.data.id && quizFinished ? (
|
||||
<QuizSearch quizId={data?.data.id} />
|
||||
) : null}
|
||||
|
||||
{data?.data.id && (
|
||||
<QuizWinnerTable
|
||||
smsNumber={data.data.sms_number}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
'use client';
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { Queries } from '@/api/queries';
|
||||
import Loader from '../Loader';
|
||||
import { IQuizQuestionsHistory } from '@/models/quizQuestionHistory.model';
|
||||
import { Validator } from '@/utils/validator';
|
||||
import { v4 } from 'uuid';
|
||||
import QuizContext from '@/context/QuizContext';
|
||||
"use client";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { Queries } from "@/api/queries";
|
||||
import Loader from "../Loader";
|
||||
import { IQuizQuestionsHistory } from "@/models/quizQuestionHistory.model";
|
||||
import { Validator } from "@/utils/validator";
|
||||
import { v4 } from "uuid";
|
||||
import QuizContext from "@/context/QuizContext";
|
||||
|
||||
type TProps = {
|
||||
finished: string;
|
||||
|
|
@ -15,13 +15,19 @@ type TProps = {
|
|||
|
||||
const QuizAccordion = ({ finished, questionId }: TProps) => {
|
||||
const [data, setData] = useState<IQuizQuestionsHistory>();
|
||||
const [opened, setOpened] = useState<boolean>(finished === 'closed' ? false : true);
|
||||
const [opened, setOpened] = useState<boolean>(
|
||||
finished === "closed" ? false : true
|
||||
);
|
||||
|
||||
const { quizSearchData } = useContext(QuizContext).quizSearchContext;
|
||||
const { searchActive } = useContext(QuizContext).quizSearchActiveContext;
|
||||
|
||||
useEffect(() => {
|
||||
if (quizSearchData && Object.values(quizSearchData.data).length != 0 && searchActive) {
|
||||
if (
|
||||
quizSearchData &&
|
||||
Object.values(quizSearchData.data).length != 0 &&
|
||||
searchActive
|
||||
) {
|
||||
setOpened(true);
|
||||
} else {
|
||||
setOpened(false);
|
||||
|
|
@ -56,10 +62,14 @@ const QuizAccordion = ({ finished, questionId }: TProps) => {
|
|||
<>
|
||||
<motion.div
|
||||
initial={{ height: 0, opacity: 0 }}
|
||||
animate={{ height: 'auto', opacity: 1 }}
|
||||
animate={{ height: "auto", opacity: 1 }}
|
||||
exit={{ height: 0, opacity: 0 }}
|
||||
transition={{ duration: 0.3 }}>
|
||||
<div className="flex bg-fillTableHead md:p-0 gap-3 md:gap-0 border-b border-fillTableStrokeTableHead p-[8px] w-full">
|
||||
transition={{ duration: 0.3 }}
|
||||
>
|
||||
<div
|
||||
onClick={() => setOpened(!opened)}
|
||||
className="flex bg-fillTableHead md:p-0 gap-3 md:gap-0 border-b border-fillTableStrokeTableHead p-[8px] w-full cursor-pointer"
|
||||
>
|
||||
<div className="block text-[12px] sm:text-base text-textBlack leading-[125%] font-semibold max-w-[15px] sm:max-w-[100px] w-full sm:px-6 sm:py-5">
|
||||
<span>№</span>
|
||||
</div>
|
||||
|
|
@ -83,9 +93,12 @@ const QuizAccordion = ({ finished, questionId }: TProps) => {
|
|||
{data.data.map((user, id) => (
|
||||
<div
|
||||
className={`flex border-b border-fillTableStrokeTableRow last:border-none ${
|
||||
id % 2 === 0 ? ' bg-fillTableRow' : 'bg-fillTableRow2'
|
||||
id % 2 === 0
|
||||
? " bg-fillTableRow"
|
||||
: "bg-fillTableRow2"
|
||||
}`}
|
||||
key={v4()}>
|
||||
key={v4()}
|
||||
>
|
||||
<div className="block text-base text-textBlack leading-[125%] max-w-[100px] w-[100%] px-6 py-5">
|
||||
<span>{id + 1}</span>
|
||||
</div>
|
||||
|
|
@ -111,9 +124,12 @@ const QuizAccordion = ({ finished, questionId }: TProps) => {
|
|||
{data.data.map((user, id) => (
|
||||
<div
|
||||
className={`flex items-center justify-center flex-col border-b border-fillTableStrokeTableRow last:border-none p-[8px] gap-1 ${
|
||||
id % 2 === 0 ? ' bg-fillTableRow' : 'bg-fillTableRow2'
|
||||
id % 2 === 0
|
||||
? " bg-fillTableRow"
|
||||
: "bg-fillTableRow2"
|
||||
}`}
|
||||
key={v4()}>
|
||||
key={v4()}
|
||||
>
|
||||
<div className="flex gap-[12px] w-full items-center">
|
||||
<div className="block text-[12px] text-textBlack leading-[125%] max-w-[15px] w-full">
|
||||
<span>{id + 1}</span>
|
||||
|
|
@ -147,9 +163,12 @@ const QuizAccordion = ({ finished, questionId }: TProps) => {
|
|||
<div key={v4()}>
|
||||
<div
|
||||
className={`sm:flex border-b border-fillTableStrokeTableRow last:border-none hidden ${
|
||||
answerId % 2 === 0 ? ' bg-fillTableRow' : 'bg-fillTableRow2'
|
||||
answerId % 2 === 0
|
||||
? " bg-fillTableRow"
|
||||
: "bg-fillTableRow2"
|
||||
}`}
|
||||
key={v4()}>
|
||||
key={v4()}
|
||||
>
|
||||
<div className="block text-base leading-[125%] max-w-[100px] w-[100%] px-6 py-5">
|
||||
{answer.serial_number_for_correct != null ? (
|
||||
<span className="text-fillGreen">
|
||||
|
|
@ -177,12 +196,16 @@ const QuizAccordion = ({ finished, questionId }: TProps) => {
|
|||
|
||||
<div
|
||||
className={`sm:hidden flex items-center justify-center flex-col border-b border-fillTableStrokeTableRow last:border-none p-[8px] gap-1 ${
|
||||
answerId % 2 === 0 ? ' bg-fillTableRow' : 'bg-fillTableRow2'
|
||||
answerId % 2 === 0
|
||||
? " bg-fillTableRow"
|
||||
: "bg-fillTableRow2"
|
||||
}`}
|
||||
key={v4()}>
|
||||
key={v4()}
|
||||
>
|
||||
<div className="flex gap-[12px] w-full items-center">
|
||||
<div className="block text-[12px] leading-[125%] max-w-[15px] w-full">
|
||||
{answer.serial_number_for_correct != null ? (
|
||||
{answer.serial_number_for_correct !=
|
||||
null ? (
|
||||
<span className="text-fillGreen">
|
||||
{answer.serial_number_for_correct}
|
||||
</span>
|
||||
|
|
@ -204,12 +227,14 @@ const QuizAccordion = ({ finished, questionId }: TProps) => {
|
|||
</div>
|
||||
</div>
|
||||
<div className="text-[12px] text-textDarkt leading-[125%] max-w-[289px] w-[100%] text-center">
|
||||
<span>Wagty: {Validator.parseDate(answer.dt)}</span>
|
||||
<span>
|
||||
Wagty: {Validator.parseDate(answer.dt)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
: null,
|
||||
: null
|
||||
)
|
||||
: null}
|
||||
</motion.div>
|
||||
|
|
@ -217,12 +242,15 @@ const QuizAccordion = ({ finished, questionId }: TProps) => {
|
|||
)}
|
||||
</AnimatePresence>
|
||||
) : null}
|
||||
{finished === 'closed' ? (
|
||||
{finished === "closed" ? (
|
||||
<button
|
||||
onClick={() => setOpened(!opened)}
|
||||
className={`w-full ${
|
||||
opened ? 'bg-fillRed text-white' : 'bg-fillButtonLowContrastDefault text-textDarkt'
|
||||
} flex items-center justify-center text-xs md:text-base uppercase leading-[150%] p-[8px] md:py-5 gap-[5px] md:gap-[10px] transition-all delay-[0.2s] font-medium `}>
|
||||
opened
|
||||
? "bg-fillRed text-white"
|
||||
: "bg-fillButtonLowContrastDefault text-textDarkt"
|
||||
} flex items-center justify-center text-xs md:text-base uppercase leading-[150%] p-[8px] md:py-5 gap-[5px] md:gap-[10px] transition-all delay-[0.2s] font-medium `}
|
||||
>
|
||||
Netijeler
|
||||
<div>
|
||||
<svg
|
||||
|
|
@ -231,10 +259,11 @@ const QuizAccordion = ({ finished, questionId }: TProps) => {
|
|||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
className="w-[20px] h-[20px] md:w-[24px] md:h-[24px]">
|
||||
className="w-[20px] h-[20px] md:w-[24px] md:h-[24px]"
|
||||
>
|
||||
<path
|
||||
d="M7.41 15.41L12 10.83L16.59 15.41L18 14L12 8L6 14L7.41 15.41Z"
|
||||
fill={`${opened ? '#fff' : '#636370'}`}
|
||||
fill={`${opened ? "#fff" : "#636370"}`}
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -63,29 +63,8 @@ const QuizQuestionList = ({
|
|||
);
|
||||
});
|
||||
|
||||
// const isActive = data?.data.questions.some(
|
||||
// (question) => question.status === 'active' || question.status === 'new',
|
||||
// );
|
||||
|
||||
// data.data.questions.map((question) =>
|
||||
// question.status === 'active' || question.status === 'new'
|
||||
// ? setQuizFinished(false)
|
||||
// : setQuizFinished(true),
|
||||
// );
|
||||
}, 60000);
|
||||
return () => clearInterval(interval);
|
||||
|
||||
// Queries.getQuizQuestions().then((res) => {
|
||||
// setData(res);
|
||||
// setQuestionsData(res.data.questions);
|
||||
// setSmsNumber(res.data.sms_number);
|
||||
|
||||
// res.data.questions.map((question) =>
|
||||
// question.status === 'active' || question.status === 'new'
|
||||
// ? setQuizFinished(false)
|
||||
// : setQuizFinished(true),
|
||||
// );
|
||||
// });
|
||||
}
|
||||
}, [quizFinished]);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
'use client';
|
||||
import QuizContext from '@/context/QuizContext';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { ChangeEvent, FormEvent, useContext, useState } from 'react';
|
||||
"use client";
|
||||
import QuizContext from "@/context/QuizContext";
|
||||
import { useQuizSearchActive } from "@/store/store";
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import { ChangeEvent, FormEvent, useContext, useState } from "react";
|
||||
|
||||
const QuizSearch = ({ quizId }: { quizId: number }) => {
|
||||
const [phone, setPhone] = useState<string>('');
|
||||
const [phone, setPhone] = useState<string>("");
|
||||
const { setActive } = useQuizSearchActive();
|
||||
|
||||
const { setSearchActive } = useContext(QuizContext).quizSearchActiveContext;
|
||||
|
||||
|
|
@ -12,8 +14,9 @@ const QuizSearch = ({ quizId }: { quizId: number }) => {
|
|||
|
||||
const handleCleanSearch = () => {
|
||||
setQuizSearchData(undefined);
|
||||
setPhone('');
|
||||
setPhone("");
|
||||
setSearchActive(false);
|
||||
setActive(false);
|
||||
};
|
||||
|
||||
const handleSearchChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
|
|
@ -21,7 +24,7 @@ const QuizSearch = ({ quizId }: { quizId: number }) => {
|
|||
};
|
||||
|
||||
const handleKeyPress = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (event.key === 'Enter') {
|
||||
if (event.key === "Enter") {
|
||||
// Prevent the default form submission behavior
|
||||
event.preventDefault();
|
||||
// Call the function to handle the form submission
|
||||
|
|
@ -29,23 +32,29 @@ const QuizSearch = ({ quizId }: { quizId: number }) => {
|
|||
}
|
||||
};
|
||||
|
||||
const handleSearchSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
||||
const handleSearchSubmit = async (
|
||||
event: React.FormEvent<HTMLFormElement>
|
||||
) => {
|
||||
event.preventDefault();
|
||||
|
||||
try {
|
||||
const response = await fetch(`https://sms.turkmentv.gov.tm/api/quiz/${quizId}/search`, {
|
||||
method: 'POST',
|
||||
const response = await fetch(
|
||||
`https://sms.turkmentv.gov.tm/api/quiz/${quizId}/search`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ phone }),
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
// Handle the response as needed
|
||||
|
||||
const data = await response.json();
|
||||
setQuizSearchData(data);
|
||||
setSearchActive(true);
|
||||
setActive(true);
|
||||
} catch (error) {}
|
||||
};
|
||||
|
||||
|
|
@ -57,9 +66,10 @@ const QuizSearch = ({ quizId }: { quizId: number }) => {
|
|||
<div className="max-w-[500px] w-full flex flex-col gap-[10px] items-center ">
|
||||
<form
|
||||
onSubmit={handleSearchSubmit}
|
||||
className="bg-fillFormRest flex border w-full rounded-xl shadow-quizButton">
|
||||
className="bg-fillFormRest flex border w-full rounded-xl shadow-quizButton"
|
||||
>
|
||||
<div className="relative rounded-lg rounded-e-none w-full">
|
||||
{' '}
|
||||
{" "}
|
||||
<input
|
||||
type="tel"
|
||||
className="block w-full h-full rounded-lg rounded-e-none py-3 px-2 md:px-4 text-sm md:text-base leading-[150%] text-textCaptioninform bg-transparent"
|
||||
|
|
@ -79,13 +89,15 @@ const QuizSearch = ({ quizId }: { quizId: number }) => {
|
|||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
onClick={handleCleanSearch}>
|
||||
onClick={handleCleanSearch}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none">
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
d="M11.9998 13.4L7.0998 18.3C6.91647 18.4834 6.68314 18.575 6.3998 18.575C6.11647 18.575 5.88314 18.4834 5.6998 18.3C5.51647 18.1167 5.4248 17.8834 5.4248 17.6C5.4248 17.3167 5.51647 17.0834 5.6998 16.9L10.5998 12L5.6998 7.10005C5.51647 6.91672 5.4248 6.68338 5.4248 6.40005C5.4248 6.11672 5.51647 5.88338 5.6998 5.70005C5.88314 5.51672 6.11647 5.42505 6.3998 5.42505C6.68314 5.42505 6.91647 5.51672 7.0998 5.70005L11.9998 10.6L16.8998 5.70005C17.0831 5.51672 17.3165 5.42505 17.5998 5.42505C17.8831 5.42505 18.1165 5.51672 18.2998 5.70005C18.4831 5.88338 18.5748 6.11672 18.5748 6.40005C18.5748 6.68338 18.4831 6.91672 18.2998 7.10005L13.3998 12L18.2998 16.9C18.4831 17.0834 18.5748 17.3167 18.5748 17.6C18.5748 17.8834 18.4831 18.1167 18.2998 18.3C18.1165 18.4834 17.8831 18.575 17.5998 18.575C17.3165 18.575 17.0831 18.4834 16.8998 18.3L11.9998 13.4Z"
|
||||
fill="#BCBCD6"
|
||||
|
|
@ -97,13 +109,15 @@ const QuizSearch = ({ quizId }: { quizId: number }) => {
|
|||
</div>
|
||||
<button
|
||||
className="bg-fillButtonAccentDefault px-4 py-3 rounded-lg rounded-l-none"
|
||||
type="submit">
|
||||
type="submit"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none">
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
d="M9.5 3C11.2239 3 12.8772 3.68482 14.0962 4.90381C15.3152 6.12279 16 7.77609 16 9.5C16 11.11 15.41 12.59 14.44 13.73L14.71 14H15.5L20.5 19L19 20.5L14 15.5V14.71L13.73 14.44C12.5505 15.4468 11.0507 15.9999 9.5 16C7.77609 16 6.12279 15.3152 4.90381 14.0962C3.68482 12.8772 3 11.2239 3 9.5C3 7.77609 3.68482 6.12279 4.90381 4.90381C6.12279 3.68482 7.77609 3 9.5 3ZM9.5 5C7 5 5 7 5 9.5C5 12 7 14 9.5 14C12 14 14 12 14 9.5C14 7 12 5 9.5 5Z"
|
||||
fill="#fff"
|
||||
|
|
@ -112,7 +126,7 @@ const QuizSearch = ({ quizId }: { quizId: number }) => {
|
|||
</button>
|
||||
</form>
|
||||
<h4 className="text-sm md:text-base text-textLight">
|
||||
Her soragyň aşagynda siziň ugradan jogaplaryňyz görkeziler{' '}
|
||||
Her soragyň aşagynda siziň ugradan jogaplaryňyz görkeziler{" "}
|
||||
</h4>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { v4 } from "uuid";
|
|||
import { useState, useEffect, useContext } from "react";
|
||||
import { IQuizQuestionsWinners } from "@/models/quizQuestionsWinners.model";
|
||||
import QuizContext from "@/context/QuizContext";
|
||||
import { useQuizSearchActive } from "@/store/store";
|
||||
|
||||
interface Message {
|
||||
answer: string;
|
||||
|
|
@ -41,151 +42,21 @@ interface IProps {
|
|||
}
|
||||
|
||||
const QuizWinnerTable = ({ quizId, quizFinished, smsNumber }: IProps) => {
|
||||
// const [questionsData, setQuestionsData] = useState<IQuizQuestions>();
|
||||
const [winnersData, setWinnersData] = useState<IQuizQuestionsWinners>();
|
||||
const { questionsData } = useContext(QuizContext).quizQuestionsContext;
|
||||
|
||||
const [socket, setSocket] = useState<WebSocket | null>(null);
|
||||
const [isConnected, setIsConnected] = useState(false);
|
||||
const { quizSearchData } = useContext(QuizContext).quizSearchContext;
|
||||
const { active } = useQuizSearchActive();
|
||||
|
||||
useEffect(() => {
|
||||
if (!active) {
|
||||
Queries.getQuizWinners(quizId).then((res) => {
|
||||
setWinnersData(res);
|
||||
});
|
||||
}, [quizId]);
|
||||
|
||||
// let socket: WebSocket | null = null;
|
||||
// let reconnectTimeout: NodeJS.Timeout | null = null;
|
||||
// let pingInterval: NodeJS.Timeout | null = null;
|
||||
|
||||
// const connectWebSocket = () => {
|
||||
// try {
|
||||
// socket = new WebSocket(`wss://sms.turkmentv.gov.tm/ws/quiz?dst=${smsNumber}`);
|
||||
// setSocket(socket);
|
||||
|
||||
// socket.onopen = () => {
|
||||
// console.log('WebSocket is connected');
|
||||
// setIsConnected(true);
|
||||
|
||||
// pingInterval = setInterval(() => {
|
||||
// if (socket?.readyState === WebSocket.OPEN) {
|
||||
// try {
|
||||
// socket.send(JSON.stringify({ type: 'ping' }));
|
||||
// } catch (error) {
|
||||
// console.error('Error sending ping:', error);
|
||||
// }
|
||||
// }
|
||||
// }, 25000); // Ping every 25 seconds
|
||||
// };
|
||||
|
||||
// socket.onmessage = (event) => {
|
||||
// try {
|
||||
// console.log('Message received from WebSocket:', event.data);
|
||||
// const message = JSON.parse(event.data);
|
||||
// handleOnMessage(message);
|
||||
// } catch (error) {
|
||||
// console.error('Error processing message:', error);
|
||||
// }
|
||||
// };
|
||||
|
||||
// socket.onerror = (error) => {
|
||||
// console.error('WebSocket error:', error);
|
||||
// };
|
||||
|
||||
// socket.onclose = () => {
|
||||
// console.log('WebSocket is closed');
|
||||
// setIsConnected(false);
|
||||
|
||||
// if (pingInterval) {
|
||||
// clearInterval(pingInterval);
|
||||
// }
|
||||
|
||||
// if (!reconnectTimeout) {
|
||||
// reconnectTimeout = setTimeout(() => {
|
||||
// console.log('Attempting to reconnect WebSocket...');
|
||||
// connectWebSocket();
|
||||
// }, 5000); // Reconnect after 5 seconds
|
||||
// }
|
||||
// };
|
||||
// } catch (error) {
|
||||
// console.error('WebSocket connection error:', error);
|
||||
// }
|
||||
// };
|
||||
|
||||
// if (smsNumber && winnersData) {
|
||||
// connectWebSocket();
|
||||
// }
|
||||
|
||||
// return () => {
|
||||
// if (socket) {
|
||||
// socket.close();
|
||||
// }
|
||||
// if (reconnectTimeout) {
|
||||
// clearTimeout(reconnectTimeout);
|
||||
// }
|
||||
// if (pingInterval) {
|
||||
// clearInterval(pingInterval);
|
||||
// }
|
||||
// };
|
||||
// }, [smsNumber]);
|
||||
|
||||
// Function to handle incoming WebSocket message and update winnersData
|
||||
const handleOnMessage = (message: Message) => {
|
||||
if (!winnersData) {
|
||||
console.error("winnersData is undefined");
|
||||
return;
|
||||
} else if (active) {
|
||||
setWinnersData(undefined);
|
||||
}
|
||||
|
||||
console.log("updating winnersData");
|
||||
|
||||
// Update the winnersData by matching phone with starred_src from the message
|
||||
setWinnersData((prevWinnersData) => {
|
||||
if (!prevWinnersData) {
|
||||
return prevWinnersData;
|
||||
}
|
||||
|
||||
return {
|
||||
...prevWinnersData,
|
||||
data: prevWinnersData.data.map((winner) => {
|
||||
if (winner.client.phone === message.starred_src) {
|
||||
const updatedAnswers = [
|
||||
...winner.client.answers,
|
||||
{
|
||||
id: message.question_id,
|
||||
question_id: message.question_id,
|
||||
score: message.score,
|
||||
serial_number_for_correct: message.serial_number_for_correct,
|
||||
client_id: winner.client.id,
|
||||
},
|
||||
];
|
||||
|
||||
// Calculate the new correct_answers_time by summing serial_number_for_correct
|
||||
const updatedCorrectAnswersTime = updatedAnswers
|
||||
.reduce(
|
||||
(sum, answer) => sum + answer.serial_number_for_correct,
|
||||
0
|
||||
)
|
||||
.toString();
|
||||
|
||||
return {
|
||||
...winner,
|
||||
client: {
|
||||
...winner.client,
|
||||
answers: updatedAnswers,
|
||||
},
|
||||
total_score_of_client: (
|
||||
parseInt(winner.total_score_of_client) + message.score
|
||||
).toString(),
|
||||
correct_answers_time: updatedCorrectAnswersTime, // Update correct_answers_time
|
||||
};
|
||||
}
|
||||
return winner;
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
console.log("winnersData is updated");
|
||||
};
|
||||
}, [quizId, active]);
|
||||
|
||||
return winnersData?.data.length !== 0 ? (
|
||||
<div className="flex flex-col justify-center items-center gap-[60px]">
|
||||
|
|
@ -198,30 +69,33 @@ const QuizWinnerTable = ({ quizId, quizFinished, smsNumber }: IProps) => {
|
|||
<div className="table-desktop hidden sm:flex flex-col bg-fillTableHead rounded-[25px] shadow-quizButton overflow-hidden max-w-[1000px] w-full">
|
||||
{/* Table Head */}
|
||||
<div className="flex border-b border-fillTableStrokeTableHead">
|
||||
{winnersData?.data[0].client_id ? (
|
||||
{winnersData?.data[0].client_id || quizSearchData?.data ? (
|
||||
<div className="text-center flex justify-center items-center text-base text-textBlack leading-[125%] font-semibold max-w-[54px] w-[100%] pl-6 pr-3 py-5">
|
||||
<span>№</span>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{winnersData?.data[0].client.phone ? (
|
||||
{winnersData?.data[0].client.phone || quizSearchData?.data ? (
|
||||
<div className="text-center flex justify-center items-center text-base text-textBlack leading-[125%] font-semibold max-w-[176px] w-[100%] px-3 py-5">
|
||||
<span>Gatnaşyjynyň tel. Beligisi</span>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{winnersData?.data[0].client.answers.length !== 0 ? (
|
||||
{winnersData?.data[0].client.answers.length ||
|
||||
quizSearchData?.data ? (
|
||||
<div className="text-center flex justify-center items-center text-base text-textBlack leading-[125%] font-semibold w-[100%] px-3 py-5">
|
||||
<span>Soraglara jogap berilişiň nobaty</span>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{winnersData?.data[0].total_score_of_client ? (
|
||||
{winnersData?.data[0].total_score_of_client ||
|
||||
quizSearchData?.data ? (
|
||||
<div className="text-center flex justify-center items-center text-base text-textBlack leading-[125%] font-semibold max-w-[180px] w-[100%] px-3 py-5">
|
||||
<span>Nobatlaryň jemi</span>
|
||||
</div>
|
||||
) : null}
|
||||
{winnersData?.data[0].total_score_of_client ? (
|
||||
{winnersData?.data[0].total_score_of_client ||
|
||||
quizSearchData?.data ? (
|
||||
<div className="text-center flex justify-center items-center text-base text-textBlack leading-[125%] font-semibold max-w-[180px] w-[100%] px-3 py-5">
|
||||
<span>Utuklaryň jemi</span>
|
||||
</div>
|
||||
|
|
@ -230,7 +104,8 @@ const QuizWinnerTable = ({ quizId, quizFinished, smsNumber }: IProps) => {
|
|||
|
||||
{/* Table Body */}
|
||||
<div className="">
|
||||
{winnersData?.data.map((winner, id) => (
|
||||
{winnersData
|
||||
? winnersData?.data.map((winner, id) => (
|
||||
<div
|
||||
className={`flex border-b border-fillTableStrokeTableRow ${
|
||||
id % 2 === 0 ? "bg-fillTableRow" : "bg-fillTableRow2"
|
||||
|
|
@ -238,7 +113,13 @@ const QuizWinnerTable = ({ quizId, quizFinished, smsNumber }: IProps) => {
|
|||
key={v4()}
|
||||
>
|
||||
<div className="flex justify-center items-center text-base text-textBlack leading-[125%] max-w-[54px] w-[100%] pl-6 pr-3 py-5">
|
||||
<span>{id + 1}</span>
|
||||
<span>
|
||||
{id > 0 &&
|
||||
winner.correct_answers_time ===
|
||||
winnersData.data[id - 1].correct_answers_time
|
||||
? id
|
||||
: id + 1}
|
||||
</span>
|
||||
</div>
|
||||
{winnersData.data[0].client.phone ? (
|
||||
<div className="flex justify-center items-center text-base text-textBlack leading-[125%] font-semibold max-w-[176px] w-[100%] px-3 py-5">
|
||||
|
|
@ -264,7 +145,8 @@ const QuizWinnerTable = ({ quizId, quizFinished, smsNumber }: IProps) => {
|
|||
key={v4()}
|
||||
className={`text-sm font-semibold leading-[125%] ${
|
||||
matchingAnswer &&
|
||||
matchingAnswer.serial_number_for_correct !== 0
|
||||
matchingAnswer.serial_number_for_correct !==
|
||||
0
|
||||
? "text-fillGreen"
|
||||
: matchingAnswer &&
|
||||
matchingAnswer?.serial_number_for_correct ===
|
||||
|
|
@ -275,7 +157,8 @@ const QuizWinnerTable = ({ quizId, quizFinished, smsNumber }: IProps) => {
|
|||
>
|
||||
{matchingAnswer && matchingAnswer.score !== 0
|
||||
? matchingAnswer.serial_number_for_correct
|
||||
: matchingAnswer && matchingAnswer?.score === 0
|
||||
: matchingAnswer &&
|
||||
matchingAnswer?.score === 0
|
||||
? "X"
|
||||
: "0"}
|
||||
</span>
|
||||
|
|
@ -300,7 +183,69 @@ const QuizWinnerTable = ({ quizId, quizFinished, smsNumber }: IProps) => {
|
|||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
))}
|
||||
))
|
||||
: quizSearchData && (
|
||||
<div
|
||||
className={`flex border-b border-fillTableStrokeTableRow bg-fillTableRow2`}
|
||||
>
|
||||
{/* Place of the client */}
|
||||
<div className="flex justify-center items-center text-base text-textBlack leading-[125%] max-w-[54px] w-[100%] pl-6 pr-3 py-5">
|
||||
<span>{quizSearchData.result.place}</span>
|
||||
</div>
|
||||
{/* Client phone number */}
|
||||
<div className="flex justify-center items-center text-base text-textBlack leading-[125%] font-semibold max-w-[176px] w-[100%] px-3 py-5">
|
||||
<span>
|
||||
+
|
||||
{Object.keys(quizSearchData.data).map(
|
||||
(questionId, i) =>
|
||||
i === 0 &&
|
||||
quizSearchData.data[questionId].answers[0].client
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
{/* Serial number answer to questions */}
|
||||
<div className="flex justify-center items-center gap-6 text-base text-textGray leading-[125%] w-[100%] px-3 py-5">
|
||||
{Object.keys(quizSearchData.data)
|
||||
.map((quistionId) => quizSearchData.data[quistionId])
|
||||
.map((question) => {
|
||||
const matchingAnswer = question.answers[0];
|
||||
|
||||
return (
|
||||
<span
|
||||
key={v4()}
|
||||
className={`text-sm font-semibold leading-[125%] ${
|
||||
matchingAnswer &&
|
||||
matchingAnswer.serial_number_for_correct !== 0
|
||||
? "text-fillGreen"
|
||||
: matchingAnswer &&
|
||||
matchingAnswer?.serial_number_for_correct ===
|
||||
0
|
||||
? "text-fillRed"
|
||||
: "text-textLight"
|
||||
}`}
|
||||
>
|
||||
{matchingAnswer && matchingAnswer.score !== 0
|
||||
? matchingAnswer.serial_number_for_correct
|
||||
: matchingAnswer && matchingAnswer?.score === 0
|
||||
? "X"
|
||||
: "0"}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="flex justify-center items-center text-base text-textBlack leading-[125%] max-w-[180px] w-[100%] px-3 py-3">
|
||||
<span className="border border-[#2C7CDA] text-[#2C7CDA] rounded-full w-[36px] h-[36px] flex justify-center items-center text-base leading-[125%] ">
|
||||
{quizSearchData.result.total_serial}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-center items-center text-base text-textBlack leading-[125%] max-w-[180px] w-[100%] px-3 py-3">
|
||||
<span className="bg-fillOrange rounded-full w-[36px] h-[36px] flex justify-center items-center text-base leading-[125%] text-white">
|
||||
{quizSearchData.result.total_score}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -308,24 +253,26 @@ const QuizWinnerTable = ({ quizId, quizFinished, smsNumber }: IProps) => {
|
|||
<div className="sm:hidden flex flex-col bg-fillTableHead rounded-[13px] shadow-quizButton overflow-hidden max-w-[1000px] w-full">
|
||||
{/* Table Head */}
|
||||
<div className="flex border-b border-fillTableStrokeTableHead p-2 gap-[8px]">
|
||||
{winnersData?.data[0].client_id ? (
|
||||
{winnersData?.data[0].client_id || quizSearchData?.data ? (
|
||||
<div className="text-center flex items-center text-xs text-textBlack leading-[125%] font-semibold max-w-[14px] w-[100%]">
|
||||
<span>№</span>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{winnersData?.data[0].client.phone ? (
|
||||
{winnersData?.data[0].client.phone || quizSearchData?.data ? (
|
||||
<div className="text-center flex justify-center items-center text-xs text-textBlack leading-[125%] font-semibold max-w-[107px] w-[100%]">
|
||||
<span>Gatnaşyjynyň tel. Beligisi</span>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{winnersData?.data[0].total_score_of_client ? (
|
||||
{winnersData?.data[0].total_score_of_client ||
|
||||
quizSearchData?.data ? (
|
||||
<div className="text-center flex justify-center items-center text-xs text-textBlack leading-[125%] font-semibold max-w-[75px] w-[100%]">
|
||||
<span>Soraglara jogap berilişiň nobaty </span>
|
||||
</div>
|
||||
) : null}
|
||||
{winnersData?.data[0].total_score_of_client ? (
|
||||
{winnersData?.data[0].total_score_of_client ||
|
||||
quizSearchData?.data ? (
|
||||
<div className="text-center flex justify-center items-center text-xs text-textBlack leading-[125%] font-semibold max-w-[99px] w-[100%]">
|
||||
<span>Nobatlaryň jemi</span>
|
||||
</div>
|
||||
|
|
@ -334,7 +281,8 @@ const QuizWinnerTable = ({ quizId, quizFinished, smsNumber }: IProps) => {
|
|||
|
||||
{/* Table Body */}
|
||||
<div className="">
|
||||
{winnersData?.data.map((winner, id) => (
|
||||
{winnersData
|
||||
? winnersData?.data.map((winner, id) => (
|
||||
<div
|
||||
className={`flex border-b border-fillTableStrokeTableRow items-center p-[8px] gap-[8px] ${
|
||||
id % 2 === 0 ? "bg-fillTableRow" : "bg-fillTableRow2"
|
||||
|
|
@ -385,7 +333,8 @@ const QuizWinnerTable = ({ quizId, quizFinished, smsNumber }: IProps) => {
|
|||
answer.score > 0
|
||||
) ||
|
||||
winner.client.answers.find(
|
||||
(answer) => answer.question_id === question.id
|
||||
(answer) =>
|
||||
answer.question_id === question.id
|
||||
);
|
||||
return (
|
||||
<span
|
||||
|
|
@ -402,7 +351,8 @@ const QuizWinnerTable = ({ quizId, quizFinished, smsNumber }: IProps) => {
|
|||
: "text-textLight"
|
||||
}`}
|
||||
>
|
||||
{matchingAnswer && matchingAnswer.score !== 0
|
||||
{matchingAnswer &&
|
||||
matchingAnswer.score !== 0
|
||||
? matchingAnswer.serial_number_for_correct
|
||||
: matchingAnswer &&
|
||||
matchingAnswer?.score === 0
|
||||
|
|
@ -417,7 +367,81 @@ const QuizWinnerTable = ({ quizId, quizFinished, smsNumber }: IProps) => {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
))
|
||||
: quizSearchData && (
|
||||
<div
|
||||
className={`flex border-b border-fillTableStrokeTableRow items-center p-[8px] gap-[8px] bg-fillTableRow2`}
|
||||
>
|
||||
<div className="flex items-center text-base text-textBlack leading-[125%] max-w-[14px] w-[100%] ">
|
||||
<span>{quizSearchData.result.place}</span>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-[8px] w-full">
|
||||
<div className="flex gap-[8px] items-center">
|
||||
<div className="flex items-center text-xs text-textBlack leading-[125%] font-semibold max-w-[107px] w-full">
|
||||
<span>
|
||||
+
|
||||
{Object.keys(quizSearchData.data).map(
|
||||
(questionId, i) =>
|
||||
i === 0 &&
|
||||
quizSearchData.data[questionId].answers[0]
|
||||
.client
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-center items-center text-xs text-textBlack leading-[125%] max-w-[75px] w-full">
|
||||
<span className="border border-[#2C7CDA] text-[#2C7CDA] rounded-full w-[24px] h-[24px] flex justify-center items-center text-xs leading-[125%] ">
|
||||
{quizSearchData.result.total_serial}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-center items-center text-xs text-textBlack leading-[125%] max-w-[99px] w-full">
|
||||
<span className="bg-fillOrange rounded-full w-[24px] h-[24px] flex justify-center items-center text-xs leading-[125%] text-white">
|
||||
{quizSearchData.result.total_score}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-[8px] items-center">
|
||||
<div className="flex justify-center items-center text-xs text-textLight leading-[125%] font-semibold w-fit">
|
||||
<span>Soraglara näçinji jogap berdi :</span>
|
||||
</div>
|
||||
<div className="flex justify-center items-center gap-[4px] text-xs text-textGray leading-[125%] w-fit">
|
||||
{Object.keys(quizSearchData.data)
|
||||
.map(
|
||||
(quistionId) => quizSearchData.data[quistionId]
|
||||
)
|
||||
.map((question) => {
|
||||
const matchingAnswer = question.answers[0];
|
||||
|
||||
return (
|
||||
<span
|
||||
key={v4()}
|
||||
className={`text-sm font-semibold leading-[125%] ${
|
||||
matchingAnswer &&
|
||||
matchingAnswer.serial_number_for_correct !==
|
||||
0
|
||||
? "text-fillGreen"
|
||||
: matchingAnswer &&
|
||||
matchingAnswer?.serial_number_for_correct ===
|
||||
0
|
||||
? "text-fillRed"
|
||||
: "text-textLight"
|
||||
}`}
|
||||
>
|
||||
{matchingAnswer && matchingAnswer.score !== 0
|
||||
? matchingAnswer.serial_number_for_correct
|
||||
: matchingAnswer &&
|
||||
matchingAnswer?.score === 0
|
||||
? "X"
|
||||
: "0"}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
export interface IQuizSearchData {
|
||||
data: { [key: string]: Datum };
|
||||
result: {
|
||||
total_score: number;
|
||||
total_serial: number;
|
||||
place: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface Datum {
|
||||
|
|
|
|||
|
|
@ -5,8 +5,18 @@ interface ILotteryStatus {
|
|||
setStatus: (value: "Upcoming" | "Finished" | "Ongoing") => void;
|
||||
}
|
||||
|
||||
interface IQuizSearch {
|
||||
active: boolean;
|
||||
setActive: (value: boolean) => void;
|
||||
}
|
||||
|
||||
export const useLotteryStatus = create<ILotteryStatus>((set) => ({
|
||||
status: "Upcoming",
|
||||
setStatus: (value: "Upcoming" | "Finished" | "Ongoing") =>
|
||||
set({ status: value }),
|
||||
}));
|
||||
|
||||
export const useQuizSearchActive = create<IQuizSearch>((set) => ({
|
||||
active: false,
|
||||
setActive: (value: boolean) => set({ active: value }),
|
||||
}));
|
||||
|
|
|
|||
Loading…
Reference in New Issue