From 8928455c3a424b044992ec50092a0a25f8b62ab4 Mon Sep 17 00:00:00 2001 From: PxlLoewe <72106766+PxlLoewe@users.noreply.github.com> Date: Mon, 17 Feb 2025 10:39:19 +0100 Subject: [PATCH] completed pw change, TESTNG REQUIRED --- .../app/(app)/settings/_components/forms.tsx | 89 +++++++++++-------- apps/hub/app/(app)/settings/actions.ts | 36 ++++++-- 2 files changed, 81 insertions(+), 44 deletions(-) diff --git a/apps/hub/app/(app)/settings/_components/forms.tsx b/apps/hub/app/(app)/settings/_components/forms.tsx index 4d5fe7ec..2f1fd89b 100644 --- a/apps/hub/app/(app)/settings/_components/forms.tsx +++ b/apps/hub/app/(app)/settings/_components/forms.tsx @@ -1,14 +1,14 @@ -"use client"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { DiscordAccount, User } from "@repo/db"; -import { useState } from "react"; -import { useForm } from "react-hook-form"; -import { z } from "zod"; -import { unlinkDiscord, updateUser, changePassword } from "../actions"; -import { Toaster, toast } from "react-hot-toast"; -import { useSession } from "next-auth/react"; -import { useRouter } from "next/navigation"; -import { Button } from "../../../_components/ui/Button"; +'use client'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { DiscordAccount, User } from '@repo/db'; +import { useState } from 'react'; +import { useForm } from 'react-hook-form'; +import { z } from 'zod'; +import { unlinkDiscord, updateUser, changePassword } from '../actions'; +import { Toaster, toast } from 'react-hot-toast'; +import { useSession } from 'next-auth/react'; +import { useRouter } from 'next/navigation'; +import { Button } from '../../../_components/ui/Button'; import { PersonIcon, EnvelopeClosedIcon, @@ -20,14 +20,14 @@ import { LockClosedIcon, LockOpen2Icon, LockOpen1Icon, -} from "@radix-ui/react-icons"; +} from '@radix-ui/react-icons'; export const ProfileForm = ({ user }: { user: 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", + message: 'Bitte gebe eine gültige E-Mail Adresse ein', }), }); const [isLoading, setIsLoading] = useState(false); @@ -49,12 +49,12 @@ export const ProfileForm = ({ user }: { user: User }) => { await updateUser(values); form.reset(values); setIsLoading(false); - toast.success("Deine Änderungen wurden gespeichert!", { + toast.success('Deine Änderungen wurden gespeichert!', { style: { background: - "var(--fallback-b1, oklch(var(--b1) / var(--tw-bg-opacity, 1)))", + 'var(--fallback-b1, oklch(var(--b1) / var(--tw-bg-opacity, 1)))', color: - "var(--fallback-nc, oklch(var(--nc) / var(--tw-text-opacity, 1)))", + 'var(--fallback-nc, oklch(var(--nc) / var(--tw-text-opacity, 1)))', }, }); })} @@ -70,7 +70,7 @@ export const ProfileForm = ({ user }: { user: User }) => { { { - Verbindung trennen{isLoading && "..."} + Verbindung trennen{isLoading && '...'} ) : ( @@ -231,7 +231,7 @@ export const SocialForm = ({ className="input input-bordered w-full" placeholder="1445241" defaultValue={user.vatsimCid as number | undefined} - {...form.register("vatsimCid", { + {...form.register('vatsimCid', { valueAsNumber: true, })} /> @@ -269,22 +269,33 @@ export const PasswordForm = ({ user }: { user: User }) => { defaultValues: {}, resolver: zodResolver(schema), }); + console.log(form.formState.errors); return (
{ setIsLoading(true); - await changePassword(values); + const result = await changePassword( + values.password, + values.newPassword + ); form.reset(values); setIsLoading(false); - toast.success("Dein Passwort wurde geändert!", { - style: { - background: - "var(--fallback-b1, oklch(var(--b1) / var(--tw-bg-opacity, 1)))", - color: - "var(--fallback-nc, oklch(var(--nc) / var(--tw-text-opacity, 1)))", - }, - }); + if (result.error) { + form.setError('password', { + type: 'manual', + message: result.error, + }); + } else if (result.success) { + toast.success('Dein Passwort wurde geändert!', { + style: { + background: + 'var(--fallback-b1, oklch(var(--b1) / var(--tw-bg-opacity, 1)))', + color: + 'var(--fallback-nc, oklch(var(--nc) / var(--tw-text-opacity, 1)))', + }, + }); + } })} >

@@ -298,10 +309,10 @@ export const PasswordForm = ({ user }: { user: User }) => { {form.formState.errors.password && ( @@ -314,10 +325,10 @@ export const PasswordForm = ({ user }: { user: User }) => { {form.formState.errors.newPassword && ( @@ -332,10 +343,10 @@ export const PasswordForm = ({ user }: { user: User }) => { {form.formState.errors.newPasswordConfirm && ( diff --git a/apps/hub/app/(app)/settings/actions.ts b/apps/hub/app/(app)/settings/actions.ts index 3bfb3fc7..a5d50ed4 100644 --- a/apps/hub/app/(app)/settings/actions.ts +++ b/apps/hub/app/(app)/settings/actions.ts @@ -1,6 +1,7 @@ -"use server"; -import { Prisma, PrismaClient } from "@repo/db"; -import { getServerSession } from "../../api/auth/[...nextauth]/auth"; +'use server'; +import { prisma, Prisma, PrismaClient } from '@repo/db'; +import { getServerSession } from '../../api/auth/[...nextauth]/auth'; +import bcrypt from 'bcryptjs'; export const unlinkDiscord = async (userId: string) => { const client = new PrismaClient(); @@ -25,6 +26,31 @@ export const updateUser = async (changes: Prisma.UserUpdateInput) => { }); }; -export const changePassword = async (changes: Prisma.UserUpdateInput) => { - // TODO: Add password change logic +export const changePassword = async ( + oldPassword: string, + newPassword: string +) => { + const session = await getServerSession(); + if (!session) + return { + error: 'User not found', + }; + + if (!(await bcrypt.compare(oldPassword, session.user.password))) + return { + error: 'Old password is incorrect', + }; + + const hashedPassword = await bcrypt.hash(newPassword, 15); + await prisma.user.update({ + data: { + password: hashedPassword, + }, + where: { + id: session.user.id, + }, + }); + return { + success: true, + }; };