Dashboard Stats

This commit is contained in:
Nicolas
2025-02-28 03:10:48 +01:00
parent c5b8a7c4cb
commit cda2dec67c
13 changed files with 202 additions and 245 deletions

View File

@@ -0,0 +1,44 @@
import { PlaneIcon, Workflow } from "lucide-react";
import { useSession } from "next-auth/react";
interface HeaderProps {
isChecked: boolean;
handleCheckboxChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
}
export const Header = ({ isChecked, handleCheckboxChange }: HeaderProps) => {
const session = useSession();
console.log(session);
return (
<header className="flex justify-between items-center p-4">
<h1 className="text-2xl font-bold">
Hallo,{" "}
{session.status === "authenticated"
? session.data?.user.firstname
: "<username>"}
{"!"}
</h1>
<div>
<div className="tooltip" data-tip="Disponent / Pilot">
<label className="toggle text-base-content">
<input
type="checkbox"
checked={isChecked}
onChange={handleCheckboxChange}
/>
<Workflow
className="w-4 h-4"
viewBox="0 0 24 24"
aria-label="enabled"
/>
<PlaneIcon
className="w-4 h-4"
viewBox="0 0 24 24"
aria-label="disabled"
/>
</label>
</div>
</div>
</header>
);
};

View File

@@ -0,0 +1,129 @@
import { PlaneIcon } from "lucide-react";
interface StatsProps {
isChecked: boolean;
}
export const Stats = ({ isChecked }: StatsProps) => {
return isChecked ? PilotStats() : DispoStats();
};
export const PilotStats = (): JSX.Element => {
return (
<div className="stats shadow">
<div className="stat">
<div className="stat-figure text-primary">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
className="inline-block h-8 w-8 stroke-current"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"
></path>
</svg>
</div>
<div className="stat-title">Einsätze geflogen</div>
<div className="stat-value text-primary">127</div>
<div className="stat-desc">Du bist damit unter den top 5%!</div>
</div>
<div className="stat">
<div className="stat-figure text-secondary">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
className="inline-block h-8 w-8 stroke-current"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M13 10V3L4 14h7v7l9-11h-7z"
></path>
</svg>
</div>
<div className="stat-title">Pilot Login Zeit</div>
<div className="stat-value text-secondary">35h 12m</div>
<div className="stat-desc">Mehr als 58% aller anderen User!</div>
</div>
<div className="stat">
<div className="stat-figure text-info">
<PlaneIcon className="w-8 h-8" />
</div>
<div className="stat-value text-info">Christoph 31</div>
<div className="stat-title">
War bisher dein Rettungsmittel der Wahl
</div>
<div className="stat-desc text-secondary">
87 Stationen warten noch auf dich!
</div>
</div>
</div>
);
};
export const DispoStats = (): JSX.Element => {
return (
<div className="stats shadow">
<div className="stat">
<div className="stat-figure text-primary">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
className="inline-block h-8 w-8 stroke-current"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"
></path>
</svg>
</div>
<div className="stat-title">Einsätze disponiert</div>
<div className="stat-value text-primary">578</div>
<div className="stat-desc">Du bist damit unter den top 9%!</div>
</div>
<div className="stat">
<div className="stat-figure text-secondary">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
className="inline-block h-8 w-8 stroke-current"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M13 10V3L4 14h7v7l9-11h-7z"
></path>
</svg>
</div>
<div className="stat-title">Disponent Login Zeit</div>
<div className="stat-value text-secondary">53h 12m</div>
<div className="stat-desc">Mehr als 69% aller anderen User!</div>
</div>
<div className="stat">
<div className="stat-figure text-info">
<PlaneIcon className="w-8 h-8" />
</div>
<div className="stat-value text-info">Christoph Berlin</div>
<div className="stat-title">Wurde von dir am meisten Disponiert</div>
<div className="stat-desc text-secondary">
43 Stationen warten auf deine Einsätze!
</div>
</div>
</div>
);
};

View File

