From 7c370268044d3079df2fdb0f90f98dc20f1e3340 Mon Sep 17 00:00:00 2001 From: mphstar Date: Tue, 25 Feb 2025 20:26:23 +0700 Subject: [PATCH] feat: quiz tebak huruf --- src/components/molecules/NavLink.tsx | 2 +- .../Kuis/MenyusunHuruf/MenyusunHuruf.tsx | 44 +++++- src/pages/Kuis/MenyusunHuruf/Quiz.tsx | 37 +---- src/pages/Kuis/TebakHuruf/Quiz.tsx | 92 ++++++++++-- src/pages/Kuis/TebakHuruf/TebakHuruf.tsx | 138 +++++++++++++++++- src/stores/TebakHurufStore.ts | 12 ++ 6 files changed, 264 insertions(+), 61 deletions(-) diff --git a/src/components/molecules/NavLink.tsx b/src/components/molecules/NavLink.tsx index 198acf6..e063bcf 100644 --- a/src/components/molecules/NavLink.tsx +++ b/src/components/molecules/NavLink.tsx @@ -10,7 +10,7 @@ const NavLink = ({ href, name, isActive }: NavLinkProps) => {
  • diff --git a/src/pages/Kuis/MenyusunHuruf/MenyusunHuruf.tsx b/src/pages/Kuis/MenyusunHuruf/MenyusunHuruf.tsx index 7a41918..f523020 100644 --- a/src/pages/Kuis/MenyusunHuruf/MenyusunHuruf.tsx +++ b/src/pages/Kuis/MenyusunHuruf/MenyusunHuruf.tsx @@ -1,11 +1,49 @@ import LayoutPage from "@/components/templates/LayoutPage"; import useMenyusunHurufStore from "@/stores/MenyusunHurufStore"; +import useNavbarStore from "@/stores/NavbarStore"; import { useEffect } from "react"; import { Link, useNavigate } from "react-router-dom"; import Swal from "sweetalert2"; const MenyusunHuruf = () => { const quizStore = useMenyusunHurufStore(); + const store = useNavbarStore(); + + useEffect(() => { + store.setNavSelected("kuis"); + }, []); + + const saveData = async () => { + try { + await fetch("https://ksuli-api.deno.dev/proses-kuis", { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer KSULI_TOKEN_321`, + }, + body: JSON.stringify({ + kategori_id: "rec_cuum7c5qrj60bgubcjog", + person_name: quizStore.name, + score: parseInt(quizStore.time.toString()), + }), + }); + + Swal.close(); + } catch (error) { + console.error("Error saving data:", error); + Swal.fire({ + icon: "error", + title: "Oops...", + text: "Something went wrong while saving your data!", + }); + } + + Swal.fire({ + icon: "success", + title: "Kuis telah selesai", + text: `Anda menyelesaikan kuis dalam waktu ${quizStore.time} detik`, + }); + }; const shuffleArray = (array: any[]) => { for (let i = array.length - 1; i > 0; i--) { @@ -19,11 +57,7 @@ const MenyusunHuruf = () => { useEffect(() => { if (quizStore.isFinish) { - Swal.fire({ - icon: "success", - title: "Kuis telah selesai", - text: `Anda menyelesaikan kuis dalam waktu ${quizStore.time} detik`, - }); + saveData(); } }, [quizStore.isFinish]); diff --git a/src/pages/Kuis/MenyusunHuruf/Quiz.tsx b/src/pages/Kuis/MenyusunHuruf/Quiz.tsx index f58468c..afb8942 100644 --- a/src/pages/Kuis/MenyusunHuruf/Quiz.tsx +++ b/src/pages/Kuis/MenyusunHuruf/Quiz.tsx @@ -6,7 +6,6 @@ import calcLandmarkList from "@/utils/CalculateLandmark"; import preProcessLandmark from "@/utils/PreProcessLandmark"; import { abjads } from "@/utils/ConvertResult"; import useNavbarStore from "@/stores/NavbarStore"; -import ProgressBar from "@/components/molecules/ProgressBar"; import { MdOutlineQuiz } from "react-icons/md"; import useMenyusunHurufStore from "@/stores/MenyusunHurufStore"; import { useNavigate } from "react-router-dom"; @@ -94,7 +93,6 @@ const Quiz = () => { } }; - const [progress, setProgress] = useState(0); const [answer, setAnswer] = useState(""); let tempAnswer = ""; @@ -196,7 +194,6 @@ const Quiz = () => { Swal.showLoading(); }, }); - await saveData(parseInt(answerTime.toString())); navigate("/kuis/menyusun-huruf/"); } @@ -204,32 +201,6 @@ const Quiz = () => { } }; - const saveData = async (time: number) => { - try { - await fetch("https://ksuli-api.deno.dev/proses-kuis", { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer KSULI_TOKEN_321`, - }, - body: JSON.stringify({ - kategori_id: "rec_cuum7c5qrj60bgubcjog", - person_name: quizStore.name, - score: time, - }), - }); - - Swal.close(); - } catch (error) { - console.error("Error saving data:", error); - Swal.fire({ - icon: "error", - title: "Oops...", - text: "Something went wrong while saving your data!", - }); - } - }; - const detectHands = async () => { if (showAnswer) { return; @@ -256,10 +227,8 @@ const Quiz = () => { makePrediction(finalResult); } else { setHandPresence(false); - setProgress(0); } } else { - setProgress(0); } } } @@ -316,13 +285,13 @@ const Quiz = () => { {!showAnswer && (
    -

    +

    Susun huruf "{quizStore.listSoal[quizStore.soalIndex]}"

    {answer.length > 0 && (
    -

    +

    {answer}

    @@ -334,9 +303,7 @@ const Quiz = () => {
    -

    Tahan Tangan..

    -
    )} diff --git a/src/pages/Kuis/TebakHuruf/Quiz.tsx b/src/pages/Kuis/TebakHuruf/Quiz.tsx index 0520f56..3343271 100644 --- a/src/pages/Kuis/TebakHuruf/Quiz.tsx +++ b/src/pages/Kuis/TebakHuruf/Quiz.tsx @@ -4,10 +4,13 @@ import * as tf from "@tensorflow/tfjs"; import { FilesetResolver, HandLandmarker } from "@mediapipe/tasks-vision"; import calcLandmarkList from "@/utils/CalculateLandmark"; import preProcessLandmark from "@/utils/PreProcessLandmark"; -import ConvertResult from "@/utils/ConvertResult"; +import ConvertResult, { abjads } from "@/utils/ConvertResult"; import useNavbarStore from "@/stores/NavbarStore"; import ProgressBar from "@/components/molecules/ProgressBar"; import { MdOutlineQuiz } from "react-icons/md"; +import useTebakHurufStore from "@/stores/TebakHurufStore"; +import { useNavigate } from "react-router-dom"; +import Swal from "sweetalert2"; // type PredictResult = { // abjad: String; @@ -85,6 +88,9 @@ const Quiz = () => { let previousResult: string[] = []; const [progress, setProgress] = useState(0); + let noSoal = 0; + let isLoading = false; + const navigate = useNavigate(); const makePrediction = async (finalResult: any) => { const input = tf.tensor2d([finalResult]); @@ -127,13 +133,45 @@ const Quiz = () => { } if (previousResult.length == 11) { + isLoading = true; + + if (abjads[parseInt(maxKey)] === quizStore.listSoal[noSoal]) { + quizStore.addJawaban({ + jawaban: abjads[parseInt(maxKey)], + isCorrect: true, + }); + } else { + quizStore.addJawaban({ + jawaban: abjads[parseInt(maxKey)], + isCorrect: false, + }); + } + setShowAnswer(true); - previousResult = []; - setProgress(0); - setTimeout(() => { + isLoading = false; setShowAnswer(false); + setProgress(0); + noSoal++; + previousResult = []; + quizStore.setSoalIndex(noSoal); + + if (noSoal === quizStore.listSoal.length) { + quizStore.setSession(false); + quizStore.setIsFinish(true); + + Swal.fire({ + title: "Loading", + text: "Proses menyimpan data...", + allowOutsideClick: false, + didOpen: () => { + Swal.showLoading(); + }, + }); + + navigate("/kuis/tebak-huruf"); + } }, 2000); } @@ -163,7 +201,9 @@ const Quiz = () => { const calt = calcLandmarkList(videoRef.current, landm); const finalResult = preProcessLandmark(calt); - makePrediction(finalResult); + if (!isLoading) { + makePrediction(finalResult); + } } else { setHandPresence(false); setProgress(0); @@ -179,6 +219,15 @@ const Quiz = () => { }; const store = useNavbarStore(); + const quizStore = useTebakHurufStore(); + + console.log(quizStore.jawaban); + + useEffect(() => { + if (!quizStore.session) { + window.location.href = "/kuis/tebak-huruf"; + } + }, []); useEffect(() => { store.setNavSelected("kuis"); @@ -205,33 +254,48 @@ const Quiz = () => {
    Jawaban Salah -

    A

    +

    + {quizStore.jawaban[quizStore.soalIndex]?.jawaban} +

    - Jawaban kamu Salah + Jawaban kamu{" "} + {quizStore.jawaban[quizStore.soalIndex]?.isCorrect + ? "Benar" + : "Salah"}

    -

    Soal: 1 / 10

    +

    + Soal: {quizStore.soalIndex + 1} / {quizStore.listSoal.length} +

    {loadCamera ? (
    {!showAnswer && ( -
    -

    - Tebak Huruf K +
    +

    + Tebak Huruf {quizStore.listSoal[quizStore.soalIndex]}

    )} {handPresence && !showAnswer && ( -
    +
    diff --git a/src/pages/Kuis/TebakHuruf/TebakHuruf.tsx b/src/pages/Kuis/TebakHuruf/TebakHuruf.tsx index 62ab3b5..842a810 100644 --- a/src/pages/Kuis/TebakHuruf/TebakHuruf.tsx +++ b/src/pages/Kuis/TebakHuruf/TebakHuruf.tsx @@ -1,7 +1,128 @@ import LayoutPage from "@/components/templates/LayoutPage"; -import { Link } from "react-router-dom"; +import useNavbarStore from "@/stores/NavbarStore"; +import useTebakHurufStore from "@/stores/TebakHurufStore"; +import { useEffect } from "react"; +import { Link, useNavigate } from "react-router-dom"; +import Swal from "sweetalert2"; const TebakHuruf = () => { + const quizStore = useTebakHurufStore(); + + const store = useNavbarStore(); + + useEffect(() => { + store.setNavSelected("kuis"); + }, []); + + const shuffleSoal = () => { + const arr = [ + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + ]; + + const shuffledArr = arr.sort(() => 0.5 - Math.random()).slice(0, 10); + return shuffledArr; + }; + + const saveData = async () => { + let score = 0; + let benar = 0; + let salah = 0; + try { + quizStore.jawaban.forEach((jawaban) => { + if (jawaban.isCorrect) { + score += 10; + benar += 1; + } else { + salah += 1; + } + }); + + await fetch("https://ksuli-api.deno.dev/proses-kuis", { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer KSULI_TOKEN_321`, + }, + body: JSON.stringify({ + kategori_id: "rec_cuum78tqrj678tmbcjh0", + person_name: quizStore.name, + score: score, + }), + }); + + Swal.close(); + } catch (error) { + console.error("Error saving data:", error); + Swal.fire({ + icon: "error", + title: "Oops...", + text: "Something went wrong while saving your data!", + }); + } + + Swal.fire({ + icon: "success", + title: "Kuis telah selesai", + html: ` +

    Anda menyelesaikan kuis dengan score: ${score}

    +

    Jawaban benar: ${benar}

    +

    Jawaban salah: ${salah}

    + `, + }); + }; + + const router = useNavigate(); + + const ProsesKuis = () => { + if (quizStore.name === "") { + Swal.fire({ + icon: "error", + title: "Oops...", + text: "Isi nama terlebih dahulu", + }); + return; + } + + quizStore.setSoalIndex(0); + quizStore.setSession(true); + quizStore.setListSoal(shuffleSoal()); + + router("/kuis/tebak-huruf/app"); + }; + + useEffect(() => { + if (quizStore.isFinish) { + saveData(); + } + + return () => { + quizStore.setIsFinish(false); + }; + }, [quizStore.isFinish]); + return (
    @@ -25,13 +146,18 @@ const TebakHuruf = () => { quizStore.setName(e.target.value)} className="bg-transparent outline-none p-2 px-8 flex-1 w-full" /> - - - +
    Lihat Ranking
    diff --git a/src/stores/TebakHurufStore.ts b/src/stores/TebakHurufStore.ts index 9a870c2..27b5ffe 100644 --- a/src/stores/TebakHurufStore.ts +++ b/src/stores/TebakHurufStore.ts @@ -15,6 +15,12 @@ type TebakHurufType = { jawaban: JawabanType[]; setJawaban: (jawaban: JawabanType[]) => void; addJawaban: (jawaban: JawabanType) => void; + session: boolean; + setSession: (session: boolean) => void; + name: string; + setName: (name: string) => void; + isFinish: boolean; + setIsFinish: (isFinish: boolean) => void; }; const useTebakHurufStore = create((set) => ({ @@ -28,6 +34,12 @@ const useTebakHurufStore = create((set) => ({ setJawaban: (jawaban) => set({ jawaban: jawaban }), addJawaban: (jawaban) => set((state) => ({ jawaban: [...state.jawaban, jawaban] })), + session: false, + setSession: (session) => set({ session: session }), + name: "", + setName: (name) => set({ name: name }), + isFinish: false, + setIsFinish: (isFinish) => set({ isFinish: isFinish }), })); export default useTebakHurufStore;