Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
bd0a431
refactor: validate 분리
SwimmingRiver Jun 16, 2025
b019f2e
refactor: 경로 이동replace로 수정
SwimmingRiver Jun 16, 2025
7dbdbde
refactor: 회원가입 페이지 ssr로 변경
SwimmingRiver Jun 16, 2025
381c646
refactor: 컴포넌트 분리
SwimmingRiver Jun 16, 2025
6c78dc6
chore: 타입 수정
SwimmingRiver Jun 16, 2025
5e2b217
refactor: 폼 입력 필드 분리
SwimmingRiver Jun 16, 2025
85e4ec9
refactor: 타입 수정
SwimmingRiver Jun 17, 2025
5243922
refactor: 컴포넌트 분리
SwimmingRiver Jun 17, 2025
da356cb
refactor: ssr로 변경
SwimmingRiver Jun 17, 2025
f00632b
fix: 타입 수정
SwimmingRiver Jun 17, 2025
3fd1910
refactor: 접근성 설정
SwimmingRiver Jun 17, 2025
539d402
fix: 스타일 수정
SwimmingRiver Jun 17, 2025
4332827
chore: 오타수정
SwimmingRiver Jun 17, 2025
74268c5
chore: 파일명 변경
SwimmingRiver Jun 17, 2025
896719e
chore: export 제거
SwimmingRiver Jun 17, 2025
b44c5c9
refactor: useForm 수정
SwimmingRiver Jun 17, 2025
d69bb98
chore: 불필요한 태그 제거
SwimmingRiver Jun 17, 2025
04c0d58
fix: referr 수정
SwimmingRiver Jun 17, 2025
a5428b8
chore: 파일명 변경
SwimmingRiver Jun 17, 2025
8a4f327
refactor: useForm 수정
SwimmingRiver Jun 17, 2025
1c03697
Merge branch 'develop' of https://github.com/we-write/frontend into r…
SwimmingRiver Jun 17, 2025
3a6e59d
feat: 회원가입 토스트 추가
SwimmingRiver Jun 17, 2025
df26c13
Merge branch 'refactor/#249-page-signup' of https://github.com/we-wri…
SwimmingRiver Jun 17, 2025
992f2da
feat: 토스트 추가
SwimmingRiver Jun 17, 2025
604e11f
chore: 타입 수정
SwimmingRiver Jun 18, 2025
6a315fe
fix: 불필요한 태그 제거
SwimmingRiver Jun 18, 2025
f403731
refactor: hooks 에러 핸들링 분리
SwimmingRiver Jun 18, 2025
83fa5a6
chore: 타입명 수정
SwimmingRiver Jun 18, 2025
83932bc
refactor: 회원가입 에러 핸들링 분리
SwimmingRiver Jun 18, 2025
2de7b91
refactor: 입력 필드 InputForm 으로 변경
SwimmingRiver Jun 19, 2025
e0a7fce
Merge pull request #146 from we-write/refactor/#252-page-signin
SwimmingRiver Jun 19, 2025
5414630
Merge branch 'develop' into refactor/#249-page-signup
SwimmingRiver Jun 19, 2025
a116110
fix: getMyInfoOnServer 경로 변경
SwimmingRiver Jun 19, 2025
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
1 change: 1 addition & 0 deletions src/api/auth/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export interface SignUpFormData {
passwordCheck: string;
companyName: string;
}

export type SignUpRequest = Omit<SignUpFormData, 'passwordCheck'>;

//TODO: 병합 후 수정
Expand Down
17 changes: 17 additions & 0 deletions src/app/auths/signin/_components/LinkToSignUp.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Link from 'next/link';

const LinkToSignUp = () => {
return (
<div className="flex-center gap-2">
<span>WE WRITE가 처음이신가요?</span>
<Link
href="/auths/signup"
className="text-write-main font-semibold underline"
>
회원가입
</Link>
</div>
);
};

export default LinkToSignUp;
67 changes: 67 additions & 0 deletions src/app/auths/signin/_components/SignInForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
'use client';
import Button from '@/components/common/Button/Button';
import InputForm from '@/components/common/Form/InputForm';
import useBoolean from '@/hooks/useBoolean';
import { useSignInForm } from '@/hooks/api/auth/useSignInForm';
import { VisibilityOff, VisibilityOn } from '@public/assets/icons';
import { signInValidate } from '@/utils/validators/auth';

const SignInForm = () => {
const { value: isShowPassword, toggle: toggleIsShowPassword } = useBoolean();

const { onSubmit, register, handleSubmit, isSubmitting, errors } =
useSignInForm();

return (
<form className="flex flex-col gap-6" onSubmit={handleSubmit(onSubmit)}>
<InputForm
label="아이디"
name="email"
placeholder="이메일을 입력해주세요."
register={register('email', {
validate: (value) => signInValidate({ value, name: 'email' }),
})}
type="email"
hasError={!!errors.email}
helperText={errors.email?.message}
/>

<InputForm
name="password"
label="비밀번호"
placeholder="비밀번호를 입력해주세요."
register={register('password', {
validate: (value) => signInValidate({ value, name: 'password' }),
})}
type={isShowPassword ? 'text' : 'password'}
hasError={!!errors.password}
helperText={errors.password?.message}
suffixIcon={
<button
type="button"
className="flex items-center justify-center"
onClick={toggleIsShowPassword}
>
{isShowPassword ? (
<VisibilityOn aria-label="show password" fill="currentColor" />
) : (
<VisibilityOff aria-label="hide password" fill="currentColor" />
)}
</button>
}
/>

<Button
role="button"
type="submit"
color="custom"
disabled={isSubmitting || !!errors.email || !!errors.password}
className={`${errors.email || errors.password ? 'bg-gray-400' : 'bg-write-main'} font-bold text-white`}
>
로그인
</Button>
</form>
);
};

