Skip to content

Commit 5fdc331

Browse files
committed
feat: update sign up page
1 parent 542b089 commit 5fdc331

File tree

9 files changed

+149
-57
lines changed

9 files changed

+149
-57
lines changed

apps/web/@/actions/auth/index.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
"use server"
22

3+
import { redirect } from "next/navigation"
4+
35
import { signIn, signOut } from "configs/auth"
6+
import { Prisma } from "database"
7+
import { createUser } from "database/src/users/queries"
8+
import { z } from "zod"
49

510
export const signInWithCredentials = async (email: string, password: string) => {
611
await signIn("credentials", {
@@ -18,3 +23,38 @@ export const onSignOut = async () => {
1823
redirectTo: "/",
1924
})
2025
}
26+
27+
// SIGN UP
28+
export const signUpSchema = z.object({
29+
email: z.string().email("Email is invalid"),
30+
password: z.string().min(8),
31+
confirmPassword: z.string().min(8),
32+
})
33+
34+
export type SignUpDataInput = z.infer<typeof signUpSchema>
35+
36+
export type SignUpDataOutput = z.inferFlattenedErrors<typeof signUpSchema>
37+
38+
export const signUp = async (
39+
data: Pick<Prisma.UserCreateInput, "email" | "password">
40+
): Promise<SignUpDataOutput> => {
41+
try {
42+
await createUser({ data })
43+
44+
redirect("/login")
45+
} catch (error) {
46+
if (error.code === "P2002") {
47+
return {
48+
formErrors: [],
49+
fieldErrors: {
50+
email: ["Email already exists"], // TODO: localize error message
51+
},
52+
}
53+
}
54+
55+
return {
56+
formErrors: [error?.message],
57+
fieldErrors: {},
58+
}
59+
}
60+
}

apps/web/@/molecules/auth/sign-up/index.tsx

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33
import Link from "next/link"
44

55
import { zodResolver } from "@hookform/resolvers/zod"
6+
import { Prisma } from "database"
67
import { GithubIcon } from "lucide-react"
78
import { useTranslations } from "next-intl"
9+
import { useFormState } from "react-dom"
810
import { useForm } from "react-hook-form"
11+
import { toast } from "react-toastify"
912
import {
1013
Button,
1114
Card,
@@ -23,29 +26,50 @@ import {
2326
} from "ui"
2427
import { z } from "zod"
2528

29+
import { signUp, SignUpDataInput, signUpSchema } from "@/actions/auth"
30+
2631
import AuthForm from "../auth-form"
2732

2833
export default function SignUp() {
2934
const t = useTranslations("auth")
3035

31-
const form = useForm({
32-
resolver: zodResolver(
33-
z.object({
34-
email: z.string().email(t("email.invalid")),
35-
password: z.string().min(8, t("password.min")),
36-
confirmPassword: z.string().min(8, t("password.min")),
37-
})
38-
),
36+
const form = useForm<SignUpDataInput>({
37+
resolver: zodResolver(signUpSchema),
38+
mode: "onTouched",
3939
})
4040

4141
const {
4242
formState: { errors },
4343
register,
4444
handleSubmit,
45+
setError,
4546
} = form
4647

47-
const onSubmit = (data: any) => {
48-
// TODO: Implement sign up
48+
// TODO:
49+
// const [state, formAction] = useActionState<Pick<Prisma.UserCreateInput, "email" | "password">>(
50+
// signUp,
51+
// null
52+
// )
53+
54+
console.log(">>>", errors)
55+
56+
const formAction = async ({ confirmPassword, ...data }: SignUpDataInput) => {
57+
const error = await signUp(data)
58+
59+
console.log("formAction>>error", error)
60+
61+
if (error.formErrors) {
62+
toast.error(error.formErrors?.at(0))
63+
}
64+
65+
if (error.fieldErrors) {
66+
Object?.entries(error.fieldErrors)?.forEach(([field, message]) => {
67+
setError(field, {
68+
type: "manual",
69+
message,
70+
})
71+
})
72+
}
4973
}
5074

5175
return (
@@ -55,7 +79,7 @@ export default function SignUp() {
5579
description="Register to your account to continue."
5680
>
5781
<Form {...form}>
58-
<form onSubmit={handleSubmit(onSubmit)}>
82+
<form onSubmit={handleSubmit(formAction)}>
5983
<div className="grid w-full gap-4">
6084
<FormField
6185
name="email"
@@ -65,7 +89,7 @@ export default function SignUp() {
6589
<FormControl>
6690
<Input
6791
id="email"
68-
placeholder={t("email")}
92+
placeholder={t("email_label")}
6993
type="email"
7094
autoCapitalize="none"
7195
autoComplete="email"

apps/web/app/[lang]/(public-fullwidth)/author/[authorId]/page.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ import UserProfile from "@/molecules/follower/user-profile"
44
import PostList from "@/molecules/posts/post-list"
55

66
export const generateMetadata = async ({ params }) => {
7-
const { data: author, error } = await getUser({ userId: params?.authorId })
7+
const { data: author, error } = await getUser({
8+
where: {
9+
id: params?.authorId,
10+
},
11+
})
812

913
return {
1014
title: author?.name,

apps/web/configs/auth.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { PrismaAdapter } from "@auth/prisma-adapter"
2-
import prisma from "database"
2+
import prisma, { getUser } from "database"
33
import NextAuth from "next-auth"
44
import Credentials from "next-auth/providers/credentials"
55
import GithubProvider from "next-auth/providers/github"
@@ -23,7 +23,7 @@ export const {
2323
},
2424
authorize: async (credentials: Record<string, string>) => {
2525
try {
26-
const user = await prisma.user.findUnique({
26+
const { data: user } = await getUser({
2727
where: {
2828
email: credentials.email,
2929
password: credentials.password,

packages/database/src/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
import { createTag, getTag, getTags, getTopTags } from "./tags/queries"
2424
import type { TTagItem, TTagListItem } from "./tags/selects"
2525
import { tagListSelect } from "./tags/selects"
26-
import { getUser } from "./users/queries"
26+
import { createUser, getUser, updateUser } from "./users/queries"
2727
import { TUserDetail } from "./users/selects"
2828

2929
export * from "@prisma/client"
@@ -49,6 +49,8 @@ export {
4949

5050
// Users
5151
getUser,
52+
createUser,
53+
updateUser,
5254

5355
// Images
5456
getImages,

packages/database/src/shared/type.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export interface IActionReturn<T> {
2222
export interface IGetListResponse<T> {
2323
data: T[]
2424
total: number
25-
page: number
26-
totalPages: number
27-
limit: number
25+
page?: number
26+
totalPages?: number
27+
limit?: number
2828
}

packages/database/src/tags/queries.ts

Lines changed: 14 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,45 +8,30 @@ import prisma from "../prisma"
88
import { DEFAULT_LIMIT, DEFAULT_PAGE, IActionReturn, IGetListResponse } from "../shared/type"
99
import { tagItemSelect, tagListSelect, TTagItem, TTagListItem } from "./selects"
1010

11-
type GetTagsProps = {
12-
page?: number
13-
limit?: number
14-
orderBy?: Prisma.TagsOrderByRelevanceInput
15-
}
16-
17-
export const getTags = async ({
18-
page = 1,
19-
limit = LIMIT_PER_PAGE,
20-
orderBy,
21-
}: GetTagsProps): Promise<IActionReturn<IGetListResponse<TTagItem>>> => {
22-
const tagQuery = {
23-
select: tagListSelect,
24-
take: Number(limit) || 10,
25-
skip: (page > 0 ? page - 1 : 0) * Number(limit),
26-
where: {
27-
name: {
28-
contains: orderBy?.search,
29-
mode: "insensitive",
30-
},
31-
},
32-
orderBy,
11+
export const getTags = async (
12+
tagsFindManyArgs: Prisma.TagsFindManyArgs = {
13+
take: LIMIT_PER_PAGE,
14+
skip: DEFAULT_LIMIT * (DEFAULT_PAGE - 1),
3315
}
34-
16+
): Promise<IActionReturn<IGetListResponse<TTagListItem>>> => {
3517
try {
3618
const [data, total] = await Promise.all([
37-
prisma.tags.findMany(tagQuery),
19+
prisma.tags.findMany({
20+
...tagsFindManyArgs,
21+
select: tagListSelect,
22+
}),
3823
prisma.tags.count({
39-
where: tagQuery.where,
24+
where: tagsFindManyArgs?.where || {},
4025
}),
4126
])
4227

28+
prisma.tags.findMany()
29+
4330
return {
4431
data: {
4532
data,
4633
total,
47-
limit,
48-
page,
49-
totalPages: Math.ceil(total / Number(limit)),
34+
limit: tagsFindManyArgs?.take || DEFAULT_LIMIT,
5035
},
5136
}
5237
} catch (error) {
@@ -56,8 +41,7 @@ export const getTags = async ({
5641
data: {
5742
data: [],
5843
total: 0,
59-
limit,
60-
page,
44+
limit: DEFAULT_LIMIT,
6145
},
6246
error,
6347
}

packages/database/src/users/queries.ts

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
1+
import { Prisma } from "@prisma/client"
2+
13
import prisma from "../prisma"
24
import { IActionReturn } from "../shared/type"
35
import { TUserDetail, userDetailSelect } from "./selects"
4-
import { TGetUserProps } from "./type"
56

6-
export const getUser = async ({ userId }: TGetUserProps): Promise<IActionReturn<TUserDetail>> => {
7+
export const getUser = async (
8+
userFindFirstArgs: Prisma.UserFindFirstArgs
9+
): Promise<IActionReturn<TUserDetail>> => {
710
try {
811
const data = await prisma.user.findFirst({
9-
where: {
10-
id: userId,
11-
},
12+
...userFindFirstArgs,
1213
select: userDetailSelect,
1314
})
1415

1516
if (!data) {
1617
throw {
18+
data: null,
1719
error: "NOT_FOUND",
1820
}
1921
}
@@ -28,3 +30,42 @@ export const getUser = async ({ userId }: TGetUserProps): Promise<IActionReturn<
2830
}
2931
}
3032
}
33+
34+
export const createUser = async (
35+
userCreateArgs: Prisma.UserCreateArgs
36+
): Promise<IActionReturn<TUserDetail>> => {
37+
try {
38+
const data = await prisma.user.create({
39+
...userCreateArgs,
40+
select: userDetailSelect,
41+
})
42+
43+
return {
44+
data,
45+
}
46+
} catch (error) {
47+
throw {
48+
error,
49+
data: null,
50+
}
51+
}
52+
}
53+
54+
export const updateUser = async (
55+
userUpdateArgs: Prisma.UserUpdateArgs
56+
): Promise<IActionReturn<TUserDetail>> => {
57+
try {
58+
const data = await prisma.user.update({
59+
...userUpdateArgs,
60+
select: userDetailSelect,
61+
})
62+
return {
63+
data,
64+
}
65+
} catch (error) {
66+
throw {
67+
error,
68+
data: null,
69+
}
70+
}
71+
}

packages/database/src/users/type.ts

Lines changed: 0 additions & 3 deletions
This file was deleted.

0 commit comments

Comments
 (0)