diff --git a/app/(main)/quiz/[quiz_id]/page.tsx b/app/(main)/quiz/[quiz_id]/page.tsx index 075e36f..f824d4b 100644 --- a/app/(main)/quiz/[quiz_id]/page.tsx +++ b/app/(main)/quiz/[quiz_id]/page.tsx @@ -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(false); const [data, setData] = useState(); + 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 (
- {typeof data !== 'string' ? ( + {typeof data !== "string" ? (
@@ -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) => { ) : ( {'banner'} {
{data?.data.rules && data.data.notes ? ( - + ) : null}
- {data?.data.id && quizFinished ? : null} -
- {data?.data ? ( + {data?.data && !active ? ( { /> ) : null} + {data?.data.id && quizFinished ? ( + + ) : null} + {data?.data.id && ( { const [data, setData] = useState(); - const [opened, setOpened] = useState(finished === 'closed' ? false : true); + const [opened, setOpened] = useState( + 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) => { <> -
+ transition={{ duration: 0.3 }} + > +
setOpened(!opened)} + className="flex bg-fillTableHead md:p-0 gap-3 md:gap-0 border-b border-fillTableStrokeTableHead p-[8px] w-full cursor-pointer" + >
@@ -83,9 +93,12 @@ const QuizAccordion = ({ finished, questionId }: TProps) => { {data.data.map((user, id) => (
+ key={v4()} + >
{id + 1}
@@ -111,9 +124,12 @@ const QuizAccordion = ({ finished, questionId }: TProps) => { {data.data.map((user, id) => (
+ key={v4()} + >
{id + 1} @@ -147,9 +163,12 @@ const QuizAccordion = ({ finished, questionId }: TProps) => {
diff --git a/components/quiz/QuizWinnerTable.tsx b/components/quiz/QuizWinnerTable.tsx index dc0620d..301561e 100644 --- a/components/quiz/QuizWinnerTable.tsx +++ b/components/quiz/QuizWinnerTable.tsx @@ -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(); const [winnersData, setWinnersData] = useState(); const { questionsData } = useContext(QuizContext).quizQuestionsContext; - const [socket, setSocket] = useState(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 ? (
@@ -198,30 +69,33 @@ const QuizWinnerTable = ({ quizId, quizFinished, smsNumber }: IProps) => {
{/* Table Head */}
- {winnersData?.data[0].client_id ? ( + {winnersData?.data[0].client_id || quizSearchData?.data ? (
) : null} - {winnersData?.data[0].client.phone ? ( + {winnersData?.data[0].client.phone || quizSearchData?.data ? (
Gatnaşyjynyň tel. Beligisi
) : null} - {winnersData?.data[0].client.answers.length !== 0 ? ( + {winnersData?.data[0].client.answers.length || + quizSearchData?.data ? (
Soraglara jogap berilişiň nobaty
) : null} - {winnersData?.data[0].total_score_of_client ? ( + {winnersData?.data[0].total_score_of_client || + quizSearchData?.data ? (
Nobatlaryň jemi
) : null} - {winnersData?.data[0].total_score_of_client ? ( + {winnersData?.data[0].total_score_of_client || + quizSearchData?.data ? (
Utuklaryň jemi
@@ -230,34 +104,111 @@ const QuizWinnerTable = ({ quizId, quizFinished, smsNumber }: IProps) => { {/* Table Body */}
- {winnersData?.data.map((winner, id) => ( -
-
- {id + 1} -
- {winnersData.data[0].client.phone ? ( -
- +{winner.client.phone} + {winnersData + ? winnersData?.data.map((winner, id) => ( +
+
+ + {id > 0 && + winner.correct_answers_time === + winnersData.data[id - 1].correct_answers_time + ? id + : id + 1} + +
+ {winnersData.data[0].client.phone ? ( +
+ +{winner.client.phone} +
+ ) : null} + {winnersData.data[0].client.answers.length !== 0 ? ( +
+ {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 ( + + {matchingAnswer && matchingAnswer.score !== 0 + ? matchingAnswer.serial_number_for_correct + : matchingAnswer && + matchingAnswer?.score === 0 + ? "X" + : "0"} + + ); + }) + : null} +
+ ) : null} + + {winnersData.data[0].total_score_of_client ? ( +
+ + {winner.correct_answers_time} + +
+ ) : null} + {winnersData.data[0].total_score_of_client ? ( +
+ + {winner.total_score_of_client} + +
+ ) : null}
- ) : null} - {winnersData.data[0].client.answers.length !== 0 ? ( -
- {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 && ( +
+ {/* Place of the client */} +
+ {quizSearchData.result.place} +
+ {/* Client phone number */} +
+ + + + {Object.keys(quizSearchData.data).map( + (questionId, i) => + i === 0 && + quizSearchData.data[questionId].answers[0].client + )} + +
+ {/* Serial number answer to questions */} +
+ {Object.keys(quizSearchData.data) + .map((quistionId) => quizSearchData.data[quistionId]) + .map((question) => { + const matchingAnswer = question.answers[0]; return ( { : "0"} ); - }) - : null} -
- ) : null} + })} +
- {winnersData.data[0].total_score_of_client ? ( -
- - {winner.correct_answers_time} - +
+ + {quizSearchData.result.total_serial} + +
+
+ + {quizSearchData.result.total_score} + +
- ) : null} - {winnersData.data[0].total_score_of_client ? ( -
- - {winner.total_score_of_client} - -
- ) : null} -
- ))} + )}
@@ -308,24 +253,26 @@ const QuizWinnerTable = ({ quizId, quizFinished, smsNumber }: IProps) => {
{/* Table Head */}
- {winnersData?.data[0].client_id ? ( + {winnersData?.data[0].client_id || quizSearchData?.data ? (
) : null} - {winnersData?.data[0].client.phone ? ( + {winnersData?.data[0].client.phone || quizSearchData?.data ? (
Gatnaşyjynyň tel. Beligisi
) : null} - {winnersData?.data[0].total_score_of_client ? ( + {winnersData?.data[0].total_score_of_client || + quizSearchData?.data ? (
Soraglara jogap berilişiň nobaty
) : null} - {winnersData?.data[0].total_score_of_client ? ( + {winnersData?.data[0].total_score_of_client || + quizSearchData?.data ? (
Nobatlaryň jemi
@@ -334,59 +281,138 @@ const QuizWinnerTable = ({ quizId, quizFinished, smsNumber }: IProps) => { {/* Table Body */}
- {winnersData?.data.map((winner, id) => ( -
-
- {id + 1} -
+ {winnersData + ? winnersData?.data.map((winner, id) => ( +
+
+ {id + 1} +
-
-
- {winnersData.data[0].client.phone ? ( -
- +{winner.client.phone} -
- ) : null} +
+
+ {winnersData.data[0].client.phone ? ( +
+ +{winner.client.phone} +
+ ) : null} - {winnersData.data[0].total_score_of_client ? ( -
- - {winner.correct_answers_time} - + {winnersData.data[0].total_score_of_client ? ( +
+ + {winner.correct_answers_time} + +
+ ) : null} + {winnersData.data[0].total_score_of_client ? ( +
+ + {winner.total_score_of_client} + +
+ ) : null}
- ) : null} - {winnersData.data[0].total_score_of_client ? ( -
- - {winner.total_score_of_client} - +
+ {winnersData?.data[0].client.answers.length !== 0 ? ( +
+ Soraglara näçinji jogap berdi : +
+ ) : null} + {winnersData.data[0].client.answers.length !== 0 ? ( +
+ {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 ( + + {matchingAnswer && + matchingAnswer.score !== 0 + ? matchingAnswer.serial_number_for_correct + : matchingAnswer && + matchingAnswer?.score === 0 + ? "X" + : "0"} + + ); + }) + : null} +
+ ) : null}
- ) : null} +
-
- {winnersData?.data[0].client.answers.length !== 0 ? ( -
- Soraglara näçinji jogap berdi : + )) + : quizSearchData && ( +
+
+ {quizSearchData.result.place} +
+ +
+
+
+ + + + {Object.keys(quizSearchData.data).map( + (questionId, i) => + i === 0 && + quizSearchData.data[questionId].answers[0] + .client + )} + +
+ +
+ + {quizSearchData.result.total_serial} + +
+
+ + {quizSearchData.result.total_score} + +
- ) : null} - {winnersData.data[0].client.answers.length !== 0 ? ( -
- {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 - ); +
+
+ Soraglara näçinji jogap berdi : +
+
+ {Object.keys(quizSearchData.data) + .map( + (quistionId) => quizSearchData.data[quistionId] + ) + .map((question) => { + const matchingAnswer = question.answers[0]; + return ( { 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"} ); - }) - : null} + })} +
- ) : null} +
-
-
- ))} + )}
diff --git a/models/quizSearchData.model.ts b/models/quizSearchData.model.ts index 7f6ce16..c150528 100644 --- a/models/quizSearchData.model.ts +++ b/models/quizSearchData.model.ts @@ -1,5 +1,10 @@ export interface IQuizSearchData { data: { [key: string]: Datum }; + result: { + total_score: number; + total_serial: number; + place: number; + }; } export interface Datum { diff --git a/store/store.ts b/store/store.ts index 3f35e89..9fc14a5 100644 --- a/store/store.ts +++ b/store/store.ts @@ -5,8 +5,18 @@ interface ILotteryStatus { setStatus: (value: "Upcoming" | "Finished" | "Ongoing") => void; } +interface IQuizSearch { + active: boolean; + setActive: (value: boolean) => void; +} + export const useLotteryStatus = create((set) => ({ status: "Upcoming", setStatus: (value: "Upcoming" | "Finished" | "Ongoing") => set({ status: value }), })); + +export const useQuizSearchActive = create((set) => ({ + active: false, + setActive: (value: boolean) => set({ active: value }), +}));