enzostvs HF Staff commited on
Commit
091969f
·
1 Parent(s): e59a161

work in progress. end page and error management are missing

Browse files
app/api/[questId]/score/route.ts ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { NextRequest } from "next/server";
2
+ import { PrismaClient } from '@prisma/client'
3
+
4
+ const prisma = new PrismaClient()
5
+
6
+ export async function POST(request: NextRequest, { params }: { params: { questId: string } }) {
7
+ const { questId } = params;
8
+ const { promptId } = await request.json()
9
+
10
+ if (!promptId) {
11
+ return Response.json({
12
+ message: "promptId is required",
13
+ }, { statusText: "Missing body fields", status: 404 });
14
+ }
15
+
16
+ const quest = await prisma.quest.findUnique({
17
+ where: {
18
+ id: questId
19
+ }
20
+ })
21
+
22
+ if (!quest?.id) {
23
+ return Response.json({
24
+ message: "Quest doesn't exist",
25
+ }, { statusText: "Not Found", status: 404 });
26
+ }
27
+
28
+ // even if the answer is wrong, we delete the quest, not needed anymore
29
+ // await prisma.quest.delete({
30
+ // where: {
31
+ // id: questId
32
+ // }
33
+ // })
34
+
35
+ if (quest.prompt_id_correct !== promptId) {
36
+ return Response.json({
37
+ ok: false,
38
+ message: "Wrong answer",
39
+ }, { statusText: "Wrong answer", status: 400 });
40
+ }
41
+
42
+ return Response.json({
43
+ ok: true,
44
+ })
45
+ }
app/api/start/route.ts CHANGED
@@ -4,11 +4,6 @@ import { PrismaClient } from '@prisma/client'
4
  const prisma = new PrismaClient()
5
 