export default SignInForm;
139 changes: 13 additions & 126 deletions src/app/auths/signin/page.tsx
Original file line number Diff line number Diff line change
@@ -1,139 +1,26 @@
'use client';
import Button from '@/components/common/Button/Button';
import InputForm from '@/components/common/Form/InputForm';
import SignInForm from './_components/SignInForm';
import getMyInfoOnServer from '@/providers/auth-provider/getMyInfoOnServer';
import { headers } from 'next/headers';
import { redirect } from 'next/navigation';
import LinkToSignUp from './_components/LinkToSignUp';

import { VisibilityOff, VisibilityOn } from '@public/assets/icons';
import { usePostSignin } from '@/hooks/api/auth/usePostSignin';
import { SigninRequest } from '@/api/auth/type';
const SignIn = async () => {
const { isSignIn } = await getMyInfoOnServer();
const referer = (await headers()).get('referer');

import Link from 'next/link';
import { useRouter } from 'next/navigation';

import { useEffect } from 'react';
import { SubmitHandler, useForm } from 'react-hook-form';
import useBoolean from '@/hooks/useBoolean';
import { useAuth } from '@/providers/auth-provider/AuthProvider.client';
import { APP_ROUTES } from '@/constants/appRoutes';
import useReferer from '@/hooks/useReferer';

const SignIn = () => {
const { value: isShowPassword, toggle: toggleIsShowPassword } = useBoolean();
const { redirectPath } = useReferer();
const router = useRouter();
const {
register,
handleSubmit,
setError,
formState: { isSubmitting, errors },
} = useForm<SigninRequest>();
const { mutate: signIn, isPending } = usePostSignin();
const { isSignIn } = useAuth();
const onSubmit: SubmitHandler<SigninRequest> = (data) => {
if (isSubmitting || isPending) return;
signIn(data, {
onSuccess: () => {
router.replace(redirectPath);
},
onError: (error: Error) => {
const errorData = JSON.parse(error.message);
if (
errorData.code === 'VALIDATION_ERROR' ||
errorData.code === 'USER_NOT_FOUND'
) {
setError('email', {
type: 'manual',
message: errorData.message,
});
}
if (errorData.code === 'INVALID_CREDENTIALS') {
setError('password', {
type: 'manual',
message: errorData.message,
});
}
},
});
};
useEffect(() => {
if (isSignIn) {
router.push(APP_ROUTES.social);
}
}, []);
if (isSignIn) {
return <div>Loading...</div>;
redirect(referer ?? '/');
}

return (
<div className="flex h-screen w-full flex-col items-center justify-center">
<div className="flex max-h-[478px] w-[343px] flex-col gap-10 rounded-3xl bg-white px-4 py-6 sm:px-4 md:w-[608px] md:px-13 lg:max-h-[478px] lg:w-[508px]">
<h1 className="text-write-main text-center text-xl font-bold">
로그인
</h1>
<form className="flex flex-col gap-6" onSubmit={handleSubmit(onSubmit)}>
<div className="flex flex-col gap-2">
<InputForm
label="아이디"
name="email"
type="email"
placeholder="이메일을 입력해주세요."
register={{
...register('email', { required: '이메일을 입력해주세요.' }),
}}
helperText={errors.email?.message}
hasError={!!errors.email}
/>
</div>
<div>
<InputForm
label="비밀번호"
name="password"
placeholder="비밀번호를 입력해주세요."
register={{
...register('password', {
required: '비밀번호를 입력해주세요.',
}),
}}
hasError={!!errors.password}
helperText={errors.password?.message}
suffixIcon={
<button
type="button"
className="flex items-center justify-center"
onClick={toggleIsShowPassword}
>
{isShowPassword ? (
<VisibilityOn
aria-label="show password"
fill="currentColor"
/>
) : (
<VisibilityOff
aria-label="hide password"
fill="currentColor"
/>
)}
</button>
}
type={isShowPassword ? 'text' : 'password'}
/>
</div>
<Button
role="button"
type="submit"
isDisabled={isPending || !!errors.email || !!errors.password}
isLoading={isSubmitting || isPending}
>
로그인
</Button>
</form>
<div className="flex items-center justify-center gap-2">
<span>WE WRITE가 처음이신가요?</span>
<Link
href="/auths/signup"
className="text-write-main font-semibold underline"
>
회원가입
</Link>
</div>

<SignInForm />
<LinkToSignUp />
</div>
</div>
);
Expand Down
17 changes: 17 additions & 0 deletions src/app/auths/signup/_components/LinkToSignIn.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { APP_ROUTES } from '@/constants/appRoutes';
import Link from 'next/link';

const LinkToSignIn = () => {
return (
<div className="flex-center gap-2">
<span>이미 회원이신가요?</span>
<Link
href={APP_ROUTES.signin}
className="text-write-main font-semibold underline"
>
로그인
</Link>
</div>
);
};
export default LinkToSignIn;
Loading