diff --git a/README.md b/README.md
index b1c3f91..b341baf 100644
--- a/README.md
+++ b/README.md
@@ -32,7 +32,7 @@ npm run start
## Credits
-Made with love by [Elie Baier](https://github.com/fayorg) & [Tim Haller](https://github.com/timhaller).
+Designed & made with love by [Elie Baier](https://github.com/fayorg), [Tim Haller](https://github.com/timhaller) & [Michal Polka](https://github.com/michalpolka).
We'd like to thanks Ms. Tixhon for the good idea and the great gifts!
diff --git a/actions/mangeTest.ts b/actions/mangeTest.ts
new file mode 100644
index 0000000..74822da
--- /dev/null
+++ b/actions/mangeTest.ts
@@ -0,0 +1,12 @@
+"use server";
+
+import prisma from "@/lib/prisma";
+
+export async function setTestActive(id: number, active: boolean) {
+ const users = await prisma.users.findFirst();
+
+ console.log(users);
+
+ return true;
+
+}
\ No newline at end of file
diff --git a/app/dashboard/ActiveCard.tsx b/app/dashboard/ActiveCard.tsx
new file mode 100644
index 0000000..4152d49
--- /dev/null
+++ b/app/dashboard/ActiveCard.tsx
@@ -0,0 +1,22 @@
+'use client';
+
+import { setTestActive } from '@/actions/mangeTest';
+import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from '@/components/ui/alert-dialog';
+
+export default function ActiveCard() {
+ return (
+
+ Open
+
+
+ Etes-vous sur de vouloir terminer ce test?
+ Les votations ne seront plus ouverte pour ce test. Vous pouvez cependant le réactiver dans le dashboard.
+
+
+ Cancel
+ setTestActive(1, true)}>Continue
+
+
+
+ );
+}
diff --git a/app/dashboard/page.tsx b/app/dashboard/page.tsx
new file mode 100644
index 0000000..7cf6c54
--- /dev/null
+++ b/app/dashboard/page.tsx
@@ -0,0 +1,25 @@
+import prisma from '@/lib/prisma';
+import ActiveCard from './ActiveCard';
+
+export default async function Dashboard() {
+ const tests = await prisma.test.findMany({ select: { isActive: true, isPassed: true, id: true, testOf: { select: { id: true, firstName: true, lastName: true, isTeacher: true } } } });
+
+ const activeTests = tests.filter((test) => test.isActive);
+ const passedTests = tests.filter((test) => test.isPassed);
+
+ return (
+
+
Dashboard
+
+
Test(s) Actif(s) :
+
+ {activeTests.map((test) => (
+ -
+ {test.testOf.firstName + ' ' + test.testOf.lastName}
+
+ ))}
+
+
+
+ );
+}
diff --git a/app/layout.tsx b/app/layout.tsx
index dd3b95c..027c8dc 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,12 +1,19 @@
-import type { Metadata } from 'next';
import { Inter } from 'next/font/google';
import '@styles/global.css';
const inter = Inter({ subsets: ['latin'] });
+import type { Metadata } from "next";
+
+export const metadata: Metadata = {
+ title: 'Calendrier de l\'avent',
+ description: 'Calendrier de l\'avent de maths de la 3M03',
+};
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
+
{children}
);
diff --git a/app/results/[id]/page.tsx b/app/results/[id]/page.tsx
index dc1412c..021e298 100644
--- a/app/results/[id]/page.tsx
+++ b/app/results/[id]/page.tsx
@@ -1,42 +1,46 @@
-"use server";
-import {Chart} from "@components/custom/chart";
-import logo from "@images/logo.svg";
-import Image from "next/image";
-import Prisma from '@lib/prisma'
+'use server';
+import { Chart } from '@components/custom/chart';
+import logo from '@images/logo.svg';
+import Image from 'next/image';
+import Prisma from '@lib/prisma';
interface data {
- name: string
- total: number
+ name: string;
+ total: number;
}
export default async function Page({ params }: { params: { id: string } }) {
+ const teacherGrade = await Prisma.grade.findFirst({ where: { testId: parseInt(params.id), user: { isTeacher: true } } });
- const grades = await Prisma.grade.findMany({ where: { testId: parseInt(params.id) }})
- const allGrades = ['1', '1.5', '2', '2.5', '3', '3.5', '4', '4.5', '5', '5.5', '6']
- let gradeOccurences = new Array(allGrades.length).fill(0)
- const gradeList = grades.map((grade) => grade.grade)
+ const grades = await Prisma.grade.findMany({where: {testId: parseInt(params.id), user: {isTeacher: false}}});
- for (let i = 0; i < gradeList.length; i++) {
- gradeOccurences[allGrades.indexOf(gradeList[i].toString())]++
- }
+ const allGrades = ['1', '1.5', '2', '2.5', '3', '3.5', '4', '4.5', '5', '5.5', '6'];
+ let gradeOccurences = new Array(allGrades.length).fill(0);
+ const gradeList = grades.map((grade) => grade.grade);
- let data: data[] = []
- for (let i = 0; i < gradeOccurences.length; i++) {
- data.push({
- name: allGrades[i],
- total: gradeOccurences[i]
- })
- }
- for (let grade in grades) {
- console.log(grade);
- }
+ for (let i = 0; i < gradeList.length; i++) {
+ gradeOccurences[allGrades.indexOf(gradeList[i].toString())]++;
+ }
- return (
-
-
-
-
- )
+ let data: data[] = [];
+ for (let i = 0; i < gradeOccurences.length; i++) {
+ data.push({
+ name: allGrades[i],
+ total: gradeOccurences[i],
+ });
+ }
+ return (
+
+
+ {teacherGrade && (
+
+
Mme Tixhon :
+
{teacherGrade.grade}
+
+ )}
+
+
+ );
}
diff --git a/assets/end.mp3 b/assets/end.mp3
new file mode 100644
index 0000000..f66643c
Binary files /dev/null and b/assets/end.mp3 differ
diff --git a/components/custom/chart.tsx b/components/custom/chart.tsx
index b40690c..a271d8f 100644
--- a/components/custom/chart.tsx
+++ b/components/custom/chart.tsx
@@ -11,19 +11,21 @@ interface ChartProps {
export function Chart({...props}: ChartProps) {
return (
-
-
- {props.data.map((item, index) => (
-
- ))}
-
-
- {props.data.map((item, index) => (
-
- ))}
+
+
+
+ {props.data.map((item, index) => (
+
+ ))}
+
+
+ {props.data.map((item, index) => (
+
+ ))}
+
)
diff --git a/components/custom/countdown.tsx b/components/custom/countdown.tsx
new file mode 100644
index 0000000..a60571f
--- /dev/null
+++ b/components/custom/countdown.tsx
@@ -0,0 +1,43 @@
+"use client";
+
+import React from 'react';
+import { useTimer } from 'react-timer-hook';
+
+import { Button } from "@components/ui/button";
+import { PauseIcon, Play} from "lucide-react";
+
+interface MyTimerProps {
+ expiryTimestamp: Date;
+ onEnd?: () => void;
+}
+
+export default function MyTimer({ expiryTimestamp, onEnd } : MyTimerProps) {
+ const {
+ seconds,
+ minutes,
+ isRunning,
+ pause,
+ resume,
+ } = useTimer({
+ expiryTimestamp,
+ onExpire: () => onEnd && onEnd()
+ })
+
+ return (
+
+
+ {String(minutes).padStart(2, "0")}:
+ {String(seconds).padStart(2, "0")}
+
+
{isRunning ? 'Running' : 'Not running'}
+
+
+ );
+}
diff --git a/components/ui/alert-dialog.tsx b/components/ui/alert-dialog.tsx
new file mode 100644
index 0000000..ce104c2
--- /dev/null
+++ b/components/ui/alert-dialog.tsx
@@ -0,0 +1,141 @@
+"use client"
+
+import * as React from "react"
+import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
+
+import { cn } from "@/lib/utils"
+import { buttonVariants } from "@/components/ui/button"
+
+const AlertDialog = AlertDialogPrimitive.Root
+
+const AlertDialogTrigger = AlertDialogPrimitive.Trigger
+
+const AlertDialogPortal = AlertDialogPrimitive.Portal
+
+const AlertDialogOverlay = React.forwardRef<
+ React.ElementRef
,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName
+
+const AlertDialogContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+
+
+
+))
+AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
+
+const AlertDialogHeader = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
+
+)
+AlertDialogHeader.displayName = "AlertDialogHeader"
+
+const AlertDialogFooter = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
+
+)
+AlertDialogFooter.displayName = "AlertDialogFooter"
+
+const AlertDialogTitle = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
+
+const AlertDialogDescription = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogDescription.displayName =
+ AlertDialogPrimitive.Description.displayName
+
+const AlertDialogAction = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName
+
+const AlertDialogCancel = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
+
+export {
+ AlertDialog,
+ AlertDialogPortal,
+ AlertDialogOverlay,
+ AlertDialogTrigger,
+ AlertDialogContent,
+ AlertDialogHeader,
+ AlertDialogFooter,
+ AlertDialogTitle,
+ AlertDialogDescription,
+ AlertDialogAction,
+ AlertDialogCancel,
+}
diff --git a/components/ui/button.tsx b/components/ui/button.tsx
new file mode 100644
index 0000000..0ba4277
--- /dev/null
+++ b/components/ui/button.tsx
@@ -0,0 +1,56 @@
+import * as React from "react"
+import { Slot } from "@radix-ui/react-slot"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+
+const buttonVariants = cva(
+ "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
+ {
+ variants: {
+ variant: {
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
+ destructive:
+ "bg-destructive text-destructive-foreground hover:bg-destructive/90",
+ outline:
+ "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
+ secondary:
+ "bg-secondary text-secondary-foreground hover:bg-secondary/80",
+ ghost: "hover:bg-accent hover:text-accent-foreground",
+ link: "text-primary underline-offset-4 hover:underline",
+ },
+ size: {
+ default: "h-10 px-4 py-2",
+ sm: "h-9 rounded-md px-3",
+ lg: "h-11 rounded-md px-8",
+ icon: "h-10 w-10",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ }
+)
+
+export interface ButtonProps
+ extends React.ButtonHTMLAttributes,
+ VariantProps {
+ asChild?: boolean
+}
+
+const Button = React.forwardRef(
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
+ const Comp = asChild ? Slot : "button"
+ return (
+
+ )
+ }
+)
+Button.displayName = "Button"
+
+export { Button, buttonVariants }
diff --git a/package-lock.json b/package-lock.json
index 22a96ec..f976ea6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,6 +9,7 @@
"version": "0.1.0",
"dependencies": {
"@prisma/client": "^5.6.0",
+ "@radix-ui/react-alert-dialog": "^1.0.5",
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-slider": "^1.1.2",
"@radix-ui/react-slot": "^1.0.2",
@@ -22,6 +23,7 @@
"react": "^18",
"react-chartjs-2": "^5.2.0",
"react-dom": "^18",
+ "react-timer-hook": "^3.0.7",
"socket.io": "^4.7.2",
"socket.io-client": "^4.7.2",
"swr": "^2.2.4",
@@ -471,6 +473,34 @@
"@babel/runtime": "^7.13.10"
}
},
+ "node_modules/@radix-ui/react-alert-dialog": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.0.5.tgz",
+ "integrity": "sha512-OrVIOcZL0tl6xibeuGt5/+UxoT2N27KCFOPjFyfXMnchxSHZ/OW7cCX2nGlIYJrbHK/fczPcFzAwvNBB6XBNMA==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-context": "1.0.1",
+ "@radix-ui/react-dialog": "1.0.5",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-slot": "1.0.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-arrow": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.0.3.tgz",
@@ -554,6 +584,42 @@
}
}
},
+ "node_modules/@radix-ui/react-dialog": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.0.5.tgz",
+ "integrity": "sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-context": "1.0.1",
+ "@radix-ui/react-dismissable-layer": "1.0.5",
+ "@radix-ui/react-focus-guards": "1.0.1",
+ "@radix-ui/react-focus-scope": "1.0.4",
+ "@radix-ui/react-id": "1.0.1",
+ "@radix-ui/react-portal": "1.0.4",
+ "@radix-ui/react-presence": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-slot": "1.0.2",
+ "@radix-ui/react-use-controllable-state": "1.0.1",
+ "aria-hidden": "^1.1.1",
+ "react-remove-scroll": "2.5.5"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-direction": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.0.1.tgz",
@@ -4370,6 +4436,14 @@
}
}
},
+ "node_modules/react-timer-hook": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/react-timer-hook/-/react-timer-hook-3.0.7.tgz",
+ "integrity": "sha512-ATpNcU+PQRxxfNBPVqce2+REtjGAlwmfoNQfcEBMZFxPj0r3GYdKhyPHdStvqrejejEi0QvqaJZjy2lBlFvAsA==",
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ }
+ },
"node_modules/read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
diff --git a/package.json b/package.json
index 4b194bb..826bdc1 100644
--- a/package.json
+++ b/package.json
@@ -10,6 +10,7 @@
},
"dependencies": {
"@prisma/client": "^5.6.0",
+ "@radix-ui/react-alert-dialog": "^1.0.5",
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-slider": "^1.1.2",
"@radix-ui/react-slot": "^1.0.2",
@@ -23,6 +24,7 @@
"react": "^18",
"react-chartjs-2": "^5.2.0",
"react-dom": "^18",
+ "react-timer-hook": "^3.0.7",
"socket.io": "^4.7.2",
"socket.io-client": "^4.7.2",
"swr": "^2.2.4",
diff --git a/styles/global.css b/styles/global.css
index fb1ff9a..fe6db4b 100644
--- a/styles/global.css
+++ b/styles/global.css
@@ -47,4 +47,23 @@
--input: 0 0% 80%;
--ring: 348 71% 60%;
}
+
+ html {
+ padding-top: env(safe-area-inset-top);
+ padding-bottom: env(safe-area-inset-bottom);
+ background-color: black;
+ }
+
+ body {
+ padding-top: env(safe-area-inset-top);
+ padding-bottom: env(safe-area-inset-bottom);
+ background-color: black;
+ }
+
+ /* If using React, set height on the root div as well */
+ #root {
+ padding-top: env(safe-area-inset-top);
+ padding-bottom: env(safe-area-inset-bottom);
+ background-color: black;
+ }
}
diff --git a/tsconfig.json b/tsconfig.json
index 709a6e8..66d7499 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -25,8 +25,9 @@
"@styles/*": ["/styles/*"],
"@santa/*": ["./images/santa/*"],
"@images/*": ["./images/*"],
+ "@assets/*": ["./assets/*"],
}
},
- "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "**/*.d.ts"],
"exclude": ["node_modules"]
}
diff --git a/types/sounds.d.ts b/types/sounds.d.ts
new file mode 100644
index 0000000..3f6ebdd
--- /dev/null
+++ b/types/sounds.d.ts
@@ -0,0 +1,4 @@
+declare module '*.mp3' {
+ const content: string;
+ export default content;
+}