quiz page adjustments

This commit is contained in:
Ilgeldi 2025-02-24 16:45:37 +05:00
parent 15ac1ca1c7
commit a4eae0e528
7 changed files with 417 additions and 346 deletions

View File

@ -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}

View File

@ -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>

View File

@ -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]);

View File

@ -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',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ phone }),
});
const response = await fetch(
`https://sms.turkmentv.gov.tm/api/quiz/${quizId}/search`,
{
method: "POST",
headers: {
"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>

View File

@ -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(() => {
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;
if (!active) {
Queries.getQuizWinners(quizId).then((res) => {
setWinnersData(res);
});
} 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,34 +104,111 @@ const QuizWinnerTable = ({ quizId, quizFinished, smsNumber }: IProps) => {
{/* Table Body */}
<div className="">
{winnersData?.data.map((winner, id) => (
<div
className={`flex border-b border-fillTableStrokeTableRow ${
id % 2 === 0 ? "bg-fillTableRow" : "bg-fillTableRow2"
}`}
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>
</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">
<span>+{winner.client.phone}</span>
{winnersData
? winnersData?.data.map((winner, id) => (
<div
className={`flex border-b border-fillTableStrokeTableRow ${
id % 2 === 0 ? "bg-fillTableRow" : "bg-fillTableRow2"
}`}
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 > 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">
<span>+{winner.client.phone}</span>
</div>
) : null}
{winnersData.data[0].client.answers.length !== 0 ? (
<div className="flex justify-center items-center gap-6 text-base text-textGray leading-[125%] w-[100%] px-3 py-5">
{questionsData
? questionsData.map((question) => {
const matchingAnswer =
winner.client.answers.find(
(answer) =>
answer.question_id === question.id &&
answer.score > 0
) ||
winner.client.answers.find(
(answer) => answer.question_id === question.id
);
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>
);
})
: null}
</div>
) : null}
{winnersData.data[0].total_score_of_client ? (
<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%] ">
{winner.correct_answers_time}
</span>
</div>
) : null}
{winnersData.data[0].total_score_of_client ? (
<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">
{winner.total_score_of_client}
</span>
</div>
) : null}
</div>
) : null}
{winnersData.data[0].client.answers.length !== 0 ? (
<div className="flex justify-center items-center gap-6 text-base text-textGray leading-[125%] w-[100%] px-3 py-5">
{questionsData
? questionsData.map((question) => {
const matchingAnswer =
winner.client.answers.find(
(answer) =>
answer.question_id === question.id &&
answer.score > 0
) ||
winner.client.answers.find(
(answer) => answer.question_id === question.id
);
))
: 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
@ -280,27 +231,21 @@ const QuizWinnerTable = ({ quizId, quizFinished, smsNumber }: IProps) => {
: "0"}
</span>
);
})
: null}
</div>
) : null}
})}
</div>
{winnersData.data[0].total_score_of_client ? (
<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%] ">
{winner.correct_answers_time}
</span>
<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>
) : null}
{winnersData.data[0].total_score_of_client ? (
<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">
{winner.total_score_of_client}
</span>
</div>
) : null}
</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,59 +281,138 @@ const QuizWinnerTable = ({ quizId, quizFinished, smsNumber }: IProps) => {
{/* Table Body */}
<div className="">
{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"
}`}
key={v4()}
>
<div className="flex items-center text-base text-textBlack leading-[125%] max-w-[14px] w-[100%] ">
<span>{id + 1}</span>
</div>
{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"
}`}
key={v4()}
>
<div className="flex items-center text-base text-textBlack leading-[125%] max-w-[14px] w-[100%] ">
<span>{id + 1}</span>
</div>
<div className="flex flex-col gap-[8px] w-full">
<div className="flex gap-[8px] items-center">
{winnersData.data[0].client.phone ? (
<div className="flex items-center text-xs text-textBlack leading-[125%] font-semibold max-w-[107px] w-full">
<span>+{winner.client.phone}</span>
</div>
) : null}
<div className="flex flex-col gap-[8px] w-full">
<div className="flex gap-[8px] items-center">
{winnersData.data[0].client.phone ? (
<div className="flex items-center text-xs text-textBlack leading-[125%] font-semibold max-w-[107px] w-full">
<span>+{winner.client.phone}</span>
</div>
) : null}
{winnersData.data[0].total_score_of_client ? (
<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%] ">
{winner.correct_answers_time}
</span>
{winnersData.data[0].total_score_of_client ? (
<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%] ">
{winner.correct_answers_time}
</span>
</div>
) : null}
{winnersData.data[0].total_score_of_client ? (
<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">
{winner.total_score_of_client}
</span>
</div>
) : null}
</div>
) : null}
{winnersData.data[0].total_score_of_client ? (
<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">
{winner.total_score_of_client}
</span>
<div className="flex gap-[8px] items-center">
{winnersData?.data[0].client.answers.length !== 0 ? (
<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>
) : null}
{winnersData.data[0].client.answers.length !== 0 ? (
<div className="flex justify-center items-center gap-[4px] text-xs text-textGray leading-[125%] w-fit">
{questionsData
? questionsData.map((question) => {
const matchingAnswer =
winner.client.answers.find(
(answer) =>
answer.question_id === question.id &&
answer.score > 0
) ||
winner.client.answers.find(
(answer) =>
answer.question_id === question.id
);
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>
);
})
: null}
</div>
) : null}
</div>
) : null}
</div>
</div>
<div className="flex gap-[8px] items-center">
{winnersData?.data[0].client.answers.length !== 0 ? (
<div className="flex justify-center items-center text-xs text-textLight leading-[125%] font-semibold w-fit">
<span>Soraglara näçinji jogap berdi :</span>
))
: 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>
) : null}
{winnersData.data[0].client.answers.length !== 0 ? (
<div className="flex justify-center items-center gap-[4px] text-xs text-textGray leading-[125%] w-fit">
{questionsData
? questionsData.map((question) => {
const matchingAnswer =
winner.client.answers.find(
(answer) =>
answer.question_id === question.id &&
answer.score > 0
) ||
winner.client.answers.find(
(answer) => answer.question_id === question.id
);
<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()}
@ -396,7 +422,7 @@ const QuizWinnerTable = ({ quizId, quizFinished, smsNumber }: IProps) => {
0
? "text-fillGreen"
: matchingAnswer &&
matchingAnswer.serial_number_for_correct ===
matchingAnswer?.serial_number_for_correct ===
0
? "text-fillRed"
: "text-textLight"
@ -410,14 +436,12 @@ const QuizWinnerTable = ({ quizId, quizFinished, smsNumber }: IProps) => {
: "0"}
</span>
);
})
: null}
})}
</div>
</div>
) : null}
</div>
</div>
</div>
</div>
))}
)}
</div>
</div>
</div>

View File

@ -1,5 +1,10 @@
export interface IQuizSearchData {
data: { [key: string]: Datum };
result: {
total_score: number;
total_serial: number;
place: number;
};
}
export interface Datum {

View File

@ -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 }),
}));