diff --git a/client/.env.sample b/client/.env.sample
new file mode 100644
index 0000000..70a73f3
--- /dev/null
+++ b/client/.env.sample
@@ -0,0 +1 @@
+SERVER_URL=
\ No newline at end of file
diff --git a/client/jest.config.js b/client/jest.config.js
index 4931934..1473472 100644
--- a/client/jest.config.js
+++ b/client/jest.config.js
@@ -1,3 +1,6 @@
module.exports = {
testEnvironment: 'jsdom',
+ moduleNameMapper: {
+ '.+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2|svg)$': 'jest-transform-stub',
+ },
};
diff --git a/client/package-lock.json b/client/package-lock.json
index 99b1bea..10e451f 100644
--- a/client/package-lock.json
+++ b/client/package-lock.json
@@ -34,6 +34,7 @@
"fork-ts-checker-webpack-plugin": "^6.3.2",
"html-webpack-plugin": "^5.3.2",
"jest": "^27.0.6",
+ "jest-transform-stub": "^2.0.0",
"prettier": "^2.3.2",
"typescript": "^4.3.5",
"webpack": "^5.50.0",
@@ -8765,6 +8766,12 @@
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
}
},
+ "node_modules/jest-transform-stub": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/jest-transform-stub/-/jest-transform-stub-2.0.0.tgz",
+ "integrity": "sha512-lspHaCRx/mBbnm3h4uMMS3R5aZzMwyNpNIJLXj4cEsV0mIUtS4IjYJLSoyjRCtnxb6RIGJ4NL2quZzfIeNhbkg==",
+ "dev": true
+ },
"node_modules/jest-util": {
"version": "27.0.6",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.6.tgz",
@@ -20369,6 +20376,12 @@
"semver": "^7.3.2"
}
},
+ "jest-transform-stub": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/jest-transform-stub/-/jest-transform-stub-2.0.0.tgz",
+ "integrity": "sha512-lspHaCRx/mBbnm3h4uMMS3R5aZzMwyNpNIJLXj4cEsV0mIUtS4IjYJLSoyjRCtnxb6RIGJ4NL2quZzfIeNhbkg==",
+ "dev": true
+ },
"jest-util": {
"version": "27.0.6",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.6.tgz",
diff --git a/client/package.json b/client/package.json
index 71806dc..3122072 100644
--- a/client/package.json
+++ b/client/package.json
@@ -34,6 +34,7 @@
"fork-ts-checker-webpack-plugin": "^6.3.2",
"html-webpack-plugin": "^5.3.2",
"jest": "^27.0.6",
+ "jest-transform-stub": "^2.0.0",
"prettier": "^2.3.2",
"typescript": "^4.3.5",
"webpack": "^5.50.0",
diff --git a/client/src/components/login/Login.test.tsx b/client/src/components/login/Login.test.tsx
new file mode 100644
index 0000000..6c096e1
--- /dev/null
+++ b/client/src/components/login/Login.test.tsx
@@ -0,0 +1,17 @@
+import React from 'react';
+import { render } from '@testing-library/react';
+import Login from './Login';
+
+describe('Login 컴포넌트', () => {
+ test('facebook 버튼 UI', () => {
+ const login = render();
+
+ login.getByText('페이스북으로 로그인');
+ });
+
+ test('google 버튼 UI', () => {
+ const login = render();
+
+ login.getByText('구글로 로그인');
+ });
+});
diff --git a/client/src/components/login/Login.tsx b/client/src/components/login/Login.tsx
new file mode 100644
index 0000000..ed3f1e7
--- /dev/null
+++ b/client/src/components/login/Login.tsx
@@ -0,0 +1,69 @@
+import React, { useCallback, useMemo } from 'react';
+import styled from 'styled-components';
+import OAuthButton from './OAuthButton';
+import FACEBOOK from './facebook.svg';
+import GOOGLE from './google.svg';
+
+enum OAuthType {
+ Facebook,
+ Google,
+}
+
+const Header = styled.h1`
+ font-size: 24px;
+ font-weight: normal;
+`;
+
+const LoginContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+`;
+
+const OAuthButtonWrapper = styled.div`
+ margin-top: 20px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-direction: column;
+ gap: 10px;
+`;
+
+const Login = (): JSX.Element => {
+ const handleOAuthButtonClick = useCallback((redirectURL: string) => {
+ return () => (location.href = redirectURL);
+ }, []);
+
+ const BUTTON_PROPS = useMemo(
+ () => ({
+ [OAuthType.Facebook]: {
+ backgroundColor: '#4267b2',
+ fontColor: '#ffffff',
+ icon: FACEBOOK,
+ content: '페이스북으로 로그인',
+ onClick: handleOAuthButtonClick(`${process.env.SERVER_URL}/auth/facebook-login`),
+ },
+ [OAuthType.Google]: {
+ backgroundColor: '#EA4335',
+ fontColor: '#ffffff',
+ icon: GOOGLE,
+ content: '구글로 로그인',
+ onClick: handleOAuthButtonClick(`${process.env.SERVER_URL}/auth/google-login`),
+ },
+ }),
+ [handleOAuthButtonClick]
+ );
+
+ return (
+
+
+
+
+
+
+
+ );
+};
+
+export default Login;
diff --git a/client/src/components/login/OAuthButton.tsx b/client/src/components/login/OAuthButton.tsx
new file mode 100644
index 0000000..2a2e63f
--- /dev/null
+++ b/client/src/components/login/OAuthButton.tsx
@@ -0,0 +1,55 @@
+import React, { MouseEventHandler } from 'react';
+import styled from 'styled-components';
+
+type ContainerProps = {
+ backgroundColor: string;
+ fontColor: string;
+};
+
+const OAuthButtonContainer = styled.button`
+ background-color: ${(props) => props.backgroundColor};
+ color: ${(props) => props.fontColor};
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 15px;
+ height: 50px;
+ width: 300px;
+ padding: 15px;
+ border: none;
+ cursor: pointer;
+`;
+
+const OAuthIcon = styled.img`
+ max-width: 18px;
+ max-height: 100%;
+`;
+
+const OAuthButtonContent = styled.span`
+ font-size: 16px;
+`;
+
+type Props = {
+ backgroundColor: string;
+ fontColor: string;
+ icon: string;
+ content: string;
+ onClick: MouseEventHandler;
+};
+
+const OAuthButton = ({
+ icon,
+ fontColor,
+ backgroundColor,
+ content,
+ onClick,
+}: Props): JSX.Element => {
+ return (
+
+
+ {content}
+
+ );
+};
+
+export default OAuthButton;
diff --git a/client/src/components/login/facebook.svg b/client/src/components/login/facebook.svg
new file mode 100644
index 0000000..b60b3e1
--- /dev/null
+++ b/client/src/components/login/facebook.svg
@@ -0,0 +1,43 @@
+
+
+
+
diff --git a/client/src/components/login/google.svg b/client/src/components/login/google.svg
new file mode 100644
index 0000000..7dbb495
--- /dev/null
+++ b/client/src/components/login/google.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/client/src/components/login/kakao.svg b/client/src/components/login/kakao.svg
new file mode 100644
index 0000000..1e23afc
--- /dev/null
+++ b/client/src/components/login/kakao.svg
@@ -0,0 +1 @@
+
diff --git a/client/webpack.dev.js b/client/webpack.dev.js
index e774c20..42d44a8 100644
--- a/client/webpack.dev.js
+++ b/client/webpack.dev.js
@@ -19,6 +19,6 @@ module.exports = merge(common, {
mode: 'DEV',
},
}),
- new EnvironmentPlugin([]),
+ new EnvironmentPlugin(['SERVER_URL']),
],
});