6
  export async function POST(request: NextRequest,) {
7
-
8
- if (!prisma.prompt) {
9
- return Response.json({}, { statusText: "No table found", status: 500 });
10
- }
11
-
12
  const all_prompts = await prisma.prompt.findMany({
13
  orderBy: {
14
  id: 'desc'
@@ -19,20 +14,42 @@ export async function POST(request: NextRequest,) {
19
  return Response.json({}, { statusText: "Not enough prompts. Try again.", status: 500 });
20
  }
21
 
22
- const prompts: Array<{ prompt: string, file_name: string, id: number, is_correct?: boolean }> = []
23
- const prompts_ids: Set<number> = new Set()
24
 
25
  const is_correct = Math.floor(Math.random() * 3)
 
26
  while (prompts.length < 3) {
27
  const random_prompt = all_prompts[Math.floor(Math.random() * all_prompts.length)]
28
  if (!prompts_ids.has(random_prompt.id)) {
29
- prompts.push({
30
- ...random_prompt,
31
- is_correct: prompts.length === is_correct
32
- })
33
  prompts_ids.add(random_prompt.id)
34
  }
35
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
- return Response.json({ prompts, ok: true, status: 200 });
 
 
 
 
 
 
 
 
 
 
38
  }
 
4
  const prisma = new PrismaClient()
5
 
6
  export async function POST(request: NextRequest,) {
 
 
 
 
 
7
  const all_prompts = await prisma.prompt.findMany({
8
  orderBy: {
9
  id: 'desc'
 
14
  return Response.json({}, { statusText: "Not enough prompts. Try again.", status: 500 });
15
  }
16
 
17
+ const prompts: Array<{ prompt: string, file_name: string, id: string, is_correct?: boolean }> = []
18
+ const prompts_ids: Set<string> = new Set()
19
 
20
  const is_correct = Math.floor(Math.random() * 3)
21
+
22
  while (prompts.length < 3) {
23
  const random_prompt = all_prompts[Math.floor(Math.random() * all_prompts.length)]
24
  if (!prompts_ids.has(random_prompt.id)) {
25
+ prompts.push(random_prompt,)
 
 
 
26
  prompts_ids.add(random_prompt.id)
27
  }
28
  }
29
+
30
+ const prompt_correct = prompts[is_correct]
31
+
32
+ if (!prompt_correct) {
33
+ return Response.json({
34
+ message: "Not enough prompts. Try again."
35
+ }, { statusText: "Not enough prompts. Try again.", status: 500 });
36
+ }
37
+
38
+ const quest = await prisma.quest.create({
39
+ data: {
40
+ prompt_id_correct: prompt_correct.id
41
+ }
42
+ })
43
 
44
+ return Response.json(
45
+ {
46
+ data: {
47
+ prompts,
48
+ question: prompt_correct?.prompt,
49
+ quest_id: quest.id
50
+ },
51
+ ok: true,
52
+ status: 200
53
+ }
54
+ );
55
  }
app/layout.tsx CHANGED
@@ -1,23 +1,35 @@
 
1
  import type { Metadata } from "next";
2
  import { Inter } from "next/font/google";
3
- import "@/assets/css/globals.css";
4
 
5
- const inter = Inter({ subsets: ["latin"] });
 
6
 
7
  export const metadata: Metadata = {
8
  title: "Create Next App",
9
  description: "Generated by create next app",
10
  };
11
 
 
 
 
 
 
 
 
 
12
  export default function RootLayout({
13
  children,
14
  }: {
15
  children: React.ReactNode;
16
  }) {
17
  return (
18
- <html lang="en">
19
  <body>
20
- {children}
 
 
21
  <div id="background__noisy" />
22
  </body>
23
  </html>
 
1
+ import { cache } from "react";
2
  import type { Metadata } from "next";
3
  import { Inter } from "next/font/google";
4
+ import { QueryClient } from "@tanstack/react-query";
5
 
6
+ import Providers from "@/components/react-query/providers";
7
+ import "@/assets/css/globals.css";
8
 
9
  export const metadata: Metadata = {
10
  title: "Create Next App",
11
  description: "Generated by create next app",
12
  };
13
 
14
+ const inter = Inter({
15
+ subsets: ["latin"],
16
+ display: "swap",
17
+ variable: "--font-inter",
18
+ });
19
+
20
+ export const getQueryClient = () => cache(() => new QueryClient());
21
+
22
  export default function RootLayout({
23
  children,
24
  }: {
25
  children: React.ReactNode;
26
  }) {
27
  return (
28
+ <html lang="en" className={`${inter.variable}`}>
29
  <body>
30
+ <div className="pb-16 h-screen overflow-auto">
31
+ <Providers>{children}</Providers>
32
+ </div>
33
  <div id="background__noisy" />
34
  </body>
35
  </html>
app/page.tsx CHANGED
@@ -1,17 +1,34 @@
1
- import { Button } from "@/components/button/button";
2
- import { Quizz } from "@/components/quizz";
3
  import Link from "next/link";
 
 
 
 
 
4
 
5
  export default function Home() {
6
  return (
7
  <div className="w-full min-h-screen mx-auto max-w-4xl relative flex items-center justify-center">
8
  <div className="relative grid grid-cols-1 gap-8 py-12 px-6">
9
- <h1 className="text-center text-5xl md:text-7xl font-extrabold bg-clip-text text-transparent bg-gradient-to-b from-white to-white/80">
 
 
 
 
 
 
 
10
  Which image is the <br />
11
  <span className="bg-gradient-to-tr from-green to-cyan bg-clip-text">
12
  good
13
  </span>{" "}
14
  one?
 
 
 
 
 
 
 
15
  </h1>
16
  <h2 className="text-white text-xl md:text-2xl text-center font-light">
17
  Time to test if you now how to compose the perfect prompt. <br />
@@ -24,7 +41,7 @@ export default function Home() {
24
  </Button>
25
  </Link>
26
  </div>
27
- <div className="absolute top-1/2 left-1/2 will-transform -translate-x-1/2 -translate-y-1/2 bg-gradient-to-br from-green to-cyan blur-[120px] md:blur-[140px] w-full h-full rounded-full z-[-1] opacity-30"></div>
28
  </div>
29
  </div>
30
  );
 
 
 
1
  import Link from "next/link";
2
+ import Image from "next/image";
3
+
4
+ import { Button } from "@/components/button/button";
5
+ import SparklingEffect from "@/assets/images/sparkles.svg";
6
+ import SparklingEffect2 from "@/assets/images/sparkles-2.svg";
7
 
8
  export default function Home() {
9
  return (
10
  <div className="w-full min-h-screen mx-auto max-w-4xl relative flex items-center justify-center">
11
  <div className="relative grid grid-cols-1 gap-8 py-12 px-6">
12
+ <h1 className="text-center text-5xl md:text-7xl font-extrabold bg-clip-text text-transparent bg-gradient-to-b from-white to-white/80 relative">
13
+ <Image
14
+ src={SparklingEffect}
15
+ width={30}
16
+ height={50}
17
+ alt="Sparkling effect"
18
+ className="absolute top-8 left-0 -translate-x-[calc(100%+1rem)]"
19
+ />
20
  Which image is the <br />
21
  <span className="bg-gradient-to-tr from-green to-cyan bg-clip-text">
22
  good
23
  </span>{" "}
24
  one?
25
+ <Image
26
+ src={SparklingEffect2}
27
+ width={30}
28
+ height={50}
29
+ alt="Sparkling effect"
30
+ className="absolute -top-6 right-0 translate-x-[calc(100%+1rem)]"
31
+ />
32
  </h1>
33
  <h2 className="text-white text-xl md:text-2xl text-center font-light">
34
  Time to test if you now how to compose the perfect prompt. <br />
 
41
  </Button>
42
  </Link>
43
  </div>
44
+ <div className="absolute top-1/2 left-1/2 will-transform -translate-x-1/2 -translate-y-1/2 bg-gradient-to-br from-green to-cyan blur-[120px] md:blur-[140px] w-full h-full max-h-[250px] rounded-full z-[-1] opacity-40"></div>
45
  </div>
46
  </div>
47
  );
app/quizz/layout.tsx ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { LayoutScore } from "@/components/quizz/layout-score";
2
+
3
+ export default function RootLayout({
4
+ children,
5
+ }: {
6
+ children: React.ReactNode;
7
+ }) {
8
+ return (
9
+ <div className="min-h-screen relative">
10
+ <div className="absolute top-0 left-1/2 will-transform -translate-x-1/2 -translate-y-1/2 bg-gradient-to-br from-green to-cyan blur-[120px] md:blur-[180px] w-full h-full max-w-5xl max-h-[250px] rounded-full z-[-1] opacity-50"></div>
11
+ <header>
12
+ <div className="flex items-center justify-center md:justify-between px-6 py-5 container mx-auto">
13
+ <p className="text-center text-xl font-extrabold bg-clip-text text-transparent bg-gradient-to-b from-white to-white/80 relative">
14
+ Which image is the{" "}
15
+ <span className="bg-gradient-to-tr from-green to-cyan bg-clip-text">
16
+ good
17
+ </span>{" "}
18
+ one?
19
+ </p>
20
+ <LayoutScore className="hidden md:block" />
21
+ </div>
22
+ <div className="bg-gradient-to-r from-transparent via-white/70 to-transparent w-full h-[1px] opacity-20" />
23
+ </header>
24
+ <main className="px-6 pt-6 lg:pt-20 max-w-7xl mx-auto">{children}</main>
25
+ </div>
26
+ );
27
+ }
app/quizz/page.tsx ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import { QuizzContent } from "@/components/quizz";
2
+
3
+ export default function Quizz() {
4
+ return (
5
+ <div className="grid grid-cols-1 gap-12">
6
+ <QuizzContent />
7
+ </div>
8
+ );
9
+ }
assets/css/globals.css CHANGED
@@ -2,8 +2,8 @@
2
  @tailwind components;
3
  @tailwind utilities;
4
 
5
- body {
6
- @apply z-[1] relative bg-black min-h-screen;
7
  font-family: 'Trap', sans-serif;
8
  }
9
 
 
2
  @tailwind components;
3
  @tailwind utilities;
4
 
5
+ html, body {
6
+ @apply z-[1] relative bg-black min-h-screen overflow-hidden;
7
  font-family: 'Trap', sans-serif;
8
  }
9
 
assets/images/sparkles-2.svg ADDED
assets/images/sparkles.svg ADDED
components/button/button.tsx CHANGED
@@ -21,7 +21,7 @@ export const Button: React.FC<Props> = ({
21
  className={classNames(
22
  `font-action px-6 w-full sm:w-auto py-3 sm:px-7 sm:py-4 text-sm sm:text-base uppercase font-semibold flex items-center justify-center gap-2.5 transition-all duration-200 tracking-widest ${className}`,
23
  {
24
- "bg-white text-[#0F110F]": theme === "primary",
25
  disabled,
26
  }
27
  )}
 
21
  className={classNames(
22
  `font-action px-6 w-full sm:w-auto py-3 sm:px-7 sm:py-4 text-sm sm:text-base uppercase font-semibold flex items-center justify-center gap-2.5 transition-all duration-200 tracking-widest ${className}`,
23
  {
24
+ "bg-white text-[#0F110F] hover:-translate-y-1": theme === "primary",
25
  disabled,
26
  }
27
  )}
components/quizz/card.tsx ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from "react";
2
+ import Image from "next/image";
3
+ import Confetti from "react-confetti";
4
+
5
+ import { PromptType } from "@/utils/type";
6
+ import { useQuizz } from "./hooks/useQuizz";
7
+ import classNames from "classnames";
8
+
9
+ interface Props {
10
+ prompt: PromptType;
11
+ }
12
+
13
+ export const Card: React.FC<Props> = ({ prompt }) => {
14
+ const { onScore, success } = useQuizz();
15
+
16
+ return (
17
+ <div
18
+ className={classNames(
19
+ "w-[340px] h-[340px] p-5 relative z-[1] cursor-pointer group",
20
+ {
21
+ "!cursor-not-allowed": success,
22
+ }
23
+ )}
24
+ onClick={success ? () => {} : async () => await onScore(prompt.id)}
25
+ >
26
+ <div
27
+ className={classNames(
28
+ "absolute bottom-0 w-full left-0 px-0 py-0 flex justify-between items-center translate-y-10 transition-all duration-200",
29
+ {
30
+ "opacity-0 pointer-events-none": success !== prompt.id,
31
+ }
32
+ )}
33
+ >
34
+ <p
35
+ className={classNames("text-[90px] transition-all duration-200", {
36
+ "-translate-x-1/2 translate-y-1/2": success !== prompt.id,
37
+ })}
38
+ >
39
+ 🎉
40
+ </p>
41
+ <p
42
+ className={classNames(
43
+ "font-extrabold text-white text-7xl pr-6 pb-10 transition-all duration-200",
44
+ {
45
+ "translate-y-full": success !== prompt.id,
46
+ }
47
+ )}
48
+ >
49
+ +1
50
+ </p>
51
+ </div>
52
+ {success === prompt.id && (
53
+ <Confetti width={340} height={340} numberOfPieces={100} />
54
+ )}
55
+ <Image
56
+ src={`https://huggingface.co/datasets/enzostvs/what-is-the-prompt/resolve/main/${prompt.file_name}?expose=true`}
57
+ alt="Generated image"
58
+ width={340}
59
+ height={340}
60
+ className={classNames(
61
+ "object-center object-cover w-full h-full select-none hover:ring-4 ring-white transition-all duration-100",
62
+ {
63
+ "ring-4 !ring-[#E5AC00] hover:ring-[#E5AC00]":
64
+ success === prompt.id,
65
+ "!ring-transparent": success && success !== prompt.id,
66
+ }
67
+ )}
68
+ />
69
+ <div
70
+ className={classNames(
71
+ "w-full h-full blur-md lg:blur-md top-0 left-0 absolute z-[-1] opacity-20 transition-all duration-200",
72
+ {
73
+ "group-hover:opacity-40": !success,
74
+ }
75
+ )}
76
+ style={{
77
+ backgroundImage: `url(https://huggingface.co/datasets/enzostvs/what-is-the-prompt/resolve/main/${prompt.file_name}?expose=true)`,
78
+ }}
79
+ />
80
+ </div>
81
+ );
82
+ };
components/quizz/hooks/useQuizz.ts CHANGED
@@ -1,40 +1,66 @@
1
- import { useMemo, useState } from "react";
 
2
 
3
  import { PromptType } from "@/utils/type";
 
4
 
5
  export const useQuizz = () => {
6
- const [quizz, setQuizz] = useState<Array<PromptType> | undefined>(undefined);
7
- const [loading, setLoading] = useState<boolean>(false);
8
- const [error, setError] = useState<string | undefined>(undefined);
9
-
10
- const generate = async () => {
11
- setLoading(true);
12
- const response = await fetch(`/api/start`, { method: 'GET' });
13
- const res = await response.json();
14
-
15
- if (res.error) {
16
- setError(res.error);
17
- setLoading(false);
18
- return;
19
- }
20
 
21
- setError(undefined);
22
- setQuizz(res.prompts);
23
- setLoading(false);
24
- }
 
 
 
 
25
 
26
- console.log(quizz);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
- const correctPrompt = useMemo(() => {
29
- if (!quizz) return undefined;
30
- return quizz?.find((prompt) => prompt.is_correct)?.prompt;
31
- }, [quizz]);
 
 
 
 
 
 
32
 
33
  return {
34
- quizz,
35
  loading,
36
  error,
37
- generate,
38
- correctPrompt
 
 
39
  }
40
  }
 
1
+ import { useState } from "react";
2
+ import { useQuery, useQueryClient } from "@tanstack/react-query";
3
 
4
  import { PromptType } from "@/utils/type";
5
+ import { sleep } from "@/utils";
6
 
7
  export const useQuizz = () => {
8
+ const client = useQueryClient();
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
+ const { data: success } = useQuery<string | null>(['success'], () => null, {
11
+ refetchOnWindowFocus: false,
12
+ refetchOnMount: false,
13
+ refetchOnReconnect: false,
14
+ retry: false,
15
+ });
16
+
17
+ const setSuccess = (s: string | null) => client.setQueryData(['success'], s);
18
 
19
+ const { data: score } = useQuery<number>(['score'], () => 0, {
20
+ refetchOnWindowFocus: false,
21
+ refetchOnMount: false,
22
+ refetchOnReconnect: false,
23
+ retry: false,
24
+ });
25
+
26
+ const onScore = async (id: string) => {
27
+ const request = await fetch(`/api/${data?.quest_id}/score`, {
28
+ method: 'POST',
29
+ body: JSON.stringify({ promptId: id })
30
+ });
31
+
32
+ const response = await request.clone().json().catch(() => ({}));
33
+ if (response?.ok) {
34
+ client.setQueryData(['score'], (score: number | undefined) => {
35
+ return (score ?? 0) + 1;
36
+ });
37
+ setSuccess(id);
38
+ await sleep(3000);
39
+ setSuccess(null);
40
+ await sleep(100);
41
+ client.invalidateQueries(['quizz']);
42
+ refetch()
43
+ }
44
+ };
45
 
46
+ const { data, isFetching: loading, error, refetch } = useQuery<{ prompts: PromptType[], quest_id: string, question: string }>(['quizz'], async () => {
47
+ const request = await fetch(`/api/start`, { method: 'POST' });
48
+ const response = await request.clone().json().catch(() => ({}));
49
+ return response.data;
50
+ }, {
51
+ refetchOnWindowFocus: false,
52
+ refetchOnMount: false,
53
+ refetchOnReconnect: false,
54
+ retry: false,
55
+ });
56
 
57
  return {
58
+ prompts: data?.prompts ?? [],
59
  loading,
60
  error,
61
+ question: data?.question,
62
+ onScore,
63
+ score,
64
+ success
65
  }
66
  }
components/quizz/index.tsx CHANGED
@@ -3,51 +3,33 @@
3
  import Image from "next/image";
4
 
5
  import { useQuizz } from "./hooks/useQuizz";
 
 
 
 
 
 
 
6
 
7
- export const Quizz = () => {
8
- const { loading, quizz, error, generate, correctPrompt } = useQuizz();
9
  return (
10
  <>
11
- {loading && <p>Generating question and images...</p>}
12
- {error && (
13
- <div className="inline-block mx-auto rounded-lg bg-red-500/20 text-red-500 px-4 py-3 text-base">
14
- Something went wrong: {error}
15
- </div>
16
- )}
17
- {quizz && (
18
- <>
19
- {correctPrompt && (
20
- <h1 className="text-5xl font-bold text-white text-center leading-tight relative">
21
- “{correctPrompt?.replaceAll('"', "")}”
22
- </h1>
23
- )}
24
- <div className="grid grid-cols-3 gap-6">
25
- {quizz?.map((item, i) => (
26
- <div
27
- key={i}
28
- className="w-full h-[450px] rounded-lg overflow-hidden"
29
- >
30
- <Image
31
- src={`https://huggingface.co/datasets/enzostvs/what-is-the-prompt/resolve/main/${item?.file_name}?expose=true`}
32
- alt="Generated image"
33
- className="object-center object-cover w-full h-full"
34
- width={250}
35
- height={250}
36
- />
37
- </div>
38
- ))}
39
- </div>
40
- {/* <div className="bg-gray-600 p-4 rounded-lg text-sm text-white">
41
- {JSON.stringify(quizz)}
42
- </div> */}
43
- </>
44
- )}
45
- <button
46
- className="bg-blue-500 text-white text-sm rounded font-semibold px-4 py-2"
47
- onClick={generate}
48
- >
49
- Start a quizz
50
- </button>
51
  </>
52
  );
53
  };
 
3
  import Image from "next/image";
4
 
5
  import { useQuizz } from "./hooks/useQuizz";
6
+ import { PromptType } from "@/utils/type";
7
+ import { Card } from "./card";
8
+
9
+ export const QuizzContent = () => {
10
+ const { loading, prompts, question } = useQuizz();
11
+
12
+ if (loading) return <p>Loading...</p>;
13
 
 
 
14
  return (
15
  <>
16
+ <p className="font-extrabold bg-clip-text text-transparent bg-gradient-to-b from-white to-white/80 text-2xl lg:text-[40px] text-center lg:!leading-snug relative">
17
+ <span className="font-action text-4xl lg:text-7xl !leading-3 text-white translate-y-2 lg:translate-y-4 inline-block pr-2">
18
+
19
+ </span>
20
+ {question}
21
+ <span className="font-action text-4xl lg:text-7xl text-white !leading-3 relative translate-y-5 lg:translate-y-12 pl-2 inline-block">
22
+
23
+ </span>
24
+ </p>
25
+ <p className="text-white/70 font-normal text-lg lg:text-xl text-center">
26
+ Guess which image is related to the prompt below
27
+ </p>
28
+ <div className="flex flex-col lg:flex-row items-center justify-center gap-6 lg:gap-16">
29
+ {prompts?.map((prompt: PromptType, i: number) => (
30
+ <Card prompt={prompt} key={i} />
31
+ ))}
32
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  </>
34
  );
35
  };
components/quizz/layout-score.tsx ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use client";
2
+
3
+ import { useQuizz } from "./hooks/useQuizz";
4
+
5
+ export const LayoutScore = ({ className }: { className?: string }) => {
6
+ const { score } = useQuizz();
7
+ return (
8
+ <p className={`text-white font-extrabold text-xl ${className}`}>
9
+ {score ?? 0} point{(score ?? 0) > 1 && "s"} 🎉
10
+ </p>
11
+ );
12
+ };
components/react-query/hydrate.tsx ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ "use client";
2
+ import React from "react";
3
+ import { Hydrate as HydrationBoundary } from "@tanstack/react-query";
4
+
5
+ function Hydrate(props: { children: React.ReactNode }) {
6
+ return <HydrationBoundary>{props.children}</HydrationBoundary>;
7
+ }
8
+
9
+ export default Hydrate;
components/react-query/providers.tsx ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use client";
2
+ import * as React from "react";
3
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
4
+
5
+ export default function Providers({ children }: { children: React.ReactNode }) {
6
+ const [queryClient] = React.useState(() => new QueryClient());
7
+
8
+ return (
9
+ <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
10
+ );
11
+ }
data/dev.db CHANGED
Binary files a/data/dev.db and b/data/dev.db differ
 
next.config.js CHANGED
@@ -17,7 +17,7 @@ const nextConfig = {
17
  hostname: "aeiljuispo.cloudimg.io",
18
  },
19
  ],
20
- },
21
  }
22
 
23
  module.exports = nextConfig
 
17
  hostname: "aeiljuispo.cloudimg.io",
18
  },
19
  ],
20
+ }
21
  }
22
 
23
  module.exports = nextConfig
package-lock.json CHANGED
The diff for this file is too large to render. See raw diff
 
package.json CHANGED
@@ -11,10 +11,14 @@
11
  "dependencies": {
12
  "@huggingface/hub": "^0.12.1",
13
  "@prisma/client": "^5.6.0",
 
14
  "classnames": "^2.3.2",
 
15
  "next": "14.0.2",
 
16
  "prisma": "^5.6.0",
17
  "react": "^18",
 
18
  "react-dom": "^18",
19
  "react-use": "^17.4.0"
20
  },
 
11
  "dependencies": {
12
  "@huggingface/hub": "^0.12.1",
13
  "@prisma/client": "^5.6.0",
14
+ "@tanstack/react-query": "^4.32.6",
15
  "classnames": "^2.3.2",
16
+ "install": "^0.13.0",
17
  "next": "14.0.2",
18
+ "npm": "^10.2.4",
19
  "prisma": "^5.6.0",
20
  "react": "^18",
21
+ "react-confetti": "^6.1.0",
22
  "react-dom": "^18",
23
  "react-use": "^17.4.0"
24
  },
prisma/schema.prisma CHANGED
@@ -4,11 +4,17 @@ generator client {
4
 
5
  datasource db {
6
  provider = "sqlite"
7
- url = "file://data/dev.db"
8
  }
9
 
10
  model Prompt {
11
- id Int @id @default(autoincrement())
12
  prompt String
13
  file_name String
14
  }
 
 
 
 
 
 
 
4
 
5
  datasource db {
6
  provider = "sqlite"
7
+ url = "file:../data/dev.db"
8
  }
9
 
10
  model Prompt {
11
+ id String @id @default(uuid())
12
  prompt String
13
  file_name String
14
  }
15
+
16
+ model Quest {
17
+ id String @id @default(uuid())
18
+ prompt_id_correct String
19
+ created_at DateTime @default(now())
20
+ }
tailwind.config.ts CHANGED
@@ -10,7 +10,7 @@ const config: Config = {
10
  extend: {
11
  fontFamily: {
12
  sans: ["Trap", "serif"],
13
- action: ["Inter", "sans-serif"]
14
  },
15
  backgroundImage: {
16
  'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
 
10
  extend: {
11
  fontFamily: {
12
  sans: ["Trap", "serif"],
13
+ action: ['var(--font-inter)', "sans-serif"]
14
  },
15
  backgroundImage: {
16
  'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
utils/index.ts ADDED
@@ -0,0 +1 @@
 
 
1
+ export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
utils/type.ts CHANGED
@@ -4,6 +4,7 @@ export interface QuizzType {
4
 
5
  export interface PromptType {
6
  prompt: string,
 
7
  is_correct: boolean,
8
  file_name?: string,
9
  }
 
4
 
5
  export interface PromptType {
6
  prompt: string,
7
+ id: string,
8
  is_correct: boolean,
9
  file_name?: string,
10
  }