From 957df84c7cca8010ee86e6eda7805a08a2c88656 Mon Sep 17 00:00:00 2001 From: Elliot Saha Date: Thu, 28 Mar 2024 12:15:41 -0700 Subject: [PATCH] feat(profile/): restructured and redesigned profile/public and profile/security created a better user flow for account modification --- .../(protected)/profile/public/page.tsx | 25 ++- .../(protected)/profile/security/page.tsx | 196 +++++++++++------- src/app/api/auth/delete-account/route.ts | 13 +- src/app/api/auth/password-reset/route.ts | 11 +- .../api/auth/signup/google/callback/route.ts | 2 +- src/app/api/auth/signup/route.ts | 2 +- 6 files changed, 167 insertions(+), 82 deletions(-) diff --git a/src/app/(pages)/(protected)/profile/public/page.tsx b/src/app/(pages)/(protected)/profile/public/page.tsx index f538927..ae066a4 100644 --- a/src/app/(pages)/(protected)/profile/public/page.tsx +++ b/src/app/(pages)/(protected)/profile/public/page.tsx @@ -1,5 +1,8 @@ "use client"; import { + Tabs, + TabList, + Tab, SimpleGrid, Input, InputGroup, @@ -41,7 +44,8 @@ import { Controller, UseFormSetValue, useForm } from "react-hook-form"; import { AtSignIcon } from "@chakra-ui/icons"; import { FormatOptionLabelMeta, Select } from "chakra-react-select"; import { CloseIcon } from "@chakra-ui/icons"; -import { useSearchParams } from "next/navigation"; +import { useSearchParams, useRouter } from "next/navigation"; +import { InfoIcon, LockIcon } from "@chakra-ui/icons"; const skillOptions = [ { value: 1, label: "I've never played before" }, @@ -77,6 +81,7 @@ const initialFormUpdate = async (setValue: UseFormSetValue
) => { const AddInfo = () => { const statusToast = useToast(); const searchParams = useSearchParams(); + const router = useRouter(); const setup = searchParams.get("setup"); const { @@ -213,6 +218,21 @@ const AddInfo = () => { + + + + + Profile + + router.push(`/profile/security`)} + color="gray.600" + > + + Security + + + { ) : ( - + )} @@ -383,6 +403,7 @@ const AddInfo = () => { isSearchable={false} isDisabled={isSubmitting} value={skillOptions.find((e) => e.value === value)} + size="lg" /> )} diff --git a/src/app/(pages)/(protected)/profile/security/page.tsx b/src/app/(pages)/(protected)/profile/security/page.tsx index d2a5939..795028d 100644 --- a/src/app/(pages)/(protected)/profile/security/page.tsx +++ b/src/app/(pages)/(protected)/profile/security/page.tsx @@ -1,6 +1,10 @@ -'use client'; - +"use client"; import { + Box, + Img, + Tabs, + TabList, + Tab, Button, Container, Flex, @@ -26,16 +30,20 @@ import { AlertDialogFooter, AlertDialogBody, AlertDialogHeader, -} from '@chakra-ui/react'; -import {getClientSession} from '@utils/getClientSession'; -import axios from 'axios'; -import {DEFAULT_SERVER_ERR} from '@constants/error-messages'; -import {useEffect, useState} from 'react'; -import z from 'zod'; -import {ZOD_ERR} from '@constants/error-messages'; -import {useForm} from 'react-hook-form'; -import {zodResolver} from '@hookform/resolvers/zod'; -import React from 'react'; + Skeleton, + SkeletonText, +} from "@chakra-ui/react"; +import { getClientSession } from "@utils/getClientSession"; +import axios from "axios"; +import { DEFAULT_SERVER_ERR } from "@constants/error-messages"; +import { useEffect, useState } from "react"; +import z from "zod"; +import { ZOD_ERR } from "@constants/error-messages"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import React from "react"; +import { useRouter } from "next/navigation"; +import { InfoIcon, LockIcon } from "@chakra-ui/icons"; const schema = z.object({ email_address: z.string().email(ZOD_ERR.INVALID_EMAIL), @@ -45,7 +53,9 @@ const schema = z.object({ type Form = z.infer; const Security = () => { - const [isPassword, setIsPassword] = useState(false); + const router = useRouter(); + + const [isPassword, setIsPassword] = useState(null); const [isPasswordSubmitting, setIsPasswordSubmitting] = useState(false); @@ -60,8 +70,10 @@ const Security = () => { useEffect(() => { const getSessionProvider = async () => { const session = await getSession(); - if (session.user.provider === 'password') { + if (session?.user?.provider === "password") { setIsPassword(true); + } else { + setIsPassword(false); } }; getSessionProvider(); @@ -70,8 +82,8 @@ const Security = () => { const { handleSubmit, register, - formState: {errors, isSubmitting}, - } = useForm({resolver: zodResolver(schema)}); + formState: { errors, isSubmitting }, + } = useForm({ resolver: zodResolver(schema) }); const statusToast = useToast(); @@ -88,13 +100,13 @@ const Security = () => { `${process.env.NEXT_PUBLIC_HOSTNAME}/api/auth/password-reset`, { email_address: session.user.email_address, - } + }, ); if (res.data) { statusToast({ title: res.data.message, - status: 'success', + status: "success", }); } setIsPasswordSubmitting(false); @@ -102,7 +114,7 @@ const Security = () => { if (axios.isAxiosError(e)) { statusToast({ title: e?.response?.data?.message || DEFAULT_SERVER_ERR, - status: 'error', + status: "error", }); } setIsPasswordSubmitting(false); @@ -113,98 +125,117 @@ const Security = () => { try { setIsDeletingAccount(true); const res = await axios.get( - `${process.env.NEXT_PUBLIC_HOSTNAME}/api/auth/delete-account` + `${process.env.NEXT_PUBLIC_HOSTNAME}/api/auth/delete-account`, ); if (res.data) { statusToast({ title: res.data.message, - status: 'success', + status: "success", }); } setIsDeletingAccount(false); - window.location.href = '/'; + window.location.href = "/"; } catch (e) { if (axios.isAxiosError(e)) { statusToast({ title: e?.response?.data?.message || DEFAULT_SERVER_ERR, - status: 'error', + status: "error", }); } setIsDeletingAccount(false); } }; - const onSubmit = async ({email_address, password}: Form) => { + const onSubmit = async ({ email_address, password }: Form) => { try { const res = await axios.post( `${process.env.NEXT_PUBLIC_HOSTNAME}/api/auth/email-reset`, { email_address, password, - } + }, ); if (res.data) { statusToast({ title: res.data.message, - status: 'success', + status: "success", }); } } catch (e) { if (axios.isAxiosError(e)) { statusToast({ title: e?.response?.data?.message || DEFAULT_SERVER_ERR, - status: 'error', + status: "error", }); } } }; return ( - + - + + + router.push(`/profile/public`)} + > + + Profile + + + + Security + + + + Secure your account - + Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum sint consectetur cupidatat. - + {isPassword && ( - - )} - {isPassword && ( - + <> + + + )} { type="password" placeholder="Your password" disabled={isSubmitting} - {...register('password')} + {...register("password")} /> {errors?.password?.message} @@ -239,7 +270,7 @@ const Security = () => { type="email" placeholder="Your new email" disabled={isSubmitting} - {...register('email_address')} + {...register("email_address")} /> {errors?.email_address?.message} @@ -248,34 +279,44 @@ const Security = () => { + - - + {isPassword === false && ( + + Google + Your account is managed by Google. + + )} - { > - + Delete Account - Are you sure? Your account cannot be recovered afterwards. + + Are you sure? Your account cannot be recovered afterwards. + @@ -300,7 +343,8 @@ const Security = () => {