Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 45 additions & 2 deletions app/profile-image/_components/TermsDrawer.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
"use client";
import React, { useState } from "react";
import { ChevronRight, ArrowLeft } from "lucide-react";
import axios from "axios";
import Button from "@/components/ui/Button";
import { SelectCheckButton } from "./ProfileImageSelection";
import ProfileBottomSheet from "./ProfileBottomSheet";
import { TERMS_TEXT, PRIVACY_TEXT } from "../_constants/terms";
import { Hobby, ProfileSubmitData } from "@/lib/types/profile";
import { useProfile } from "@/providers/profile-provider";
import { useImageUpload, useProfileSignUp } from "@/hooks/useProfileSignUp";
import {
useNicknameAvailability,
NicknameAvailabilityResponse,
} from "@/hooks/useNicknameAvailability";
import { useRouter } from "next/navigation";
import { HOBBIES, HobbyCategory } from "@/lib/constants/hobbies";

Expand All @@ -31,6 +36,7 @@ const TermsDrawer = ({ children }: TermsDrawerProps) => {

const { mutateAsync: uploadImage } = useImageUpload();
const { mutate: signUp, isPending: isSubmitting } = useProfileSignUp();
const { mutateAsync: checkNicknameAvailability } = useNicknameAvailability();

const checkGradient =
"linear-gradient(220.53deg, #FF775E -18.87%, #FF4D61 62.05%, #E83ABC 125.76%)";
Expand Down Expand Up @@ -146,9 +152,46 @@ const TermsDrawer = ({ children }: TermsDrawerProps) => {

const trigger = children
? React.cloneElement(children, {
onClick: (e: React.MouseEvent<HTMLElement>) => {
onClick: async (e: React.MouseEvent<HTMLElement>) => {
children.props.onClick?.(e);
setIsOpen(true);

const nickname = (profile.nickname || "").trim();

if (!nickname) {
alert("닉네임을 입력해 주세요.");
return;
}

try {
const res = await checkNicknameAvailability(nickname);

// 200 OK 응답 처리
if (res.code === "GEN-000") {
const isAvailable =
typeof res.data === "object" ? res.data?.available : res.data;
if (isAvailable) {
setIsOpen(true);
} else {
alert("중복된 닉네임입니다. 다른 닉네임을 입력해 주세요.");
}
}
} catch (error: unknown) {
if (axios.isAxiosError(error)) {
const res = error.response?.data as NicknameAvailabilityResponse;

// 백엔드에서 400 등 에러 코드를 보낼 때 (MEM-009 등)
if (res?.code === "MEM-009") {
alert("공백은 닉네임으로 사용할 수 없습니다.");
return;
}
}

// 그 외 진짜 예상치 못한 에러 (네트워크, 500 등)
console.error("Failed to check nickname availability:", error);
alert(
"닉네임 중복 확인에 실패했습니다. 잠시 후 다시 시도해 주세요.",
);
}
},
})
: null;
Expand Down
35 changes: 35 additions & 0 deletions hooks/useNicknameAvailability.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { api } from "@/lib/axios";
import { useMutation } from "@tanstack/react-query";

export interface NicknameAvailabilityResponse {
code: string;
status: number;
message: string;
data?:
| boolean
| {
available?: boolean;
isAvailable?: boolean;
duplicate?: boolean;
};
}

const checkNicknameAvailability = async (
nickname: string,
): Promise<NicknameAvailabilityResponse> => {
const { data: response } = await api.get<NicknameAvailabilityResponse>(
"/api/auth/signup/nickname/availability",
{
params: { nickname },
},
);

return response;
};

export const useNicknameAvailability = () => {
return useMutation({
mutationFn: checkNicknameAvailability,
retry: false,
});
};
Loading