removed console.log statements
This commit is contained in:
@@ -1,2 +1,2 @@
|
|||||||
import "modules/chron";
|
import "modules/chron";
|
||||||
console.log("VAR hub Server started");
|
console.log("VAR hub Server started");
|
||||||
|
|||||||
@@ -1,246 +1,245 @@
|
|||||||
'use client';
|
"use client";
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { StationOptionalDefaultsSchema } from '@repo/db/zod';
|
import { StationOptionalDefaultsSchema } from "@repo/db/zod";
|
||||||
import { set, useForm } from 'react-hook-form';
|
import { set, useForm } from "react-hook-form";
|
||||||
import { z } from 'zod';
|
import { z } from "zod";
|
||||||
import { BosUse, Country, Station } from '@repo/db';
|
import { BosUse, Country, Station } from "@repo/db";
|
||||||
import { FileText, LocateIcon, PlaneIcon } from 'lucide-react';
|
import { FileText, LocateIcon, PlaneIcon } from "lucide-react";
|
||||||
import { Input } from '../../../../_components/ui/Input';
|
import { Input } from "../../../../_components/ui/Input";
|
||||||
import { useState } from 'react';
|
import { useState } from "react";
|
||||||
import { deleteStation, upsertStation } from '../action';
|
import { deleteStation, upsertStation } from "../action";
|
||||||
import { Button } from '../../../../_components/ui/Button';
|
import { Button } from "../../../../_components/ui/Button";
|
||||||
import { redirect } from 'next/navigation';
|
import { redirect } from "next/navigation";
|
||||||
|
|
||||||
export const StationForm = ({ station }: { station?: Station }) => {
|
export const StationForm = ({ station }: { station?: Station }) => {
|
||||||
const form = useForm<z.infer<typeof StationOptionalDefaultsSchema>>({
|
const form = useForm<z.infer<typeof StationOptionalDefaultsSchema>>({
|
||||||
resolver: zodResolver(StationOptionalDefaultsSchema),
|
resolver: zodResolver(StationOptionalDefaultsSchema),
|
||||||
defaultValues: station,
|
defaultValues: station,
|
||||||
});
|
});
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [deleteLoading, setDeleteLoading] = useState(false);
|
const [deleteLoading, setDeleteLoading] = useState(false);
|
||||||
console.log(form.formState.errors);
|
return (
|
||||||
return (
|
<>
|
||||||
<>
|
<form
|
||||||
<form
|
onSubmit={form.handleSubmit(async (values) => {
|
||||||
onSubmit={form.handleSubmit(async (values) => {
|
setLoading(true);
|
||||||
setLoading(true);
|
const createdStation = await upsertStation(values, station?.id);
|
||||||
const createdStation = await upsertStation(values, station?.id);
|
setLoading(false);
|
||||||
setLoading(false);
|
if (!station) redirect(`/admin/station`);
|
||||||
if (!station) redirect(`/admin/station`);
|
})}
|
||||||
})}
|
className="grid grid-cols-6 gap-3"
|
||||||
className="grid grid-cols-6 gap-3"
|
>
|
||||||
>
|
<div className="card bg-base-200 shadow-xl col-span-2 max-xl:col-span-6">
|
||||||
<div className="card bg-base-200 shadow-xl col-span-2 max-xl:col-span-6">
|
<div className="card-body">
|
||||||
<div className="card-body">
|
<h2 className="card-title">
|
||||||
<h2 className="card-title">
|
<FileText className="w-5 h-5" /> Allgemeines
|
||||||
<FileText className="w-5 h-5" /> Allgemeines
|
</h2>
|
||||||
</h2>
|
<Input
|
||||||
<Input
|
form={form}
|
||||||
form={form}
|
label="BOS Rufname"
|
||||||
label="BOS Rufname"
|
name="bosCallsign"
|
||||||
name="bosCallsign"
|
className="input-sm"
|
||||||
className="input-sm"
|
/>
|
||||||
/>
|
<Input
|
||||||
<Input
|
form={form}
|
||||||
form={form}
|
label="BOS Rufname (kurz)"
|
||||||
label="BOS Rufname (kurz)"
|
name="bosCallsignShort"
|
||||||
name="bosCallsignShort"
|
className="input-sm"
|
||||||
className="input-sm"
|
/>
|
||||||
/>
|
<Input
|
||||||
<Input
|
form={form}
|
||||||
form={form}
|
label="Betreiber"
|
||||||
label="Betreiber"
|
name="operator"
|
||||||
name="operator"
|
className="input-sm"
|
||||||
className="input-sm"
|
/>
|
||||||
/>
|
<Input
|
||||||
<Input
|
form={form}
|
||||||
form={form}
|
label="ATC Rufname"
|
||||||
label="ATC Rufname"
|
name="atcCallsign"
|
||||||
name="atcCallsign"
|
className="input-sm"
|
||||||
className="input-sm"
|
/>
|
||||||
/>
|
<Input
|
||||||
<Input
|
form={form}
|
||||||
form={form}
|
label="FIR (Flight Information Region)"
|
||||||
label="FIR (Flight Information Region)"
|
name="fir"
|
||||||
name="fir"
|
className="input-sm"
|
||||||
className="input-sm"
|
/>
|
||||||
/>
|
<Input
|
||||||
<Input
|
form={form}
|
||||||
form={form}
|
label="Leitstelle Rufname"
|
||||||
label="Leitstelle Rufname"
|
name="bosRadioArea"
|
||||||
name="bosRadioArea"
|
className="input-sm"
|
||||||
className="input-sm"
|
/>
|
||||||
/>
|
|
||||||
|
|
||||||
<label className="form-control w-full">
|
<label className="form-control w-full">
|
||||||
<span className="label-text text-lg flex items-center gap-2">
|
<span className="label-text text-lg flex items-center gap-2">
|
||||||
BOS Nutzung
|
BOS Nutzung
|
||||||
</span>
|
</span>
|
||||||
<select
|
<select
|
||||||
className="input-sm select select-bordered select-sm"
|
className="input-sm select select-bordered select-sm"
|
||||||
{...form.register('bosUse')}
|
{...form.register("bosUse")}
|
||||||
>
|
>
|
||||||
{Object.keys(BosUse).map((use) => (
|
{Object.keys(BosUse).map((use) => (
|
||||||
<option key={use} value={use}>
|
<option key={use} value={use}>
|
||||||
{use}
|
{use}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="card bg-base-200 shadow-xl col-span-2 max-xl:col-span-6">
|
<div className="card bg-base-200 shadow-xl col-span-2 max-xl:col-span-6">
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<h2 className="card-title">
|
<h2 className="card-title">
|
||||||
<LocateIcon className="w-5 h-5" /> Standort + Ausrüstung
|
<LocateIcon className="w-5 h-5" /> Standort + Ausrüstung
|
||||||
</h2>
|
</h2>
|
||||||
<label className="form-control w-full">
|
<label className="form-control w-full">
|
||||||
<span className="label-text text-lg flex items-center gap-2">
|
<span className="label-text text-lg flex items-center gap-2">
|
||||||
Land
|
Land
|
||||||
</span>
|
</span>
|
||||||
<select
|
<select
|
||||||
className="input-sm select select-bordered select-sm"
|
className="input-sm select select-bordered select-sm"
|
||||||
{...form.register('country', {})}
|
{...form.register("country", {})}
|
||||||
>
|
>
|
||||||
{Object.keys(Country).map((use) => (
|
{Object.keys(Country).map((use) => (
|
||||||
<option key={use} value={use}>
|
<option key={use} value={use}>
|
||||||
{use}
|
{use}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
form={form}
|
form={form}
|
||||||
label="Bundesland"
|
label="Bundesland"
|
||||||
name="locationState"
|
name="locationState"
|
||||||
className="input-sm"
|
className="input-sm"
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
form={form}
|
form={form}
|
||||||
label="Bundesland (kurz)"
|
label="Bundesland (kurz)"
|
||||||
name="locationStateShort"
|
name="locationStateShort"
|
||||||
className="input-sm"
|
className="input-sm"
|
||||||
/>
|
/>
|
||||||
<span className="label-text text-lg flex items-center gap-2">
|
<span className="label-text text-lg flex items-center gap-2">
|
||||||
Ausgerüstet mit:
|
Ausgerüstet mit:
|
||||||
</span>
|
</span>
|
||||||
<div className="form-control">
|
<div className="form-control">
|
||||||
<label className="label cursor-pointer">
|
<label className="label cursor-pointer">
|
||||||
<span>Winde</span>
|
<span>Winde</span>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="toggle"
|
className="toggle"
|
||||||
{...form.register('hasWinch')}
|
{...form.register("hasWinch")}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label className="label cursor-pointer">
|
<label className="label cursor-pointer">
|
||||||
<span>Nachtsicht Gerät</span>
|
<span>Nachtsicht Gerät</span>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="toggle"
|
className="toggle"
|
||||||
{...form.register('hasNvg')}
|
{...form.register("hasNvg")}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label className="label cursor-pointer">
|
<label className="label cursor-pointer">
|
||||||
<span>24-Stunden Einsatzfähig</span>
|
<span>24-Stunden Einsatzfähig</span>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="toggle"
|
className="toggle"
|
||||||
{...form.register('is24h')}
|
{...form.register("is24h")}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label className="label cursor-pointer">
|
<label className="label cursor-pointer">
|
||||||
<span>Bergetau</span>
|
<span>Bergetau</span>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="toggle"
|
className="toggle"
|
||||||
{...form.register('hasRope')}
|
{...form.register("hasRope")}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
form={form}
|
form={form}
|
||||||
label="Breitengrad"
|
label="Breitengrad"
|
||||||
name="latitude"
|
name="latitude"
|
||||||
className="input-sm"
|
className="input-sm"
|
||||||
formOptions={{ valueAsNumber: true }}
|
formOptions={{ valueAsNumber: true }}
|
||||||
type="number"
|
type="number"
|
||||||
step="any"
|
step="any"
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
form={form}
|
form={form}
|
||||||
label="Längengrad"
|
label="Längengrad"
|
||||||
name="longitude"
|
name="longitude"
|
||||||
className="input-sm"
|
className="input-sm"
|
||||||
formOptions={{ valueAsNumber: true }}
|
formOptions={{ valueAsNumber: true }}
|
||||||
type="number"
|
type="number"
|
||||||
step="any"
|
step="any"
|
||||||
/>
|
/>
|
||||||
<label className="label cursor-pointer">
|
<label className="label cursor-pointer">
|
||||||
<span className="text-lg">Reichweiten ausblenden</span>
|
<span className="text-lg">Reichweiten ausblenden</span>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="toggle"
|
className="toggle"
|
||||||
{...form.register('hideRangeRings')}
|
{...form.register("hideRangeRings")}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="card bg-base-200 shadow-xl col-span-2 max-xl:col-span-6">
|
<div className="card bg-base-200 shadow-xl col-span-2 max-xl:col-span-6">
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<h2 className="card-title">
|
<h2 className="card-title">
|
||||||
<PlaneIcon className="w-5 h-5" /> Hubschrauber
|
<PlaneIcon className="w-5 h-5" /> Hubschrauber
|
||||||
</h2>
|
</h2>
|
||||||
<Input
|
<Input
|
||||||
form={form}
|
form={form}
|
||||||
label="Hubschrauber Typ"
|
label="Hubschrauber Typ"
|
||||||
name="aircraft"
|
name="aircraft"
|
||||||
className="input-sm"
|
className="input-sm"
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
form={form}
|
form={form}
|
||||||
formOptions={{ valueAsNumber: true }}
|
formOptions={{ valueAsNumber: true }}
|
||||||
type="number"
|
type="number"
|
||||||
label="Hubschrauber Geschwindigkeit"
|
label="Hubschrauber Geschwindigkeit"
|
||||||
className="input-sm"
|
className="input-sm"
|
||||||
name="aircraftSpeed"
|
name="aircraftSpeed"
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
form={form}
|
form={form}
|
||||||
label="Hubschrauber Registrierung"
|
label="Hubschrauber Registrierung"
|
||||||
name="aircraftRegistration"
|
name="aircraftRegistration"
|
||||||
className="input-sm"
|
className="input-sm"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="card bg-base-200 shadow-xl col-span-6">
|
<div className="card bg-base-200 shadow-xl col-span-6">
|
||||||
<div className="card-body ">
|
<div className="card-body ">
|
||||||
<div className="flex w-full gap-4">
|
<div className="flex w-full gap-4">
|
||||||
<Button
|
<Button
|
||||||
isLoading={loading}
|
isLoading={loading}
|
||||||
type="submit"
|
type="submit"
|
||||||
className="btn btn-primary flex-1"
|
className="btn btn-primary flex-1"
|
||||||
>
|
>
|
||||||
Speichern
|
Speichern
|
||||||
</Button>
|
</Button>
|
||||||
{station && (
|
{station && (
|
||||||
<Button
|
<Button
|
||||||
isLoading={deleteLoading}
|
isLoading={deleteLoading}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
setDeleteLoading(true);
|
setDeleteLoading(true);
|
||||||
await deleteStation(station.id);
|
await deleteStation(station.id);
|
||||||
redirect('/admin/station');
|
redirect("/admin/station");
|
||||||
}}
|
}}
|
||||||
className="btn btn-error"
|
className="btn btn-error"
|
||||||
>
|
>
|
||||||
Löschen
|
Löschen
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
import { PrismaClient } from '@repo/db';
|
import { PrismaClient } from "@repo/db";
|
||||||
|
|
||||||
export default async ({ params }: { params: Promise<{ id: string }> }) => {
|
export default async ({ params }: { params: Promise<{ id: string }> }) => {
|
||||||
const prisma = new PrismaClient();
|
const prisma = new PrismaClient();
|
||||||
const { id } = await params;
|
const { id } = await params;
|
||||||
|
|
||||||
const user = await prisma.user.findUnique({
|
const user = await prisma.user.findUnique({
|
||||||
where: {
|
where: {
|
||||||
id: id,
|
id: id,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
console.log(user);
|
console.log(user);
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1>
|
<h1>
|
||||||
{user?.firstname} {user?.lastname}
|
{user?.firstname} {user?.lastname}
|
||||||
</h1>
|
</h1>
|
||||||
<p>{user?.email}</p>
|
<p>{user?.email}</p>
|
||||||
{/* TODO: Hier Nutzerdaten bearbeiten */}
|
{/* TODO: Hier Nutzerdaten bearbeiten */}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,345 +10,344 @@ import { useSession } from "next-auth/react";
|
|||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { Button } from "../../../_components/ui/Button";
|
import { Button } from "../../../_components/ui/Button";
|
||||||
import {
|
import {
|
||||||
PersonIcon,
|
PersonIcon,
|
||||||
EnvelopeClosedIcon,
|
EnvelopeClosedIcon,
|
||||||
BookmarkIcon,
|
BookmarkIcon,
|
||||||
DiscordLogoIcon,
|
DiscordLogoIcon,
|
||||||
PaperPlaneIcon,
|
PaperPlaneIcon,
|
||||||
Link2Icon,
|
Link2Icon,
|
||||||
MixerHorizontalIcon,
|
MixerHorizontalIcon,
|
||||||
LockClosedIcon,
|
LockClosedIcon,
|
||||||
LockOpen2Icon,
|
LockOpen2Icon,
|
||||||
LockOpen1Icon,
|
LockOpen1Icon,
|
||||||
} from "@radix-ui/react-icons";
|
} from "@radix-ui/react-icons";
|
||||||
|
|
||||||
export const ProfileForm = ({ user }: { user: User }) => {
|
export const ProfileForm = ({ user }: { user: User }) => {
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
firstname: z.string().min(2).max(30),
|
firstname: z.string().min(2).max(30),
|
||||||
lastname: z.string().min(2).max(30),
|
lastname: z.string().min(2).max(30),
|
||||||
email: z.string().email({
|
email: z.string().email({
|
||||||
message: "Bitte gebe eine gültige E-Mail Adresse ein",
|
message: "Bitte gebe eine gültige E-Mail Adresse ein",
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
type IFormInput = z.infer<typeof schema>;
|
type IFormInput = z.infer<typeof schema>;
|
||||||
|
|
||||||
const form = useForm<IFormInput>({
|
const form = useForm<IFormInput>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
firstname: user.firstname,
|
firstname: user.firstname,
|
||||||
lastname: user.lastname,
|
lastname: user.lastname,
|
||||||
email: user.email,
|
email: user.email,
|
||||||
},
|
},
|
||||||
resolver: zodResolver(schema),
|
resolver: zodResolver(schema),
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
className="card-body"
|
className="card-body"
|
||||||
onSubmit={form.handleSubmit(async (values) => {
|
onSubmit={form.handleSubmit(async (values) => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
await updateUser(values);
|
await updateUser(values);
|
||||||
form.reset(values);
|
form.reset(values);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
toast.success("Deine Änderungen wurden gespeichert!", {
|
toast.success("Deine Änderungen wurden gespeichert!", {
|
||||||
style: {
|
style: {
|
||||||
background: "var(--color-base-100)",
|
background: "var(--color-base-100)",
|
||||||
color: "var(--color-base-content)",
|
color: "var(--color-base-content)",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<h2 className="card-title">
|
<h2 className="card-title">
|
||||||
<MixerHorizontalIcon className="w-5 h-5" /> Persönliche Informationen
|
<MixerHorizontalIcon className="w-5 h-5" /> Persönliche Informationen
|
||||||
</h2>
|
</h2>
|
||||||
<div className="text-left">
|
<div className="text-left">
|
||||||
<label className="floating-label w-full mb-5 mt-5">
|
<label className="floating-label w-full mb-5 mt-5">
|
||||||
<span className="text-lg flex items-center gap-2">
|
<span className="text-lg flex items-center gap-2">
|
||||||
<PersonIcon /> Vorname
|
<PersonIcon /> Vorname
|
||||||
</span>
|
</span>
|
||||||
<input
|
<input
|
||||||
{...form.register("firstname")}
|
{...form.register("firstname")}
|
||||||
type="text"
|
type="text"
|
||||||
className="input input-bordered w-full"
|
className="input input-bordered w-full"
|
||||||
defaultValue={user.firstname}
|
defaultValue={user.firstname}
|
||||||
placeholder="Vorname"
|
placeholder="Vorname"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
{form.formState.errors.firstname && (
|
{form.formState.errors.firstname && (
|
||||||
<p className="text-error">
|
<p className="text-error">
|
||||||
{form.formState.errors.firstname.message}
|
{form.formState.errors.firstname.message}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<label className="floating-label w-full mb-5">
|
<label className="floating-label w-full mb-5">
|
||||||
<span className="text-lg flex items-center gap-2">
|
<span className="text-lg flex items-center gap-2">
|
||||||
<PersonIcon /> Nachname
|
<PersonIcon /> Nachname
|
||||||
</span>
|
</span>
|
||||||
<input
|
<input
|
||||||
{...form.register("lastname")}
|
{...form.register("lastname")}
|
||||||
type="text"
|
type="text"
|
||||||
className="input input-bordered w-full"
|
className="input input-bordered w-full"
|
||||||
defaultValue={user.lastname}
|
defaultValue={user.lastname}
|
||||||
placeholder="Nachname"
|
placeholder="Nachname"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
{form.formState.errors.lastname && (
|
{form.formState.errors.lastname && (
|
||||||
<p className="text-error">
|
<p className="text-error">
|
||||||
{form.formState.errors.lastname?.message}
|
{form.formState.errors.lastname?.message}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<label className="floating-label w-full">
|
<label className="floating-label w-full">
|
||||||
<span className="text-lg flex items-center gap-2">
|
<span className="text-lg flex items-center gap-2">
|
||||||
<EnvelopeClosedIcon /> E-Mail
|
<EnvelopeClosedIcon /> E-Mail
|
||||||
</span>
|
</span>
|
||||||
<input
|
<input
|
||||||
{...form.register("email")}
|
{...form.register("email")}
|
||||||
type="text"
|
type="text"
|
||||||
className="input input-bordered w-full"
|
className="input input-bordered w-full"
|
||||||
defaultValue={user.email}
|
defaultValue={user.email}
|
||||||
placeholder="E-Mail"
|
placeholder="E-Mail"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
{form.formState.errors.email && (
|
{form.formState.errors.email && (
|
||||||
<p className="text-error">{form.formState.errors.email?.message}</p>
|
<p className="text-error">{form.formState.errors.email?.message}</p>
|
||||||
)}
|
)}
|
||||||
<div className="card-actions justify-center pt-6">
|
<div className="card-actions justify-center pt-6">
|
||||||
<Button
|
<Button
|
||||||
role="submit"
|
role="submit"
|
||||||
className="btn-sm btn-wide btn-outline btn-primary"
|
className="btn-sm btn-wide btn-outline btn-primary"
|
||||||
disabled={!form.formState.isDirty}
|
disabled={!form.formState.isDirty}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
>
|
>
|
||||||
<BookmarkIcon /> Speichern
|
<BookmarkIcon /> Speichern
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SocialForm = ({
|
export const SocialForm = ({
|
||||||
discordAccount,
|
discordAccount,
|
||||||
user,
|
user,
|
||||||
}: {
|
}: {
|
||||||
discordAccount?: DiscordAccount;
|
discordAccount?: DiscordAccount;
|
||||||
user: User;
|
user: User;
|
||||||
}) => {
|
}) => {
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [vatsimLoading, setVatsimLoading] = useState(false);
|
const [vatsimLoading, setVatsimLoading] = useState(false);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
vatsimCid: z.number().min(1000).max(9999999),
|
vatsimCid: z.number().min(1000).max(9999999),
|
||||||
});
|
});
|
||||||
|
|
||||||
type IFormInput = z.infer<typeof schema>;
|
type IFormInput = z.infer<typeof schema>;
|
||||||
|
|
||||||
const form = useForm<IFormInput>({
|
const form = useForm<IFormInput>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
vatsimCid: user?.vatsimCid || undefined,
|
vatsimCid: user?.vatsimCid || undefined,
|
||||||
},
|
},
|
||||||
resolver: zodResolver(schema),
|
resolver: zodResolver(schema),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!user) return null;
|
if (!user) return null;
|
||||||
console.log("Dirty", form.formState.isDirty);
|
return (
|
||||||
return (
|
<form
|
||||||
<form
|
className="card-body"
|
||||||
className="card-body"
|
onSubmit={form.handleSubmit(async (values) => {
|
||||||
onSubmit={form.handleSubmit(async (values) => {
|
form.handleSubmit(async () => {
|
||||||
form.handleSubmit(async () => {
|
setVatsimLoading(true);
|
||||||
setVatsimLoading(true);
|
});
|
||||||
});
|
await updateUser({
|
||||||
await updateUser({
|
vatsimCid: values.vatsimCid,
|
||||||
vatsimCid: values.vatsimCid,
|
});
|
||||||
});
|
setVatsimLoading(false);
|
||||||
setVatsimLoading(false);
|
form.reset(values);
|
||||||
form.reset(values);
|
toast.success("Deine Änderungen wurden gespeichert!", {
|
||||||
toast.success("Deine Änderungen wurden gespeichert!", {
|
style: {
|
||||||
style: {
|
background: "var(--color-base-100)",
|
||||||
background: "var(--color-base-100)",
|
color: "var(--color-base-content)",
|
||||||
color: "var(--color-base-content)",
|
},
|
||||||
},
|
});
|
||||||
});
|
})}
|
||||||
})}
|
>
|
||||||
>
|
<h2 className="card-title">
|
||||||
<h2 className="card-title">
|
<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">
|
||||||
<div className="label">
|
<span className="label-text text-lg flex items-center gap-2">
|
||||||
<span className="label-text text-lg flex items-center gap-2">
|
<DiscordLogoIcon /> Discord
|
||||||
<DiscordLogoIcon /> Discord
|
</span>
|
||||||
</span>
|
</div>
|
||||||
</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"
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
await unlinkDiscord(user.id);
|
await unlinkDiscord(user.id);
|
||||||
router.refresh();
|
router.refresh();
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DiscordLogoIcon className="w-5 h-5" />
|
<DiscordLogoIcon className="w-5 h-5" />
|
||||||
<span className="group-hover:hidden">
|
<span className="group-hover:hidden">
|
||||||
Verbunden mit {discordAccount.username}
|
Verbunden mit {discordAccount.username}
|
||||||
</span>
|
</span>
|
||||||
<span className="hidden group-hover:inline">
|
<span className="hidden group-hover:inline">
|
||||||
Verbindung trennen{isLoading && "..."}
|
Verbindung trennen{isLoading && "..."}
|
||||||
</span>
|
</span>
|
||||||
</Button>
|
</Button>
|
||||||
) : (
|
) : (
|
||||||
<a href={process.env.NEXT_PUBLIC_DISCORD_URL}>
|
<a href={process.env.NEXT_PUBLIC_DISCORD_URL}>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn btn-primary btn-block"
|
className="btn btn-primary btn-block"
|
||||||
onSubmit={() => false}
|
onSubmit={() => false}
|
||||||
>
|
>
|
||||||
<DiscordLogoIcon className="w-5 h-5" /> Mit Discord verbinden
|
<DiscordLogoIcon className="w-5 h-5" /> Mit Discord verbinden
|
||||||
</button>
|
</button>
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="content-center">
|
<div className="content-center">
|
||||||
<label className="floating-label w-full mt-5">
|
<label className="floating-label w-full mt-5">
|
||||||
<span className="text-lg flex items-center gap-2">
|
<span className="text-lg flex items-center gap-2">
|
||||||
<PaperPlaneIcon /> VATSIM-CID
|
<PaperPlaneIcon /> VATSIM-CID
|
||||||
</span>
|
</span>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
className="input input-bordered w-full"
|
className="input input-bordered w-full"
|
||||||
placeholder="1445241"
|
placeholder="1445241"
|
||||||
defaultValue={user.vatsimCid as number | undefined}
|
defaultValue={user.vatsimCid as number | undefined}
|
||||||
{...form.register("vatsimCid", {
|
{...form.register("vatsimCid", {
|
||||||
valueAsNumber: true,
|
valueAsNumber: true,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
{form.formState.errors.vatsimCid && (
|
{form.formState.errors.vatsimCid && (
|
||||||
<p className="text-error">
|
<p className="text-error">
|
||||||
{form.formState.errors.vatsimCid.message}
|
{form.formState.errors.vatsimCid.message}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="card-actions justify-center pt-6 mt-auto">
|
<div className="card-actions justify-center pt-6 mt-auto">
|
||||||
<Button
|
<Button
|
||||||
className="btn-sm btn-wide btn-outline btn-primary"
|
className="btn-sm btn-wide btn-outline btn-primary"
|
||||||
isLoading={vatsimLoading}
|
isLoading={vatsimLoading}
|
||||||
disabled={!form.formState.isDirty}
|
disabled={!form.formState.isDirty}
|
||||||
role="submit"
|
role="submit"
|
||||||
>
|
>
|
||||||
<BookmarkIcon /> Speichern
|
<BookmarkIcon /> Speichern
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PasswordForm = ({ user }: { user: User }) => {
|
export const PasswordForm = ({ user }: { user: User }) => {
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
password: z.string().min(2).max(30),
|
password: z.string().min(2).max(30),
|
||||||
newPassword: z.string().min(2).max(30),
|
newPassword: z.string().min(2).max(30),
|
||||||
newPasswordConfirm: z.string().min(2).max(30),
|
newPasswordConfirm: z.string().min(2).max(30),
|
||||||
});
|
});
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
type IFormInput = z.infer<typeof schema>;
|
type IFormInput = z.infer<typeof schema>;
|
||||||
|
|
||||||
const form = useForm<IFormInput>({
|
const form = useForm<IFormInput>({
|
||||||
defaultValues: {},
|
defaultValues: {},
|
||||||
resolver: zodResolver(schema),
|
resolver: zodResolver(schema),
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
className="card-body"
|
className="card-body"
|
||||||
onSubmit={form.handleSubmit(async (values) => {
|
onSubmit={form.handleSubmit(async (values) => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
const result = await changePassword(
|
const result = await changePassword(
|
||||||
values.password,
|
values.password,
|
||||||
values.newPassword
|
values.newPassword,
|
||||||
);
|
);
|
||||||
form.reset(values);
|
form.reset(values);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
form.setError("password", {
|
form.setError("password", {
|
||||||
type: "manual",
|
type: "manual",
|
||||||
message: result.error,
|
message: result.error,
|
||||||
});
|
});
|
||||||
} else if (result.success) {
|
} else if (result.success) {
|
||||||
toast.success("Dein Passwort wurde geändert!", {
|
toast.success("Dein Passwort wurde geändert!", {
|
||||||
style: {
|
style: {
|
||||||
background: "var(--color-base-100)",
|
background: "var(--color-base-100)",
|
||||||
color: "var(--color-base-content)",
|
color: "var(--color-base-content)",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<h2 className="card-title">
|
<h2 className="card-title">
|
||||||
<LockClosedIcon className="w-5 h-5" /> Password Ändern
|
<LockClosedIcon className="w-5 h-5" /> Password Ändern
|
||||||
</h2>
|
</h2>
|
||||||
<div className="">
|
<div className="">
|
||||||
<label className="floating-label w-full mt-5 mb-5">
|
<label className="floating-label w-full mt-5 mb-5">
|
||||||
<span className="text-lg flex items-center gap-2">
|
<span className="text-lg flex items-center gap-2">
|
||||||
<LockOpen2Icon /> Aktuelles Passwort
|
<LockOpen2Icon /> Aktuelles Passwort
|
||||||
</span>
|
</span>
|
||||||
<input
|
<input
|
||||||
{...form.register("password")}
|
{...form.register("password")}
|
||||||
type="text"
|
type="text"
|
||||||
className="input input-bordered w-full"
|
className="input input-bordered w-full"
|
||||||
defaultValue={""}
|
defaultValue={""}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
{form.formState.errors.password && (
|
{form.formState.errors.password && (
|
||||||
<p className="text-error">{form.formState.errors.password.message}</p>
|
<p className="text-error">{form.formState.errors.password.message}</p>
|
||||||
)}
|
)}
|
||||||
<label className="floating-label w-full mb-5">
|
<label className="floating-label w-full mb-5">
|
||||||
<span className="text-lg flex items-center gap-2">
|
<span className="text-lg flex items-center gap-2">
|
||||||
<LockOpen1Icon /> Neues Passwort
|
<LockOpen1Icon /> Neues Passwort
|
||||||
</span>
|
</span>
|
||||||
<input
|
<input
|
||||||
{...form.register("newPassword")}
|
{...form.register("newPassword")}
|
||||||
type="text"
|
type="text"
|
||||||
className="input input-bordered w-full"
|
className="input input-bordered w-full"
|
||||||
defaultValue={""}
|
defaultValue={""}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
{form.formState.errors.newPassword && (
|
{form.formState.errors.newPassword && (
|
||||||
<p className="text-error">
|
<p className="text-error">
|
||||||
{form.formState.errors.newPassword?.message}
|
{form.formState.errors.newPassword?.message}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<label className="floating-label w-full">
|
<label className="floating-label w-full">
|
||||||
<span className="text-lg flex items-center gap-2">
|
<span className="text-lg flex items-center gap-2">
|
||||||
<LockOpen1Icon /> Passwort wiederholen
|
<LockOpen1Icon /> Passwort wiederholen
|
||||||
</span>
|
</span>
|
||||||
<input
|
<input
|
||||||
{...form.register("newPasswordConfirm")}
|
{...form.register("newPasswordConfirm")}
|
||||||
type="text"
|
type="text"
|
||||||
className="input input-bordered w-full"
|
className="input input-bordered w-full"
|
||||||
defaultValue={""}
|
defaultValue={""}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
{form.formState.errors.newPasswordConfirm && (
|
{form.formState.errors.newPasswordConfirm && (
|
||||||
<p className="text-error">
|
<p className="text-error">
|
||||||
{form.formState.errors.newPasswordConfirm?.message}
|
{form.formState.errors.newPasswordConfirm?.message}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<div className="card-actions justify-center pt-6">
|
<div className="card-actions justify-center pt-6">
|
||||||
<Button
|
<Button
|
||||||
role="submit"
|
role="submit"
|
||||||
className="btn-sm btn-wide btn-outline btn-primary"
|
className="btn-sm btn-wide btn-outline btn-primary"
|
||||||
disabled={!form.formState.isDirty}
|
disabled={!form.formState.isDirty}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
>
|
>
|
||||||
<BookmarkIcon /> Speichern
|
<BookmarkIcon /> Speichern
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ export function PaginatedTable<TData>({
|
|||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
refresh: () => {
|
refresh: () => {
|
||||||
console.log("refresh");
|
|
||||||
RefreshTableData();
|
RefreshTableData();
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -1,67 +1,66 @@
|
|||||||
import {
|
import {
|
||||||
AuthOptions,
|
AuthOptions,
|
||||||
getServerSession as getNextAuthServerSession,
|
getServerSession as getNextAuthServerSession,
|
||||||
} from 'next-auth';
|
} from "next-auth";
|
||||||
import { PrismaAdapter } from '@next-auth/prisma-adapter';
|
import { PrismaAdapter } from "@next-auth/prisma-adapter";
|
||||||
import Credentials from 'next-auth/providers/credentials';
|
import Credentials from "next-auth/providers/credentials";
|
||||||
import { PrismaClient } from '@repo/db';
|
import { PrismaClient } from "@repo/db";
|
||||||
import bcrypt from 'bcryptjs';
|
import bcrypt from "bcryptjs";
|
||||||
const prisma = new PrismaClient();
|
const prisma = new PrismaClient();
|
||||||
|
|
||||||
export const options: AuthOptions = {
|
export const options: AuthOptions = {
|
||||||
providers: [
|
providers: [
|
||||||
Credentials({
|
Credentials({
|
||||||
credentials: {
|
credentials: {
|
||||||
email: { label: 'Email', type: 'email', placeholder: 'E-Mail' },
|
email: { label: "Email", type: "email", placeholder: "E-Mail" },
|
||||||
password: { label: 'Password', type: 'password' },
|
password: { label: "Password", type: "password" },
|
||||||
},
|
},
|
||||||
async authorize(credentials, req) {
|
async authorize(credentials, req) {
|
||||||
try {
|
try {
|
||||||
if (!credentials) throw new Error('No credentials provided');
|
if (!credentials) throw new Error("No credentials provided");
|
||||||
const user = await prisma.user.findFirstOrThrow({
|
const user = await prisma.user.findFirstOrThrow({
|
||||||
where: { email: credentials.email },
|
where: { email: credentials.email },
|
||||||
});
|
});
|
||||||
if (bcrypt.compareSync(credentials.password, user.password)) {
|
if (bcrypt.compareSync(credentials.password, user.password)) {
|
||||||
console.log('User found and password correct', user);
|
return user;
|
||||||
return user;
|
}
|
||||||
}
|
return null;
|
||||||
return null;
|
} catch (error) {
|
||||||
} catch (error) {
|
return null;
|
||||||
return null;
|
}
|
||||||
}
|
},
|
||||||
},
|
}),
|
||||||
}),
|
],
|
||||||
],
|
secret: process.env.NEXTAUTH_SECRET,
|
||||||
secret: process.env.NEXTAUTH_SECRET,
|
session: {
|
||||||
session: {
|
strategy: "jwt",
|
||||||
strategy: 'jwt',
|
maxAge: 30 * 24 * 60 * 60,
|
||||||
maxAge: 30 * 24 * 60 * 60,
|
},
|
||||||
},
|
|
||||||
|
|
||||||
adapter: PrismaAdapter(prisma as any),
|
adapter: PrismaAdapter(prisma as any),
|
||||||
callbacks: {
|
callbacks: {
|
||||||
jwt: async ({ token, user }) => {
|
jwt: async ({ token, user }) => {
|
||||||
if (user && 'firstname' in user) {
|
if (user && "firstname" in user) {
|
||||||
return {
|
return {
|
||||||
...token,
|
...token,
|
||||||
...user,
|
...user,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return token;
|
return token;
|
||||||
},
|
},
|
||||||
session: async ({ session, user, token }) => {
|
session: async ({ session, user, token }) => {
|
||||||
return {
|
return {
|
||||||
...session,
|
...session,
|
||||||
user: token,
|
user: token,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pages: {
|
pages: {
|
||||||
signIn: '/login',
|
signIn: "/login",
|
||||||
signOut: '/logout',
|
signOut: "/logout",
|
||||||
error: '/authError',
|
error: "/authError",
|
||||||
newUser: '/register',
|
newUser: "/register",
|
||||||
},
|
},
|
||||||
} satisfies AuthOptions;
|
} satisfies AuthOptions;
|
||||||
|
|
||||||
export const getServerSession = async () => getNextAuthServerSession(options);
|
export const getServerSession = async () => getNextAuthServerSession(options);
|
||||||
|
|||||||
@@ -5,15 +5,11 @@ import { services } from "../../../(auth)/oauth/page";
|
|||||||
|
|
||||||
export const POST = async (req: NextRequest) => {
|
export const POST = async (req: NextRequest) => {
|
||||||
const form = new URLSearchParams(await req.text());
|
const form = new URLSearchParams(await req.text());
|
||||||
console.log("POST body:");
|
|
||||||
const client = new PrismaClient();
|
const client = new PrismaClient();
|
||||||
const accessToken = form.get("token") || form.get("code");
|
const accessToken = form.get("token") || form.get("code");
|
||||||
const clientId = form.get("client_id");
|
const clientId = form.get("client_id");
|
||||||
const clientSecret = form.get("client_secret");
|
const clientSecret = form.get("client_secret");
|
||||||
|
|
||||||
console.log("Access token:", accessToken);
|
|
||||||
console.log("Client ID:", clientId);
|
|
||||||
console.log("Secret:", clientSecret);
|
|
||||||
const service = services.find((s) => s.id === clientId);
|
const service = services.find((s) => s.id === clientId);
|
||||||
|
|
||||||
if (!accessToken)
|
if (!accessToken)
|
||||||
|
|||||||
Reference in New Issue
Block a user