Skip to content
Open
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
2 changes: 1 addition & 1 deletion src/auth/components/SigninModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { GitHubIcon, GoogleIcon, Loading } from '@shared/components/Icons';
import { Modal, Stack, Button } from '@jdesignlab/react';
import { useMachine } from '@xstate/react';
import { Mail } from '@jdesignlab/react-icons';
import { EmailPasswordForm } from './EmailPasswordForm';
import { EmailPasswordForm } from './action/EmailPasswordForm';
import { useSigninWithProvider } from '../hooks/useSigninWithProvider';
import { signMachine } from '../machines/signMachine';

Expand Down
4 changes: 2 additions & 2 deletions src/auth/components/SignupModal.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Modal, Button } from '@jdesignlab/react';
import { useMachine } from '@xstate/react';
import { UserProfileForm } from './UserProfileForm';
import { EmailPasswordForm } from './EmailPasswordForm';
import { UserProfileForm } from './action/UserProfileForm';
import { EmailPasswordForm } from './action/EmailPasswordForm';
import { signMachine } from '../machines/signMachine';
import { useSetUserAuthData } from '../hooks/useSetUserAuthData';

Expand Down
54 changes: 54 additions & 0 deletions src/auth/components/action/AuthLoginButtons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { GitHubIcon, GoogleIcon, Loading } from '@shared/components/Icons';
import { useActor } from '@xstate/react';
import { Button, Flex } from '@jdesignlab/react';
import { Mail } from '@jdesignlab/react-icons';
import { useSigninWithProvider } from '../../hooks/useSigninWithProvider';
import type { SignMachineType } from '../../machines/signMachine';
import type { InterpreterFrom } from 'xstate';

interface Props {
signMachine: InterpreterFrom<SignMachineType>;
}

export const AuthLoginButtons = (props: Props) => {
const { signMachine } = props;
const [, refSend] = useActor(signMachine);
const { isLoading: loadingWithGitHubLogin, mutate: signinGithub } = useSigninWithProvider('GITHUB', refSend);
const { isLoading: loadingWithGoogleLogin, mutate: signinGoogle } = useSigninWithProvider('GOOGLE', refSend);
return (
<Flex direction="column" gap="16px">
<Button
color="primary-500"
variant="outline"
icon={<Mail />}
onClick={() => {
refSend('EMAIL');
}}
>
Email 계정으로 로그인
</Button>
<Button
color="green-darken3"
variant="outline"
onClick={() => {
signinGithub();
}}
disabled={loadingWithGitHubLogin}
icon={loadingWithGitHubLogin ? <Loading /> : <GitHubIcon />}
>
GitHub 계정으로 로그인
</Button>
<Button
color="lightBlue-darken1"
variant="outline"
disabled={loadingWithGoogleLogin}
icon={loadingWithGoogleLogin ? <Loading /> : <GoogleIcon />}
onClick={() => {
signinGoogle();
}}
>
Google 계정으로 로그인
</Button>
</Flex>
);
};
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Text, TextInput, Button, Modal } from '@jdesignlab/react';
import { Text, TextInput, Button } from '@jdesignlab/react';
import { useForm } from 'react-hook-form';
import { useActor } from '@xstate/react';
import { Flex } from '../styles/Profile';
import { useAccountEmailWithPassword } from '../hooks/useAccountEmailWithPassword';
import { useCreateUserMutation } from '../hooks/useCreateUserMutation';
import { Flex } from '../../styles/Profile';
import { useAccountEmailWithPassword } from '../../hooks/useAccountEmailWithPassword';
import { useCreateUserMutation } from '../../hooks/useCreateUserMutation';
import type { InterpreterFrom } from 'xstate';
import type { SignMachineType } from '../machines/signMachine';
import type { EmailPasswordField } from '../types';
import type { SignMachineType } from '../../machines/signMachine';
import type { EmailPasswordField } from '../../types';

