completed user admin page

This commit is contained in:
PxlLoewe
2025-03-15 11:09:55 -07:00
parent abf3475c7c
commit 37d02ea0bc
23 changed files with 567 additions and 106 deletions

View File

@@ -62,7 +62,6 @@ export default async () => {
});
const filteredEvents = events.filter((event) => {
console.log;
if (eventCompleted(event, event.participants[0])) return false;
if (
event.type === "OBLIGATED_COURSE" &&

View File

@@ -61,9 +61,8 @@ export const AppointmentModal = ({
</h3>
<form
onSubmit={appointmentForm.handleSubmit(async (values) => {
console.log(values);
if (!event) return;
const createdAppointment = await upsertAppointment(values);
await upsertAppointment(values);
ref.current?.close();
appointmentsTableRef.current?.refresh();
})}

View File

@@ -1,10 +1,10 @@
"use client";
import { zodResolver } from "@hookform/resolvers/zod";
import { BADGES, User } from "@repo/db";
import { BADGES, PERMISSION, User } from "@repo/db";
import { useState } from "react";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { updateUser } from "../../../../settings/actions";
import { editUser, resetPassword } from "../../action";
import { toast } from "react-hot-toast";
import {
PersonIcon,
@@ -18,36 +18,25 @@ import {
} from "@radix-ui/react-icons";
import { Button } from "../../../../../_components/ui/Button";
import { Select } from "../../../../../_components/ui/Select";
import { UserSchema } from "@repo/db/zod";
import { useRouter } from "next/navigation";
interface ProfileFormProps {
user: User | null;
user: User;
}
export const ProfileForm: React.FC<ProfileFormProps> = ({ user }) => {
const schema = z.object({
firstname: z.string().min(2).max(30),
lastname: z.string().min(2).max(30),
email: z.string().email({
message: "Bitte gebe eine gültige E-Mail Adresse ein",
}),
});
const [isLoading, setIsLoading] = useState(false);
type IFormInput = z.infer<typeof schema>;
const form = useForm<IFormInput>({
defaultValues: {
firstname: user?.firstname,
lastname: user?.lastname,
email: user?.email,
},
resolver: zodResolver(schema),
const form = useForm<User>({
defaultValues: user,
resolver: zodResolver(UserSchema),
});
return (
<form
className="card-body"
onSubmit={form.handleSubmit(async (values) => {
setIsLoading(true);
await updateUser(values);
await editUser(values.id, values);
form.reset(values);
setIsLoading(false);
toast.success("Deine Änderungen wurden gespeichert!", {
@@ -114,13 +103,23 @@ export const ProfileForm: React.FC<ProfileFormProps> = ({ user }) => {
<Select
isMulti
form={form}
name="finishedBadges"
name="badges"
label="Badges"
options={Object.entries(BADGES).map(([key, value]) => ({
label: value,
value: key,
}))}
/>
<Select
isMulti
form={form}
name="permissions"
label="Permissions"
options={Object.entries(PERMISSION).map(([key, value]) => ({
label: value,
value: key,
}))}
/>
<div className="card-actions justify-center pt-6">
<Button
role="submit"
@@ -137,6 +136,8 @@ export const ProfileForm: React.FC<ProfileFormProps> = ({ user }) => {
};
export const AdminForm: React.FC<ProfileFormProps> = ({ user }) => {
const router = useRouter();
return (
<div className="card-body">
<h2 className="card-title">
@@ -145,23 +146,59 @@ export const AdminForm: React.FC<ProfileFormProps> = ({ user }) => {
<div className="text-left">
<div className="card-actions pt-6">
<Button
role="submit"
onClick={async () => {
const { password } = await resetPassword(user.id);
toast.success(
`Neues Passwort
${password}, es wurde dem Nutzer an die E-Mail gesendet!`,
{
style: {
background: "var(--color-base-100)",
color: "var(--color-base-content)",
},
},
);
}}
className="btn-sm btn-wide btn-outline btn-success"
>
<LockOpen1Icon /> Passwort zurücksetzen
</Button>
<Button
role="submit"
className="btn-sm btn-wide btn-outline btn-error"
>
<HobbyKnifeIcon /> User Sperren
</Button>
<Button
role="submit"
className="btn-sm btn-wide btn-outline btn-warning"
>
<HeartIcon /> User Entperren
</Button>
{!user.isBanned && (
<Button
onClick={async () => {
await editUser(user.id, { isBanned: true });
toast.success("Nutzer wurde gesperrt!", {
style: {
background: "var(--color-base-100)",
color: "var(--color-base-content)",
},
});
router.refresh();
}}
role="submit"
className="btn-sm btn-wide btn-outline btn-error"
>
<HobbyKnifeIcon /> User Sperren
</Button>
)}
{user.isBanned && (
<Button
onClick={async () => {
await editUser(user.id, { isBanned: false });
toast.success("Nutzer wurde entsperrt!", {
style: {
background: "var(--color-base-100)",
color: "var(--color-base-content)",
},
});
router.refresh();
}}
role="submit"
className="btn-sm btn-wide btn-outline btn-warning"
>
<HobbyKnifeIcon /> User Entperren
</Button>
)}
</div>
</div>
</div>

View File

@@ -1,19 +1,18 @@
import { PersonIcon } from "@radix-ui/react-icons";
import { PrismaClient, User } from "@repo/db";
import { AdminForm, ProfileForm } from "./_components/forms";
import { Error } from "../../../../_components/Error";
export default async ({ params }: { params: { id: string } }) => {
const prisma = new PrismaClient();
const { id } = params;
const { id } = await params;
const user: User | null = await prisma.user.findUnique({
where: {
id: id,
},
});
console.log(user);
if (!user) return <Error statusCode={404} title="User not found" />;
return (
<div className="grid grid-cols-6 gap-4">
<div className="col-span-full">

View File

@@ -0,0 +1,35 @@
"use server";
import { PrismaClient } from "@prisma/client";
import { prisma, Prisma } from "@repo/db";
import bcrypt from "bcryptjs";
import { sendMailByTemplate } from "../../../../helper/mail";
export const editUser = async (id: string, data: Prisma.UserUpdateInput) => {
return await prisma.user.update({
where: {
id: id,
},
data,
});
};
export const resetPassword = async (id: string) => {
const password = Math.random().toString(36).slice(-8);
const hashedPassword = await bcrypt.hash(password, 15);
const user = await prisma.user.update({
where: {
id: id,
},
data: {
password: hashedPassword,
},
});
await sendMailByTemplate(user.email, "password-change", {
user: user,
password: password,
});
return { password };
};

View File

@@ -103,13 +103,6 @@ const ModalBtn = ({
? (selectedDate as any)?.Participants?.length + 1
: ownIndexInParticipantList + 1;
console.log({
selectedDate,
ownPlaceInParticipantList,
ownIndexInParticipantList,
maxParticipants: event.maxParticipants,
});
return (
<>
<button