@@ -1,81 +1,35 @@
import Link from "next/link"; "use client";
import { PaginatedTable } from "../_components/PaginatedTable";
import { Header } from "../_components/ui/Header"; import { useState } from "react";
import { Header } from "./_components/Header";
import { Stats } from "./_components/stats";
/*
✔️ Einlog-Zeit
✔️ Stats
✔️ Pilot / Disponent TODO: Selection persistent machen
Map - I dont know man, passt hier vielleicht nicht rein
Logbuch / Einsatzhistorie
Badges
Aktive Events / Mandatory Events
*/
export default function Home() {
const [isChecked, setIsChecked] = useState(true);
const handleCheckboxChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setIsChecked(event.target.checked);
};
export default async function Home() {
return ( return (
<div> <div>
<Header /> <Header
<PaginatedTable isChecked={isChecked}
rowsPerPage={10} handleCheckboxChange={handleCheckboxChange}
prismaModel={"user"}
searchFields={[]}
columns={[
{
header: "ID",
accessorKey: "id",
},
{
header: "Email",
accessorKey: "email",
},
{
header: "First Name",
accessorKey: "firstname",
},
{
header: "Last Name",
accessorKey: "lastname",
footer: "Total",
},
]}
/> />
Map <div className="card bg-base-200 shadow-xl mb-4 col-span-6 xl:col-span-3">
<br /> <Stats isChecked={isChecked} />
Logbuch </div>
<br />
Einlog-Zeit (7 Tage, total)
<br />
Stats
<br />
Badges
<br />
gd
<br />
gd
<br />
gd
<br />
gd
<br />
gd
<br />
gd
<br />
gd
<br />
gd
<br />
gd
<br />
gd
<br />
gd
<br />
gd
<br />
gd
<br />
gd
<br />
gd
<br />
gd
<br />
gd
<br />
gd
<br />
</div> </div>
); );
} }

View File

