Dashboard Design continue

This commit is contained in:
Nicolas
2025-03-02 12:52:03 +01:00
parent e964c7d175
commit 3f4c77ef39
7 changed files with 315 additions and 138 deletions

View File

@@ -0,0 +1,56 @@
import { getServerSession } from "../../api/auth/[...nextauth]/auth";
import { PrismaClient } from "@repo/db";
import { KursItem } from "../events/_components/item";
export default async () => {
const prisma = new PrismaClient();
const session = await getServerSession();
if (!session) return null;
const user = await prisma.user.findUnique({
where: {
id: session.user.id,
},
});
if (!user) return null;
const events = await prisma.event.findMany({
include: {
appointments: {
where: {
appointmentDate: {
gte: new Date(),
},
},
},
participants: {
where: {
userId: user.id,
},
},
},
});
const userAppointments = await prisma.eventAppointment.findMany({
where: {
Participants: {
some: {
userId: user.id,
},
},
},
});
return (
<div className="grid grid-cols-6 gap-4">
{events.map((event) => {
return (
<KursItem
selectedAppointments={userAppointments}
user={user}
event={event}
key={event.id}
/>
);
})}
</div>
);
};

View File

@@ -6,7 +6,7 @@ interface HeaderProps {
handleCheckboxChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
}
export const Header = ({ isChecked, handleCheckboxChange }: HeaderProps) => {
export default ({ isChecked, handleCheckboxChange }: HeaderProps) => {
const session = useSession();
return (
<header className="flex justify-between items-center p-4">

View File

@@ -0,0 +1,66 @@
import SortableTable from "../../_components/Table";
export default async () => {
const columns = [
{
header: "Station",
accessorKey: "publicId",
},
{
header: "Einsatz Start",
accessorKey: "firstname",
},
{
header: "Einsatz Ende",
accessorKey: "lastname",
},
{
header: "Flugzeit",
accessorKey: "email",
},
];
const data: any[] = [
{
publicId: "Station 1",
firstname: "01.01.2021 12:00",
lastname: "01.01.2021 13:04",
email: "01h 04m",
},
{
publicId: "Station 1",
firstname: "01.01.2021 12:00",
lastname: "01.01.2021 13:04",
email: "01h 04m",
},
{
publicId: "Station 1",
firstname: "01.01.2021 12:00",
lastname: "01.01.2021 13:04",
email: "01h 04m",
},
{
publicId: "Station 1",
firstname: "01.01.2021 12:00",
lastname: "01.01.2021 13:04",
email: "01h 04m",
},
{
publicId: "Station 1",
firstname: "01.01.2021 12:00",
lastname: "01.01.2021 13:04",
email: "01h 04m",
},
];
return (
<>
<SortableTable
data={data}
columns={columns}
showEditButton={false} // Set to true if you want to show edit buttons
prismaModel="user" // Pass the prisma model if needed
/>
</>
);
};

View File

@@ -0,0 +1,25 @@
"use client";
import { useState } from "react";
import Header from "./Header";
import Stats from "./stats";
export default () => {
const [isChecked, setIsChecked] = useState(true);
const handleCheckboxChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setIsChecked(event.target.checked);
};
return (
<>
<Header
isChecked={isChecked}
handleCheckboxChange={handleCheckboxChange}
/>
<div className="card bg-base-200 shadow-xl mb-4 col-span-6 xl:col-span-3">
<Stats isChecked={isChecked} />
</div>
</>
);
};

View File

@@ -1,129 +1,129 @@
import { PlaneIcon } from "lucide-react";
interface StatsProps {
isChecked: boolean;
isChecked: boolean;
}
export const Stats = ({ isChecked }: StatsProps) => {
return isChecked ? PilotStats() : DispoStats();
export default ({ 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>
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-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>
);
<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>
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-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>
);
<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,8 +1,8 @@
"use client";
import { useState } from "react";
import { Header } from "./_components/Header";
import { Stats } from "./_components/stats";
import Logbook from "./_components/Logbook";
import { ArrowRight, NotebookText, Award, RocketIcon } from "lucide-react";
import Link from "next/link";
import Events from "./_components/Events";
import StatsClientWrapper from "./_components/StatsClientWrapper";
/*
✔️ Einlog-Zeit
@@ -15,21 +15,45 @@ Aktive Events / Mandatory Events
*/
export default function Home() {
const [isChecked, setIsChecked] = useState(true);
const handleCheckboxChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setIsChecked(event.target.checked);
};
return (
<div>
<Header
isChecked={isChecked}
handleCheckboxChange={handleCheckboxChange}
/>
<div className="card bg-base-200 shadow-xl mb-4 col-span-6 xl:col-span-3">
<Stats isChecked={isChecked} />
<StatsClientWrapper />
<div className="grid grid-cols-6 gap-4">
<div className="card bg-base-200 shadow-xl mb-4 col-span-6 xl:col-span-3">
<div className="card-body">
<h2 className="card-title justify-between">
<span className="card-title">
<NotebookText className="w-4 h-4" /> Logbook
</span>
<Link
className="badge badge-sm badge-info badge-outline"
href="/settings"
>
Zum vollständigen Logbook <ArrowRight className="w-4 h-4" />
</Link>
</h2>
<Logbook />
</div>
</div>
<div className="card bg-base-200 shadow-xl mb-4 col-span-6 xl:col-span-3">
<div className="card-body">
<h2 className="card-title justify-between">
<span className="card-title">
<Award className="w-4 h-4" /> Verdiente Abzeichen
</span>
</h2>
Badges
</div>
</div>
</div>
<div className="col-span-full">
<p className="text-xl font-semibold text-left flex items-center gap-2 mb-2 mt-5">
<RocketIcon className="w-4 h-4" /> Laufende Events & Kurse
</p>
</div>
<Events />
</div>
);
}

View File

@@ -1,10 +1,10 @@
import {
HomeIcon,
PersonIcon,
GearIcon,
ExitIcon,
LockClosedIcon,
RocketIcon,
ReaderIcon,
} from "@radix-ui/react-icons";
import Link from "next/link";
@@ -22,6 +22,18 @@ export const VerticalNav = () => {
Events & Kurse
</Link>
</li>
<li>
<Link href="/events">
<ReaderIcon />
Logbook
</Link>
</li>
<li>
<Link href="/settings">
<GearIcon />
Einstellungen
</Link>
</li>
<li>
<details open>
<summary>
@@ -41,12 +53,6 @@ export const VerticalNav = () => {
</ul>
</details>
</li>
<li>
<Link href="/settings">
<GearIcon />
Einstellungen
</Link>
</li>
</ul>
);
};