interface Props {
signMachine: InterpreterFrom<SignMachineType>;
Expand Down Expand Up @@ -61,24 +61,22 @@ export const EmailPasswordForm = (props: Props) => {
<TextInput.Label>Password</TextInput.Label>
</TextInput>
{errors.password && <Text color="red-base">{errors.password.message as string}</Text>}
<Modal.Footer>
<Flex>
{!signup && (
<Button
variant="outline"
color="red-lighten2"
onClick={() => {
refSend({ type: 'CLEAR' });
}}
>
뒤로가기
</Button>
)}
<Button type="submit" variant="outline" color="primary-500" disabled={isLoading}>
{signup ? '회원가입' : '로그인'}
<Flex>
{!signup && (
<Button
variant="outline"
color="red-lighten2"
onClick={() => {
refSend({ type: 'CLEAR' });
}}
>
뒤로가기
</Button>
</Flex>
</Modal.Footer>
)}
<Button type="submit" variant="outline" color="primary-500" disabled={isLoading}>
{signup ? '회원가입' : '로그인'}
</Button>
</Flex>
</form>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import { Loading } from '@shared/components/Icons';
import { useForm } from 'react-hook-form';
import { useActor } from '@xstate/react';
import { TextInput, Button, Modal } from '@jdesignlab/react';
import { useProfileUpdate } from '../hooks/useProfileUpdate';
import { useSetUserAuthData } from '../hooks/useSetUserAuthData';
import { parseUserInfo } from '../parseUserInfo';
import { Flex } from '../styles/Profile';
import { useProfileUpdate } from '../../hooks/useProfileUpdate';
import { useSetUserAuthData } from '../../hooks/useSetUserAuthData';
import { parseUserInfo } from '../../parseUserInfo';
import { Flex } from '../../styles/Profile';
import type { InterpreterFrom } from 'xstate';
import type { SignMachineType } from '../machines/signMachine';
import type { UserProfile } from '../types';
import type { SignMachineType } from '../../machines/signMachine';
import type { UserProfile } from '../../types';

interface Props {
signupMachineRef: InterpreterFrom<SignMachineType>;
Expand Down
22 changes: 22 additions & 0 deletions src/auth/styles/signPageStyle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { css } from '@emotion/react';

export const signFormContainer = css({
height: 'fit-content',
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
padding: '24px 16px'
});

export const title = css({
textAlign: 'center'
});

export const signButtonWrapper = css({
display: 'flex',
marginTop: '32px',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center'
});
19 changes: 14 additions & 5 deletions src/layout/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import { useSignout } from '@auth/hooks/useSignout';
import { SigninModal } from '@auth/components/SigninModal';
import { SignupModal } from '@auth/components/SignupModal';
import { ErrorModal } from '@shared/components/ErrorModal';
import { Layout } from '@shared/components/dataDisplay/FlexLayout';
import { headerWrapper, headerContents } from '@layout/styles/headerStyle';
import { useGetUserInfoById } from '@challenge/hooks/useGetUserInfoById';
import { Avatar } from '@shared/components/dataDisplay/Avatar';
import { Loading } from '@shared/components/Icons/Loading';
import { CompositionBoundaryReactQuery } from '@shared/boundaries';
import { Dropdown, Text } from '@jdesignlab/react';
import { Button, Dropdown, Text } from '@jdesignlab/react';
import { useRouter } from 'next/router';
import Image from 'next/image';
import { useSession } from 'next-auth/react';
Expand All @@ -19,6 +17,15 @@ export const Header = () => {
const moveToMain = () => {
router.push('/');
};

const moveToSigninPage = () => {
router.push('/login');
};

const moveToSignupPage = () => {
router.push('/signup');
};

const { data } = useSession();
const { userInfo } = useGetUserInfoById(data?.user?.uid);
const { mutate: signout } = useSignout();
Expand Down Expand Up @@ -86,8 +93,10 @@ export const Header = () => {
</Dropdown>
) : (
<Layout.Row gap={4}>
<SigninModal />
<SignupModal />
<Button variant="outline" onClick={moveToSigninPage}>
로그인
</Button>
<Button onClick={moveToSignupPage}>회원가입</Button>
</Layout.Row>
)}
</CompositionBoundaryReactQuery>
Expand Down
41 changes: 41 additions & 0 deletions src/pages/login.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import * as Style from '@auth/styles/signPageStyle';
import { CompositionBoundaryReactQuery } from '@shared/boundaries';
import { ErrorModal } from '@shared/components/ErrorModal';
import { signMachine } from '@auth/machines/signMachine';
import { AuthLoginButtons } from '@auth/components/action/AuthLoginButtons';
import { Loading } from '@shared/components/Icons';
import { EmailPasswordForm } from '@auth/components/action/EmailPasswordForm';
import { Button, Text } from '@jdesignlab/react';
import { useMachine } from '@xstate/react';
import { useRouter } from 'next/router';

const Login = () => {
const [state, , service] = useMachine(signMachine);
const { value: signState } = state;
const router = useRouter();

const moveToLoginPage = () => {
router.push('/signup');
};

return (
<CompositionBoundaryReactQuery suspense={<Loading />} error={(props) => <ErrorModal {...props} />}>
<section css={Style.signFormContainer}>
<div css={Style.title}>
<Text variant="heading" size="xl" color="primary-500" align="center">
로그인
</Text>
<Button variant="link" onClick={moveToLoginPage}>
계정이 없으세요?
</Button>
</div>
<div css={Style.signButtonWrapper}>
{signState === 'selection' && <AuthLoginButtons signMachine={service} />}
{signState === 'email' && <EmailPasswordForm signMachine={service} signup={false} />}
</div>
</section>
</CompositionBoundaryReactQuery>
);
};

export default Login;
66 changes: 66 additions & 0 deletions src/pages/signup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import * as Style from '@auth/styles/signPageStyle';
import { Loading } from '@shared/components/Icons';
import { CompositionBoundaryReactQuery } from '@shared/boundaries';
import { ErrorModal } from '@shared/components/ErrorModal';
import { EmailPasswordForm } from '@auth/components/action/EmailPasswordForm';
import { signMachine } from '@auth/machines/signMachine';
import { UserProfileForm } from '@auth/components/action/UserProfileForm';
import { useSetUserAuthData } from '@auth/hooks/useSetUserAuthData';
import { Button, Text } from '@jdesignlab/react';
import { useMachine } from '@xstate/react';
import { useRouter } from 'next/router';

const SignUpPage = () => {
const [state, send, service] = useMachine(signMachine);
const { value: signState, context } = state;
const userInfo = context.user;
const { updateUserData } = useSetUserAuthData();
const router = useRouter();

const moveToPage = (url: string, callback?: () => void) => {
if (callback) {
callback();
}
router.push(url);
};

const onUpdateUserData = () => {
if (userInfo) {
updateUserData(userInfo);
}
send('CLEAR');
};

if (state.matches('done')) {
moveToPage('/');
}

return (
<CompositionBoundaryReactQuery suspense={<Loading />} error={(props) => <ErrorModal {...props} />}>
<section css={Style.signFormContainer}>
<div css={Style.title}>
<Text variant="heading" size="xl" color="primary-500" align="center">
회원가입
</Text>
<Button
variant="link"
onClick={() => {
moveToPage('/login', onUpdateUserData);
}}
>
이미 계정이 있으세요?
</Button>
</div>
<div css={Style.signButtonWrapper}>
{signState === 'registry' ? (
<UserProfileForm signupMachineRef={service} />
) : (
<EmailPasswordForm signMachine={service} signup />
)}
</div>
</section>
</CompositionBoundaryReactQuery>
);
};

export default SignUpPage;
4 changes: 3 additions & 1 deletion src/shared/constants/firebaseError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export type FirebaseErrorCode =
| 'auth/invalid-display-name'
| 'auth/invalid-dynamic-link-domain'
| 'auth/invalid-email'
| 'auth/wrong-password'
| 'auth/invalid-email-verified'
| 'auth/invalid-hash-algorithm'
| 'auth/invalid-hash-block-size'
Expand Down Expand Up @@ -119,5 +120,6 @@ export const CustomFirebaseError: Record<FirebaseErrorCode, string> = {
'auth/uid-already-exists': '제공된 uid를 기존 사용자가 이미 사용하고 있습니다. 각 사용자마다 uid가 고유해야 합니다.',
'auth/unauthorized-continue-uri':
'연결 URL의 도메인이 허용 목록에 포함되어 있지 않습니다. Firebase Console에서 도메인을 허용해야 합니다.',
'auth/user-not-found': '제공된 식별자에 해당하는 기존 사용자 레코드가 없습니다.'
'auth/user-not-found': '제공된 식별자에 해당하는 기존 사용자 레코드가 없습니다.',
'auth/wrong-password': '비밀번호가 맞지 않습니다.'
};