@@ -171,17 +171,11 @@ export const SocialForm = ({
}); });
})} })}
> >
<h2 className="card-title"> <h2 className="card-title mb-5">
<Link2Icon className="w-5 h-5" /> Verbindungen & Benachrichtigungen <Link2Icon className="w-5 h-5" /> Verbindungen & Benachrichtigungen
</h2> </h2>
<div> <div>
<div> <div>
<div className="label">
<span className="label-text text-lg flex items-center gap-2">
<DiscordLogoIcon /> Discord
</span>
</div>
{discordAccount ? ( {discordAccount ? (
<Button <Button
className="btn-success btn-block btn-outline group transition-all duration-0 hover:btn-error" className="btn-success btn-block btn-outline group transition-all duration-0 hover:btn-error"

View File

@@ -16,11 +16,6 @@ export const VerticalNav = () => {
<HomeIcon /> Dashboard <HomeIcon /> Dashboard
</Link> </Link>
</li> </li>
<li>
<Link href="/profile">
<PersonIcon /> Profile
</Link>
</li>
<li> <li>
<Link href="/events"> <Link href="/events">
<RocketIcon /> <RocketIcon />

View File

@@ -1,23 +0,0 @@
'use client';
import { useSession } from 'next-auth/react';
import Link from 'next/link';
export const Header = () => {
const session = useSession();
console.log(session);
return (
<header className="flex justify-between items-center p-4">
<h1 className="text-2xl font-bold">Hub</h1>
<div>
{session.status === 'authenticated' ? (
<p>{session.data?.user.firstname}</p>
) : (
<Link href="/login">
<button className="btn">Login</button>
</Link>
)}
</div>
</header>
);
};

View File

@@ -1,17 +0,0 @@
/*
Warnings:
- Made the column `eventId` on table `Participant` required. This step will fail if there are existing NULL values in that column.
*/
-- DropForeignKey
ALTER TABLE "Participant" DROP CONSTRAINT "Participant_eventId_fkey";
-- AlterTable
ALTER TABLE "Event" ALTER COLUMN "maxParticipants" SET DEFAULT 0;
-- AlterTable
ALTER TABLE "Participant" ALTER COLUMN "eventId" SET NOT NULL;
-- AddForeignKey
ALTER TABLE "Participant" ADD CONSTRAINT "Participant_eventId_fkey" FOREIGN KEY ("eventId") REFERENCES "Event"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

View File

@@ -1,4 +0,0 @@
-- AlterTable
ALTER TABLE "Event" ALTER COLUMN "discordRoleId" SET DEFAULT '',
ALTER COLUMN "starterMoodleCourseId" SET DATA TYPE TEXT,
ALTER COLUMN "finisherMoodleCourseId" SET DATA TYPE TEXT;

View File

@@ -1,3 +0,0 @@
-- AlterTable
ALTER TABLE "Event" ALTER COLUMN "starterMoodleCourseId" SET DEFAULT '',
ALTER COLUMN "finisherMoodleCourseId" SET DEFAULT '';

View File

@@ -1,9 +0,0 @@
-- CreateEnum
CREATE TYPE "BADGES" AS ENUM ('P1', 'P2', 'P3', 'D1', 'D2', 'D3', 'DAY1');
-- CreateEnum
CREATE TYPE "PERMISSION" AS ENUM ('ADMIN_EVENT', 'ADMIN_USER', 'SUSPENDED');
-- AlterTable
ALTER TABLE "users" ADD COLUMN "badges" "BADGES"[] DEFAULT ARRAY[]::"BADGES"[],
ADD COLUMN "permissions" "PERMISSION"[] DEFAULT ARRAY[]::"PERMISSION"[];

View File

@@ -1,57 +0,0 @@
/*
Warnings:
- You are about to drop the column `selectedForParticipatioon` on the `Participant` table. All the data in the column will be lost.
- You are about to drop the column `status` on the `Participant` table. All the data in the column will be lost.
- Added the required column `eventAppointmentId` to the `Participant` table without a default value. This is not possible if the table is not empty.
*/
-- AlterEnum
-- This migration adds more than one value to an enum.
-- With PostgreSQL versions 11 and earlier, this is not possible
-- in a single migration. This can be worked around by creating
-- multiple migrations, each migration adding only one value to
-- the enum.
ALTER TYPE "PERMISSION" ADD VALUE 'PILOT';
ALTER TYPE "PERMISSION" ADD VALUE 'DISPO';
-- AlterTable
ALTER TABLE "Participant" DROP COLUMN "selectedForParticipatioon",
DROP COLUMN "status",
ADD COLUMN "eventAppointmentId" INTEGER NOT NULL,
ADD COLUMN "finisherMoodleCurseCompleted" BOOLEAN NOT NULL DEFAULT false,
ADD COLUMN "starterMoodleCurseCompleted" BOOLEAN NOT NULL DEFAULT false;
-- CreateTable
CREATE TABLE "EventAppointment" (
"id" SERIAL NOT NULL,
"eventId" INTEGER NOT NULL,
"appointmentDate" TIMESTAMP(3) NOT NULL,
CONSTRAINT "EventAppointment_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "_EventAppointmentToUser" (
"A" INTEGER NOT NULL,
"B" TEXT NOT NULL,
CONSTRAINT "_EventAppointmentToUser_AB_pkey" PRIMARY KEY ("A","B")
);
-- CreateIndex
CREATE INDEX "_EventAppointmentToUser_B_index" ON "_EventAppointmentToUser"("B");
-- AddForeignKey
ALTER TABLE "EventAppointment" ADD CONSTRAINT "EventAppointment_eventId_fkey" FOREIGN KEY ("eventId") REFERENCES "Event"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Participant" ADD CONSTRAINT "Participant_eventAppointmentId_fkey" FOREIGN KEY ("eventAppointmentId") REFERENCES "EventAppointment"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "_EventAppointmentToUser" ADD CONSTRAINT "_EventAppointmentToUser_A_fkey" FOREIGN KEY ("A") REFERENCES "EventAppointment"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "_EventAppointmentToUser" ADD CONSTRAINT "_EventAppointmentToUser_B_fkey" FOREIGN KEY ("B") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@@ -1,8 +0,0 @@
-- DropForeignKey
ALTER TABLE "Participant" DROP CONSTRAINT "Participant_eventAppointmentId_fkey";
-- AlterTable
ALTER TABLE "Participant" ALTER COLUMN "eventAppointmentId" DROP NOT NULL;
-- AddForeignKey
ALTER TABLE "Participant" ADD CONSTRAINT "Participant_eventAppointmentId_fkey" FOREIGN KEY ("eventAppointmentId") REFERENCES "EventAppointment"("id") ON DELETE SET NULL ON UPDATE CASCADE;

View File

@@ -1,38 +0,0 @@
/*
Warnings:
- You are about to drop the `_EventAppointmentToUser` table. If the table is not empty, all the data it contains will be lost.
- Added the required column `presenterId` to the `EventAppointment` table without a default value. This is not possible if the table is not empty.
*/
-- DropForeignKey
ALTER TABLE "_EventAppointmentToUser" DROP CONSTRAINT "_EventAppointmentToUser_A_fkey";
-- DropForeignKey
ALTER TABLE "_EventAppointmentToUser" DROP CONSTRAINT "_EventAppointmentToUser_B_fkey";
-- AlterTable
ALTER TABLE "EventAppointment" ADD COLUMN "presenterId" TEXT NOT NULL;
-- DropTable
DROP TABLE "_EventAppointmentToUser";
-- CreateTable
CREATE TABLE "_EventAppointmentUser" (
"A" INTEGER NOT NULL,
"B" TEXT NOT NULL,
CONSTRAINT "_EventAppointmentUser_AB_pkey" PRIMARY KEY ("A","B")
);
-- CreateIndex
CREATE INDEX "_EventAppointmentUser_B_index" ON "_EventAppointmentUser"("B");
-- AddForeignKey
ALTER TABLE "EventAppointment" ADD CONSTRAINT "EventAppointment_presenterId_fkey" FOREIGN KEY ("presenterId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "_EventAppointmentUser" ADD CONSTRAINT "_EventAppointmentUser_A_fkey" FOREIGN KEY ("A") REFERENCES "EventAppointment"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "_EventAppointmentUser" ADD CONSTRAINT "_EventAppointmentUser_B_fkey" FOREIGN KEY ("B") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;