Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[deploy] signup validation #61

Merged
merged 5 commits into from
Jul 4, 2024
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
15 changes: 15 additions & 0 deletions apis/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,18 @@ export const getCenterList = async () => {
throw error;
}
};

interface IdCheckResponseBody {
timestamp: string;
status: number;
error: string;
code: string;
message: string;
}

async function postIdCheck(loginId: string): Promise<IdCheckResponseBody> {
const { data } = await client.post(`/users/loginId`, { loginId });
return data;
}

export { postIdCheck };
21 changes: 19 additions & 2 deletions apis/hooks/auth.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useQuery, useMutation } from "@tanstack/react-query";
import { SignUp, getCenterList, userProps } from "../auth";
import { SignUp, getCenterList, postIdCheck, userProps } from "../auth";
import { useRouter } from "next/router";
import { InputError } from "@/pages/mypage/password";

function useGetCenterList() {
const { data } = useQuery({
Expand Down Expand Up @@ -28,4 +29,20 @@ function useSignUp(userData: userProps) {
return { mutate };
}

export { useGetCenterList, useSignUp };
function usePostIdCheck(
loginId: string,
setIdError: React.Dispatch<React.SetStateAction<InputError>>,
) {
const { mutate } = useMutation({
mutationKey: ["postIdCheck", loginId],
mutationFn: () => postIdCheck(loginId),
onSuccess: () => setIdError({ status: false, text: "" }),
onError: () => {
setIdError({ status: true, text: "이미 사용 중인 아이디입니다." });
},
});

return { mutate };
}

export { useGetCenterList, useSignUp, usePostIdCheck };
18 changes: 11 additions & 7 deletions components/auth/AuthInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export interface TextInputProps {
name: string;
onChange: (e: ChangeEvent<HTMLInputElement>) => void;
maxLength?: number;
isSuccess?: boolean;
}

const AuthInput = forwardRef<HTMLInputElement, TextInputProps>(
Expand All @@ -24,20 +25,23 @@ const AuthInput = forwardRef<HTMLInputElement, TextInputProps>(
name,
onChange,
maxLength = 10,
isSuccess = false,
},
ref,
) => {
const borderStyle = () => {
if (isSuccess) return "border-green-600";
else if (isError) return "border-red-500";
return "border-solid";
};

return (
<div className="w-full relative">
<div
className={`${className} rounded-xl border border-solid ${
isError ? "border-red-500" : "border-semantic-grey-2"
} rounded-lg p-2`}
>
<div className={`${className} border ${borderStyle()} rounded-xl p-2`}>
<input
type={type}
name={name}
className="w-full outline-none border-none h4 placeholder:text-grey-400 pl-1"
className="w-full outline-none border-none h4 leading-normal placeholder:text-grey-400 pl-1"
value={value}
onChange={onChange}
placeholder={placeholder}
Expand All @@ -46,7 +50,7 @@ const AuthInput = forwardRef<HTMLInputElement, TextInputProps>(
/>
</div>
{isError && (
<div className="text-red-500 h5 px-2 absolute">{errorText}</div>
<div className="text-red-500 h6 px-2 absolute">{errorText}</div>
)}
</div>
);
Expand Down
231 changes: 150 additions & 81 deletions pages/signup.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { centerProps, userProps } from "@/apis/auth";
import { useGetCenterList, useSignUp } from "@/apis/hooks/auth";
import { useGetCenterList, usePostIdCheck, useSignUp } from "@/apis/hooks/auth";
import Button from "@/components/Button";
import HeadFunction from "@/components/HeadFunction";
import AuthInput from "@/components/auth/AuthInput";
Expand All @@ -12,6 +12,7 @@ import CheckIcon from "@/public/svgs/Check.svg";
import FlexBox from "@/components/Flexbox";
import { usePostNicknameCheck } from "@/apis/hooks/mypage";
import { InputError } from "./mypage/password";
import NicknameInput from "@/components/mypage/NicknameInput";

const SignUp: NextPage = () => {
//input용
Expand Down Expand Up @@ -49,6 +50,8 @@ const SignUp: NextPage = () => {
const { mutate: signUpMutate } = useSignUp(userInfo);

//중복 확인
//닉네임 중복
const [tempName, setTempName] = useState<string>("");
const [nameError, setNameError] = useState<InputError>({
status: false,
text: "",
Expand All @@ -58,7 +61,6 @@ const SignUp: NextPage = () => {
if (checkNicknameValidity()) nameCheckMutate();
};

const [tempName, setTempName] = useState<string>("");
const checkNicknameValidity = () => {
setTempName(userInfo.nickname);
if (userInfo.nickname.length > 8) {
Expand Down Expand Up @@ -86,100 +88,167 @@ const SignUp: NextPage = () => {
setNameError,
);

//아이디 중복
const [tempId, setTempId] = useState<string>("");
const [idError, setIdError] = useState<InputError>({
status: false,
text: "",
});

const checkIdValidity = () => {
setTempId(userInfo.loginId);
if (userInfo.loginId.length > 16) {
setIdError({
status: true,
text: "아이디 최대 길이는 16자입니다.",
});
return false;
}

const regex = /^[a-zA-Z0-9\s]*$/;
if (!regex.test(userInfo.loginId)) {
setIdError({
status: true,
text: "아이디는 영어, 숫자로만 구성할 수 있습니다.",
});
return false;
}

return true;
};

const { mutate: idCheckMutate } = usePostIdCheck(
userInfo.loginId,
setIdError,
);

const onClickIdBtn = () => {
if (checkIdValidity()) idCheckMutate();
};

return (
<div className="flex flex-col w-full h-screen items-center">
<div className="flex flex-col w-screen h-screen items-center">
<HeadFunction title="회원가입" />
<form
onSubmit={onSubmit}
className="h-screen w-full items-center flex flex-col gap-9 overflow-auto scrollbar-hide mt-5"
>
<div className="flex flex-col gap-3">
<TextLine children={"아이디"} className="pl-1" />
<div className="flex flex-col gap-4">
<div className="flex flex-col gap-2">
<TextLine children={"아이디"} className="pl-1" />

<FlexBox className="w-full gap-2">
<AuthInput
placeholder="아이디를 입력하세요"
name="loginId"
ref={idInputRef}
value={userInfo.loginId}
onChange={onChange}
maxLength={16}
className="flex-grow"
isSuccess={
!(
tempId.length === 0 ||
idError.status ||
userInfo.loginId.length === 0
)
}
isError={idError.status}
errorText={idError.text}
/>
<button
className="shrink-0 px-3 py-2.5 border border-main-color text-main-color rounded-lg h5"
onClick={(e) => {
e.preventDefault();
onClickIdBtn();
}}
>
중복
</button>
</FlexBox>
</div>

<div className="flex flex-col gap-2">
<TextLine children={"비밀번호"} className="pl-1" />

<FlexBox className="w-full gap-2">
<AuthInput
placeholder="아이디를 입력하세요"
name="loginId"
ref={idInputRef}
value={userInfo.loginId}
placeholder="비밀번호를 입력하세요"
name="password"
ref={pwInputRef}
value={userInfo.password}
onChange={onChange}
maxLength={16}
className="flex-grow"
className={"w-[19.5rem]"}
/>
{/* <button
className="shrink-0 px-3 py-2.5 border border-main-color text-main-color rounded-lg h5"
onClick={(e) => {
e.preventDefault();
}}
>
중복
</button> */}
</FlexBox>

<TextLine children={"비밀번호"} className="pl-1" />

<AuthInput
placeholder="비밀번호를 입력하세요"
name="password"
ref={pwInputRef}
value={userInfo.password}
onChange={onChange}
className={"w-[19.5rem]"}
/>
</div>

<TextLine children={"닉네임"} className="pl-1" />
<FlexBox className="w-full gap-2">
<div className="flex flex-col gap-2">
<TextLine children={"닉네임"} className="pl-1" />
<FlexBox className="w-full gap-2">
<AuthInput
placeholder="한글, 영어, 숫자 포함 최대 8자"
name="nickname"
ref={nicknameInputRef}
value={userInfo.nickname}
onChange={onChange}
maxLength={8}
className="flex-grow"
isSuccess={
!(
tempName.length === 0 ||
nameError.status ||
userInfo.nickname.length === 0
)
}
isError={nameError.status}
errorText={nameError.text}
/>

<button
className="shrink-0 px-3 py-2.5 border border-main-color text-main-color rounded-lg h5"
onClick={(e) => {
e.preventDefault();
onClickCheckBtn();
}}
>
중복
</button>
</FlexBox>
</div>

<div className="flex flex-col gap-2">
<TextLine children={"식별번호"} className="pl-1" />
<AuthInput
placeholder="한글, 영어, 숫자 포함 최대 8자"
name="nickname"
ref={nicknameInputRef}
value={userInfo.nickname}
placeholder="이름과 전화번호 뒷자리 4개를 입력해주세요."
name="identifier"
ref={idfInputRef}
value={userInfo.identifier}
maxLength={10}
onChange={onChange}
maxLength={8}
className="flex-grow"
className={"w-[19.5rem]"}
/>
{/* <button
className="shrink-0 px-3 py-2.5 border border-main-color text-main-color rounded-lg h5"
onClick={(e) => {
e.preventDefault();
onClickCheckBtn();
}}
>
중복
</button> */}
</FlexBox>

<TextLine children={"식별번호"} className="pl-1" />

<AuthInput
placeholder="이름과 전화번호 뒷자리 4개를 입력해주세요."
name="identifier"
ref={idfInputRef}
value={userInfo.identifier}
maxLength={10}
onChange={onChange}
className={"w-[19.5rem]"}
/>
</div>

<TextLine children={"소속센터"} className="pl-1" />
{data && (
<select
className="border h-9 rounded-xl px-2"
value={userInfo.centerIdx}
onChange={(e) =>
setUserInfo({
...userInfo,
centerIdx: parseInt(e.target.value, 10),
})
}
>
{data.map((center: centerProps) => (
<option key={center.centerIdx} value={center.centerIdx}>
{center.name}
</option>
))}
</select>
)}
<div className="flex flex-col gap-2">
<TextLine children={"소속센터"} className="pl-1" />
{data && (
<select
className="border h-9 rounded-xl px-2"
value={userInfo.centerIdx}
onChange={(e) =>
setUserInfo({
...userInfo,
centerIdx: parseInt(e.target.value, 10),
})
}
>
{data.map((center: centerProps) => (
<option key={center.centerIdx} value={center.centerIdx}>
{center.name}
</option>
))}
</select>
)}
</div>
</div>
<button type="submit" className="w-[20rem] absolute bottom-[3.75rem]">
<Button
Expand Down
4 changes: 2 additions & 2 deletions pages/success.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const SignupSuccess: NextPage = () => {
});

return (
<div className="w-full h-full flex flex justify-center items-center">
<div className="w-screen h-screen flex flex justify-center items-center">
<FlexBox
direction="col"
className="w-[90%] h-full items-center justify-center"
Expand All @@ -31,7 +31,7 @@ const SignupSuccess: NextPage = () => {
<Button
text="로그인하러 가기"
style="bg-main-100 text-grey-900"
onClick={() => router.push("/login")}
onClick={() => router.push("/main")}
/>
</FlexBox>
</div>
Expand Down