Skip to content

Commit 2e24324

Browse files
authored
Merge pull request #59 from FE9-2/feat/response-type
feat: response type ํŒŒ์ผ
2 parents ae6e3bb + 7d4f1aa commit 2e24324

File tree

21 files changed

+534
-198
lines changed

21 files changed

+534
-198
lines changed

โ€Žsrc/app/(auth)/signup/page.tsxโ€Ž

Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,24 @@
22

33
import { useAuth } from "@/hooks/useAuth";
44
import { type SignupSchema, signupSchema } from "@/schemas/authSchema";
5-
import { ROLES } from "@/schemas/commonSchema";
5+
import { userRoles } from "@/constants/userRoles";
66
import { zodResolver } from "@hookform/resolvers/zod";
77
import Link from "next/link";
8-
import { useEffect } from "react";
98
import { FieldErrors, useForm } from "react-hook-form";
9+
import { useEffect } from "react";
1010

1111
export default function SignupPage() {
1212
const { signup, isSignupPending } = useAuth();
1313
const {
1414
register,
1515
handleSubmit,
1616
watch,
17-
setValue,
1817
formState: { errors },
18+
setValue,
1919
} = useForm<SignupSchema>({
2020
resolver: zodResolver(signupSchema),
2121
defaultValues: {
22-
role: ROLES.APPLICANT,
22+
role: userRoles.APPLICANT,
2323
phoneNumber: "",
2424
storeName: "",
2525
storePhoneNumber: "",
@@ -31,11 +31,25 @@ export default function SignupPage() {
3131
const selectedRole = watch("role");
3232
const formValues = watch();
3333

34+
useEffect(() => {
35+
if (selectedRole === userRoles.APPLICANT) {
36+
setValue("storeName", "", { shouldValidate: false });
37+
setValue("storePhoneNumber", "", {
38+
shouldValidate: false,
39+
shouldDirty: false,
40+
shouldTouch: false,
41+
});
42+
setValue("location", "", { shouldValidate: false });
43+
} else {
44+
setValue("phoneNumber", "", { shouldValidate: false });
45+
}
46+
}, [selectedRole, setValue]);
47+
3448
const isFormComplete = () => {
3549
const baseFields = ["email", "password", "confirmPassword", "name", "nickname"];
3650
const baseFieldsComplete = baseFields.every((field) => formValues[field as keyof SignupSchema]?.trim() !== "");
3751

38-
if (selectedRole === ROLES.OWNER) {
52+
if (selectedRole === userRoles.OWNER) {
3953
return (
4054
baseFieldsComplete &&
4155
formValues.storeName?.trim() !== "" &&
@@ -47,26 +61,8 @@ export default function SignupPage() {
4761
return baseFieldsComplete && formValues.phoneNumber?.trim() !== "";
4862
};
4963

50-
useEffect(() => {
51-
if (selectedRole === ROLES.APPLICANT) {
52-
setValue("storeName", "");
53-
setValue("storePhoneNumber", "");
54-
setValue("location", "");
55-
} else if (selectedRole === ROLES.OWNER) {
56-
setValue("phoneNumber", "");
57-
}
58-
}, [selectedRole, setValue]);
59-
6064
const onSubmit = (data: SignupSchema) => {
61-
if (data.role === ROLES.OWNER) {
62-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
63-
const { phoneNumber, ...ownerData } = data;
64-
signup(ownerData as SignupSchema);
65-
} else {
66-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
67-
const { storeName, storePhoneNumber, location, ...applicantData } = data;
68-
signup(applicantData as SignupSchema);
69-
}
65+
signup(data);
7066
};
7167

7268
const onError = (errors: FieldErrors<SignupSchema>) => {
@@ -134,16 +130,16 @@ export default function SignupPage() {
134130
</div>
135131
<div className="flex gap-4">
136132
<label className="flex items-center">
137-
<input {...register("role")} type="radio" value={ROLES.APPLICANT} className="mr-2" defaultChecked />
133+
<input {...register("role")} type="radio" value={userRoles.APPLICANT} className="mr-2" defaultChecked />
138134
์ง€์›์ž
139135
</label>
140136
<label className="flex items-center">
141-
<input {...register("role")} type="radio" value={ROLES.OWNER} className="mr-2" />
137+
<input {...register("role")} type="radio" value={userRoles.OWNER} className="mr-2" />
142138
์‚ฌ์žฅ๋‹˜
143139
</label>
144140
</div>
145141
{errors.role && <p className="mt-1 text-sm text-red-600">{errors.role.message}</p>}
146-
{selectedRole === ROLES.APPLICANT && (
142+
{selectedRole === userRoles.APPLICANT && (
147143
<div>
148144
<input
149145
{...register("phoneNumber")}
@@ -154,7 +150,7 @@ export default function SignupPage() {
154150
{errors.phoneNumber && <p className="mt-1 text-sm text-red-600">{errors.phoneNumber.message}</p>}
155151
</div>
156152
)}
157-
{selectedRole === ROLES.OWNER && (
153+
{selectedRole === userRoles.OWNER && (
158154
<>
159155
<div>
160156
<input

โ€Žsrc/app/api/auth/refresh/route.tsโ€Ž

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,22 @@ import { NextResponse } from "next/server";
44
import apiClient from "@/lib/apiClient";
55

66
export const POST = async (): Promise<NextResponse> => {
7+
const cookieStore = cookies();
8+
const refreshToken = cookieStore.get("refreshToken");
9+
10+
if (!refreshToken) {
11+
return new NextResponse(
12+
JSON.stringify({
13+
message: "๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.",
14+
}),
15+
{
16+
status: 200,
17+
headers: { "Content-Type": "application/json" },
18+
}
19+
);
20+
}
21+
722
try {
8-
const refreshToken = cookies().get("refreshToken")?.value;
923
// ํ† ํฐ ๊ฐฑ์‹ 
1024
const refreshResponse = await apiClient.post("/auth/refresh", { refreshToken });
1125
const { accessToken } = refreshResponse.data;

โ€Žsrc/app/api/auth/signup/route.tsโ€Ž

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,43 @@ import { AxiosError } from "axios";
22
import { NextRequest, NextResponse } from "next/server";
33

44
import apiClient from "@/lib/apiClient";
5+
import { userRoles } from "@/constants/userRoles";
56

67
export const POST = async (request: NextRequest): Promise<NextResponse> => {
78
try {
8-
const { email, name, nickname, password, role, storeName, storePhoneNumber, phoneNumber, location } =
9-
await request.json();
10-
const response = await apiClient.post("/auth/sign-up", {
11-
email,
12-
name,
13-
nickname,
14-
password,
15-
role,
16-
storeName,
17-
storePhoneNumber,
18-
phoneNumber,
19-
location,
20-
});
9+
const requestData = await request.json();
10+
const { role } = requestData;
11+
12+
let data;
13+
if (role === userRoles.APPLICANT) {
14+
// ์ง€์›์ž์˜ ๊ฒฝ์šฐ ํ•„์š”ํ•œ ํ•„๋“œ๋งŒ ์ถ”์ถœ
15+
const { email, password, name, nickname, phoneNumber, role } = requestData;
16+
17+
data = {
18+
email,
19+
password,
20+
name,
21+
nickname,
22+
phoneNumber,
23+
role,
24+
};
25+
} else {
26+
// ์‚ฌ์žฅ๋‹˜์˜ ๊ฒฝ์šฐ ํ•„์š”ํ•œ ํ•„๋“œ๋งŒ ์ถ”์ถœ
27+
const { email, password, name, nickname, storeName, storePhoneNumber, location, role } = requestData;
28+
29+
data = {
30+
email,
31+
password,
32+
name,
33+
nickname,
34+
storeName,
35+
storePhoneNumber,
36+
location,
37+
role,
38+
};
39+
}
40+
41+
const response = await apiClient.post("/auth/sign-up", data);
2142
const { accessToken, refreshToken, user } = response.data;
2243

2344
return NextResponse.json({ accessToken, refreshToken, user }, { status: 200 });
@@ -28,6 +49,6 @@ export const POST = async (request: NextRequest): Promise<NextResponse> => {
2849
return NextResponse.json({ message: error.response.data.message }, { status: error.response.status });
2950
}
3051
}
31-
return NextResponse.json({ message: "๋กœ๊ทธ์ธ ์‹คํŒจ" }, { status: 500 });
52+
return NextResponse.json({ message: "ํšŒ์›๊ฐ€์ž… ์‹คํŒจ" }, { status: 500 });
3253
}
3354
};
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export const formSortOptions = {
2+
MOST_RECENT: "mostRecent",
3+
HIGHEST_WAGE: "highestWage",
4+
MOST_APPLIED: "mostApplied",
5+
MOST_SCRAPPED: "mostScrapped",
6+
} as const;
7+
8+
export const formStatusOptions = {
9+
REJECTED: "REJECTED",
10+
INTERVIEW_PENDING: "INTERVIEW_PENDING",
11+
INTERVIEW_COMPLETED: "INTERVIEW_COMPLETED",
12+
HIRED: "HIRED",
13+
} as const;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export const oauthProviders = {
2+
GOOGLE: "google",
3+
KAKAO: "kakao",
4+
} as const;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const postSortOptions = {
2+
MOST_RECENT: "mostRecent",
3+
MOST_COMMENTED: "mostCommented",
4+
MOST_LIKED: "mostLiked",
5+
} as const;

โ€Žsrc/constants/userRoles.tsโ€Ž

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export const userRoles = {
2+
OWNER: "OWNER",
3+
APPLICANT: "APPLICANT",
4+
} as const;

โ€Žsrc/hooks/useAuth.tsโ€Ž

Lines changed: 56 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { LoginSchema, SignupSchema } from "@/schemas/authSchema";
22
import { useUserStore } from "@/store/userStore";
3-
import { AuthResponse, AuthUser } from "@/types/response/auth";
4-
import { UserDetail } from "@/types/response/user";
3+
import { AuthResponse } from "@/types/response/auth";
4+
import { UserResponse } from "@/types/response/user";
55
import { useMutation, useQueryClient } from "@tanstack/react-query";
66
import axios from "axios";
77
import { useRouter } from "next/navigation";
@@ -16,20 +16,28 @@ export const useAuth = () => {
1616
// ํ† ํฐ ๊ฐฑ์‹  mutation
1717
const refreshMutation = useMutation({
1818
mutationFn: async () => {
19-
const response = await axios.post<{ user: UserDetail }>(
20-
"/api/auth/refresh",
21-
{},
22-
{
23-
withCredentials: true,
19+
try {
20+
const response = await axios.post<AuthResponse>(
21+
"/api/auth/refresh",
22+
{},
23+
{
24+
withCredentials: true,
25+
}
26+
);
27+
return response.data;
28+
} catch (error) {
29+
if (axios.isAxiosError(error) && error.response?.status === 400) {
30+
// ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ์ด ์—†๋Š” ๊ฒฝ์šฐ ์กฐ์šฉํžˆ ์ฒ˜๋ฆฌ
31+
setUser(null);
32+
return null;
2433
}
25-
);
26-
return response.data;
34+
throw error;
35+
}
2736
},
2837
onSuccess: (data) => {
2938
if (data?.user) {
30-
const UserDetail = data.user as unknown as UserDetail;
31-
const user = { ...UserDetail } as unknown as AuthUser;
32-
setUser(user);
39+
const userResponse = data.user as unknown as UserResponse;
40+
setUser(userResponse);
3341
queryClient.invalidateQueries({ queryKey: ["user"] });
3442
}
3543
},
@@ -43,43 +51,64 @@ export const useAuth = () => {
4351
// ํšŒ์›๊ฐ€์ž… mutation
4452
const signupMutation = useMutation<AuthResponse, Error, SignupSchema>({
4553
mutationFn: async (data: SignupSchema) => {
46-
const response = await axios.post<AuthResponse>("/api/auth/signup", data, {
47-
withCredentials: true,
48-
});
49-
return response.data;
54+
try {
55+
const response = await axios.post<AuthResponse>("/api/auth/signup", data, {
56+
withCredentials: true,
57+
});
58+
return response.data;
59+
} catch (error) {
60+
if (axios.isAxiosError(error)) {
61+
// ์„œ๋ฒ„์—์„œ ์ „๋‹ฌ๋œ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ์‚ฌ์šฉ
62+
throw new Error(error.response?.data?.message || "ํšŒ์›๊ฐ€์ž… ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.");
63+
}
64+
throw error;
65+
}
5066
},
5167
onSuccess: () => {
5268
toast.success("ํšŒ์›๊ฐ€์ž…์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!");
5369
router.push("/login");
5470
},
5571
onError: (error: Error) => {
56-
toast.error(error.message || "ํšŒ์›๊ฐ€์ž… ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.");
72+
// error.message์—๋Š” ์„œ๋ฒ„์—์„œ ์ „๋‹ฌ๋œ ๋ฉ”์‹œ์ง€๊ฐ€ ํฌํ•จ๋จ
73+
toast.error(error.message);
5774
},
5875
});
5976

6077
// ๋กœ๊ทธ์ธ mutation
6178
const loginMutation = useMutation({
6279
mutationFn: async (data: LoginSchema) => {
63-
const response = await axios.post<AuthResponse>("/api/auth/login", data, {
64-
withCredentials: true,
65-
});
66-
return response.data;
80+
try {
81+
const response = await axios.post<AuthResponse>("/api/auth/login", data, {
82+
withCredentials: true,
83+
});
84+
return response.data;
85+
} catch (error) {
86+
if (axios.isAxiosError(error)) {
87+
// ์„œ๋ฒ„์—์„œ ์ „๋‹ฌ๋œ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ์‚ฌ์šฉ
88+
throw new Error(error.response?.data?.message || "๋กœ๊ทธ์ธ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.");
89+
}
90+
throw error;
91+
}
6792
},
6893
onSuccess: (data) => {
69-
setUser(data.user as AuthUser);
70-
toast.success("๋กœ๊ทธ์ธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!");
71-
router.push("/");
72-
router.refresh();
94+
if (data?.user) {
95+
const userResponse = data.user as unknown as UserResponse;
96+
setUser(userResponse);
97+
toast.success("๋กœ๊ทธ์ธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!");
98+
router.push("/");
99+
router.refresh();
100+
}
73101
},
74102
onError: (error: Error) => {
75-
toast.error(error.message || "๋กœ๊ทธ์ธ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.");
103+
// error.message์—๋Š” ์„œ๋ฒ„์—์„œ ์ „๋‹ฌ๋œ ๋ฉ”์‹œ์ง€๊ฐ€ ํฌํ•จ๋จ
104+
toast.error(error.message);
76105
},
77106
});
78107

79108
// ๋กœ๊ทธ์•„์›ƒ mutation
80109
const logoutMutation = useMutation({
81110
mutationFn: async () => {
82-
const response = await axios.post<AuthResponse>(
111+
const response = await axios.post(
83112
"/api/auth/logout",
84113
{},
85114
{

โ€Žsrc/hooks/useUser.tsโ€Ž

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ import { useQuery } from "@tanstack/react-query";
22
import axios from "axios";
33
import { toast } from "react-hot-toast";
44
import { useUserStore } from "@/store/userStore";
5-
import { UserDetail } from "@/types/response/user";
6-
import { AuthUser } from "@/types/response/auth";
5+
import { UserResponse } from "@/types/response/user";
76
import { useEffect } from "react";
87

98
async function fetchUser() {
@@ -37,9 +36,8 @@ export function useUser() {
3736

3837
useEffect(() => {
3938
if (data?.user) {
40-
const UserDetail = data.user as unknown as UserDetail;
41-
const user = { ...UserDetail } as unknown as AuthUser;
42-
setUser(user);
39+
const userResponse = data.user as unknown as UserResponse;
40+
setUser(userResponse);
4341
} else if (!isLoading) {
4442
setUser(null);
4543
}

โ€Žsrc/schemas/applicationSchema.tsโ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { z } from "zod";
2-
import { passwordSchema, phoneSchema } from "./commonSchema";
2+
import { passwordSchema, mobilePhoneSchema } from "./commonSchema";
33

44
// ์ง€์›์„œ ๋“ฑ๋ก
55
export const applicationSchema = z.object({
@@ -8,7 +8,7 @@ export const applicationSchema = z.object({
88
resumeName: z.string(),
99
resumeId: z.number(),
1010
experienceMonths: z.number(),
11-
phoneNumber: phoneSchema,
11+
phoneNumber: mobilePhoneSchema,
1212
name: z.string(),
1313
});
1414

0 commit comments

Comments
ย (0)