diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..9fc6d7f --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,55 @@ +# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions + +name: deploy + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [14.x] + # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + + - name: create env file + working-directory: ./server + run: | + touch .env + cat << EOF >> .env + ${{ secrets.ENV }} + + - name: build client files + working-directory: ./client + run: | + yarn install --frozen-lockfile + yarn build + + - name: zip distributions + run: zip -r STORE_2.zip ./client/dist ./server ./appspec.yml ./scripts + + - name: AWS configure credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ap-northeast-2 + + - name: upload to S3 + run: aws s3 cp --region ap-northeast-2 ./STORE_2.zip s3://store-2/public/ + + - name: deploy with AWS codeDeploy + run: aws deploy create-deployment --application-name store-2 --deployment-config-name CodeDeployDefault.OneAtATime --deployment-group-name store2-codedeploy --s3-location bucket=store-2,bundleType=zip,key=public/STORE_2.zip diff --git a/.github/workflows/lint-check.yml b/.github/workflows/lint-check.yml index 25b6681..cda9548 100644 --- a/.github/workflows/lint-check.yml +++ b/.github/workflows/lint-check.yml @@ -1,7 +1,7 @@ # This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions -name: Node.js CI +name: lint check on: pull_request: @@ -13,7 +13,7 @@ jobs: strategy: matrix: - node-version: [12.x, 14.x, 16.x] + node-version: [14.x] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: diff --git a/.gitignore b/.gitignore index 009d1cd..36ed06d 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,8 @@ dist # yarn yarn-error.log + +# test snapshots +__snapshots__ + +.DS_Store diff --git a/appspec.yml b/appspec.yml new file mode 100644 index 0000000..fbb5f95 --- /dev/null +++ b/appspec.yml @@ -0,0 +1,18 @@ +version: 0.0 +os: linux +files: + - source: / + destination: /home/ubuntu/store-2 + overwrite: yes + +permissions: + - object: /home/ubuntu + pattern: '**' + owner: ubuntu + group: ubuntu + +hooks: + AfterInstall: + - location: scripts/after-deploy.sh + timeout: 180 + runas: ubuntu diff --git a/client/.eslintrc.json b/client/.eslintrc.json index 257e3c0..a2ca326 100644 --- a/client/.eslintrc.json +++ b/client/.eslintrc.json @@ -5,15 +5,32 @@ "plugin:@typescript-eslint/recommended", "plugin:@typescript-eslint/recommended-requiring-type-checking", "plugin:react/recommended", - "plugin:prettier/recommended" + "plugin:prettier/recommended", + "plugin:redux-saga/recommended" ], "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint", "prettier"], + "plugins": [ + "@typescript-eslint", + "prettier", + "testing-library", + "redux-saga" + ], "parserOptions": { "project": ["client/tsconfig.json"] }, "rules": { "react/prop-types": "off", - "@typescript-eslint/no-empty-interface": "off" - } + "@typescript-eslint/no-empty-interface": "off", + "import/no-unresolved": "off" + }, + "ignorePatterns": ["webpack.*.js", "jest.config.js", "setup-tests.ts", "file-transformer.js"], + "overrides": [ + { + "files": [ + "**/__tests__/**/*.[jt]s?(x)", + "**/?(*.)+(spec|test).[jt]s?(x)" + ], + "extends": ["plugin:testing-library/react"] + } + ] } diff --git a/client/.prettierrc b/client/.prettierrc index f8abd4d..bc5bfa7 100644 --- a/client/.prettierrc +++ b/client/.prettierrc @@ -4,6 +4,6 @@ "useTabs": false, "tabWidth": 2, "trailingComma": "all", - "printWidth": 80, + "printWidth": 120, "arrowParens": "avoid" } diff --git a/client/config/webpack.common.js b/client/config/webpack.common.js index b20e8ca..6881d30 100644 --- a/client/config/webpack.common.js +++ b/client/config/webpack.common.js @@ -1,7 +1,7 @@ import path from 'path'; import HtmlWebpackPlugin from 'html-webpack-plugin'; -import { CleanWebpackPlugin } from 'clean-webpack-plugin'; import MiniCssExtractPlugin from 'mini-css-extract-plugin'; +import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin'; const __dirname = path.resolve(); @@ -10,13 +10,13 @@ export default { output: { filename: '[name].js', path: path.resolve(__dirname, 'dist'), + clean: true, + assetModuleFilename: 'assets/[hash].[ext]?[query]', }, resolve: { modules: ['node_modules'], extensions: ['.js', '.ts', '.tsx'], - alias: { - '*': path.resolve(__dirname, 'src'), - }, + plugins: [new TsconfigPathsPlugin()], }, module: { rules: [ @@ -51,9 +51,8 @@ export default { plugins: [ new HtmlWebpackPlugin({ template: './public/index.html', - favicon: './public/favicon.ico', + favicon: './public/favicon.png', }), - new CleanWebpackPlugin(), new MiniCssExtractPlugin({ filename: '[name].css', }), diff --git a/client/config/webpack.dev.js b/client/config/webpack.dev.js index 564d452..ea3cb70 100644 --- a/client/config/webpack.dev.js +++ b/client/config/webpack.dev.js @@ -9,7 +9,7 @@ export default merge(common, { module: { rules: [ { - test: /\.s[ac]ss|css$/, + test: /\.css$/, use: ['style-loader', 'css-loader'], exclude: /node_modules/, }, diff --git a/client/config/webpack.prod.js b/client/config/webpack.prod.js index d82db7d..44b16e8 100644 --- a/client/config/webpack.prod.js +++ b/client/config/webpack.prod.js @@ -9,7 +9,7 @@ export default merge(common, { module: { rules: [ { - test: /\.s[ac]ss|css$/, + test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader'], exclude: /node_modules/, }, diff --git a/client/file-transformer.js b/client/file-transformer.js new file mode 100644 index 0000000..5293551 --- /dev/null +++ b/client/file-transformer.js @@ -0,0 +1,7 @@ +const path = require('path'); + +module.exports = { + process(src, filename, config, options) { + return 'module.exports = ' + JSON.stringify(path.basename(filename || '')) + ';'; + }, +}; diff --git a/client/jest.config.js b/client/jest.config.js new file mode 100644 index 0000000..be5eadd --- /dev/null +++ b/client/jest.config.js @@ -0,0 +1,15 @@ +export default { + transform: { + '^.+\\.(js|jsx)?$': 'babel-jest', + '^.+\\.(ts|tsx)?$': 'ts-jest', + }, + testEnvironment: 'jsdom', + testMatch: ['/**/*.test.(js|jsx|ts|tsx)'], + setupFilesAfterEnv: ['/setup-tests.ts'], + transformIgnorePatterns: ['/node_modules/'], + moduleNameMapper: { + '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': + '/file-transformer.js', + }, + modulePaths: ['/src'], +}; diff --git a/client/package.json b/client/package.json index 4882bf2..292dc6b 100644 --- a/client/package.json +++ b/client/package.json @@ -17,7 +17,8 @@ "lint": "eslint ./src --ext .js,.jsx,.ts,.tsx --parser-options=project:'./tsconfig.json'", "lint:fix": "eslint ./src --ext .js,.jsx,.ts,.tsx --parser-options=project:'./tsconfig.json' --fix", "start": "webpack serve --config config/webpack.dev.js", - "build": "NODE_ENV=production webpack --config config/webpack.prod.js --progress" + "build": "NODE_ENV=production webpack --config config/webpack.prod.js --progress", + "test": "jest --config ./jest.config.js" }, "dependencies": { "@reduxjs/toolkit": "^1.6.1", @@ -27,8 +28,10 @@ "react-redux": "^7.2.4", "redux": "^4.1.1", "redux-saga": "^1.1.3", + "redux-saga-test-plan": "^4.0.3", "sanitize-html": "^2.4.0", - "styled-components": "^5.3.0" + "styled-components": "^5.3.0", + "styled-reset": "^4.3.4" }, "devDependencies": { "@babel/cli": "^7.14.8", @@ -36,6 +39,9 @@ "@babel/preset-env": "^7.15.0", "@babel/preset-react": "^7.14.5", "@babel/preset-typescript": "^7.15.0", + "@testing-library/jest-dom": "^5.14.1", + "@testing-library/react": "^12.0.0", + "@types/jest": "^27.0.0", "@types/react": "^17.0.17", "@types/react-dom": "^17.0.9", "@types/react-redux": "^7.1.18", @@ -44,7 +50,6 @@ "@typescript-eslint/parser": "^4.29.1", "babel-cli": "^6.26.0", "babel-loader": "^8.2.2", - "clean-webpack-plugin": "^4.0.0-alpha.0", "core-js-pure": "^3.16.1", "css-loader": "^6.2.0", "css-minimizer-webpack-plugin": "^3.0.2", @@ -56,12 +61,17 @@ "eslint-plugin-prettier": "^3.4.0", "eslint-plugin-react": "^7.24.0", "eslint-plugin-react-hooks": "^4.2.0", + "eslint-plugin-redux-saga": "^1.2.1", + "eslint-plugin-testing-library": "^4.10.1", "html-webpack-plugin": "^5.3.2", + "jest": "^27.0.6", "mini-css-extract-plugin": "^2.2.0", "prettier": "^2.3.2", "style-loader": "^3.2.1", "terser-webpack-plugin": "^5.1.4", + "ts-jest": "^27.0.4", "ts-loader": "^9.2.5", + "tsconfig-paths-webpack-plugin": "^3.5.1", "typescript": "^4.3.5", "webpack": "^5.49.0", "webpack-cli": "^4.7.2", diff --git a/client/public/favicon.ico b/client/public/favicon.ico deleted file mode 100644 index fdbc19b..0000000 Binary files a/client/public/favicon.ico and /dev/null differ diff --git a/client/public/favicon.png b/client/public/favicon.png new file mode 100644 index 0000000..b110988 Binary files /dev/null and b/client/public/favicon.png differ diff --git a/client/setup-tests.ts b/client/setup-tests.ts new file mode 100644 index 0000000..666127a --- /dev/null +++ b/client/setup-tests.ts @@ -0,0 +1 @@ +import '@testing-library/jest-dom/extend-expect'; diff --git a/client/src/App.tsx b/client/src/App.tsx index ba39e7f..96eae83 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,16 +1,23 @@ import React from 'react'; -import { BrowserRouter, Switch, Route } from './lib/router'; -import { MainPage, UserPage, NotFoundPage } from './pages'; +import { BrowserRouter, Switch, Route } from 'lib/router'; +import { MainPage, UserPage, NotFoundPage, SagaCounterPage, TestPage, SagaAxiosPage, LoginPage } from 'pages'; +import Theme from './styles/theme'; const App: React.FC = () => { return ( - - - - - - - + + + + + + + + + + + + + ); }; diff --git a/client/src/assets/fonts/BMEULJIRO.woff b/client/src/assets/fonts/BMEULJIRO.woff new file mode 100644 index 0000000..3322c74 Binary files /dev/null and b/client/src/assets/fonts/BMEULJIRO.woff differ diff --git a/client/src/assets/fonts/BMEULJIRO10yearslater.woff b/client/src/assets/fonts/BMEULJIRO10yearslater.woff new file mode 100644 index 0000000..9682a4f Binary files /dev/null and b/client/src/assets/fonts/BMEULJIRO10yearslater.woff differ diff --git a/client/src/assets/fonts/BMHANNA11years.woff b/client/src/assets/fonts/BMHANNA11years.woff new file mode 100644 index 0000000..f6091ed Binary files /dev/null and b/client/src/assets/fonts/BMHANNA11years.woff differ diff --git a/client/src/assets/fonts/BMHANNAAir.woff b/client/src/assets/fonts/BMHANNAAir.woff new file mode 100644 index 0000000..2ca6f2e Binary files /dev/null and b/client/src/assets/fonts/BMHANNAAir.woff differ diff --git a/client/src/assets/icons/account.png b/client/src/assets/icons/account.png new file mode 100644 index 0000000..da05b5e Binary files /dev/null and b/client/src/assets/icons/account.png differ diff --git a/client/src/assets/icons/attachment.png b/client/src/assets/icons/attachment.png new file mode 100644 index 0000000..abcf464 Binary files /dev/null and b/client/src/assets/icons/attachment.png differ diff --git a/client/src/assets/icons/back.png b/client/src/assets/icons/back.png new file mode 100644 index 0000000..2c34d83 Binary files /dev/null and b/client/src/assets/icons/back.png differ diff --git a/client/src/assets/icons/badge_best.png b/client/src/assets/icons/badge_best.png new file mode 100644 index 0000000..92f14f4 Binary files /dev/null and b/client/src/assets/icons/badge_best.png differ diff --git a/client/src/assets/icons/badge_green.png b/client/src/assets/icons/badge_green.png new file mode 100644 index 0000000..f01c709 Binary files /dev/null and b/client/src/assets/icons/badge_green.png differ diff --git a/client/src/assets/icons/badge_new.png b/client/src/assets/icons/badge_new.png new file mode 100644 index 0000000..c39b1fe Binary files /dev/null and b/client/src/assets/icons/badge_new.png differ diff --git a/client/src/assets/icons/badge_sale.png b/client/src/assets/icons/badge_sale.png new file mode 100644 index 0000000..267ec71 Binary files /dev/null and b/client/src/assets/icons/badge_sale.png differ diff --git a/client/src/assets/icons/baedalee.png b/client/src/assets/icons/baedalee.png new file mode 100644 index 0000000..b110988 Binary files /dev/null and b/client/src/assets/icons/baedalee.png differ diff --git a/client/src/assets/icons/cart.png b/client/src/assets/icons/cart.png new file mode 100644 index 0000000..21839cf Binary files /dev/null and b/client/src/assets/icons/cart.png differ diff --git a/client/src/assets/icons/congrats.gif b/client/src/assets/icons/congrats.gif new file mode 100644 index 0000000..f0ea862 Binary files /dev/null and b/client/src/assets/icons/congrats.gif differ diff --git a/client/src/assets/icons/enter.png b/client/src/assets/icons/enter.png new file mode 100644 index 0000000..446a787 Binary files /dev/null and b/client/src/assets/icons/enter.png differ diff --git a/client/src/assets/icons/find.png b/client/src/assets/icons/find.png new file mode 100644 index 0000000..c37126d Binary files /dev/null and b/client/src/assets/icons/find.png differ diff --git a/client/src/assets/icons/github.png b/client/src/assets/icons/github.png new file mode 100644 index 0000000..f685712 Binary files /dev/null and b/client/src/assets/icons/github.png differ diff --git a/client/src/assets/icons/like-filled.png b/client/src/assets/icons/like-filled.png new file mode 100644 index 0000000..af560ad Binary files /dev/null and b/client/src/assets/icons/like-filled.png differ diff --git a/client/src/assets/icons/like.png b/client/src/assets/icons/like.png new file mode 100644 index 0000000..280c492 Binary files /dev/null and b/client/src/assets/icons/like.png differ diff --git a/client/src/assets/icons/login.png b/client/src/assets/icons/login.png new file mode 100644 index 0000000..d4bb394 Binary files /dev/null and b/client/src/assets/icons/login.png differ diff --git a/client/src/assets/icons/logo_mobile.png b/client/src/assets/icons/logo_mobile.png new file mode 100644 index 0000000..3138710 Binary files /dev/null and b/client/src/assets/icons/logo_mobile.png differ diff --git a/client/src/assets/icons/logout.png b/client/src/assets/icons/logout.png new file mode 100644 index 0000000..47539d2 Binary files /dev/null and b/client/src/assets/icons/logout.png differ diff --git a/client/src/assets/icons/plus.png b/client/src/assets/icons/plus.png new file mode 100644 index 0000000..a3ec1ba Binary files /dev/null and b/client/src/assets/icons/plus.png differ diff --git a/client/src/assets/icons/search.png b/client/src/assets/icons/search.png new file mode 100644 index 0000000..df688f5 Binary files /dev/null and b/client/src/assets/icons/search.png differ diff --git a/client/src/assets/icons/star_off.png b/client/src/assets/icons/star_off.png new file mode 100644 index 0000000..30d5cc8 Binary files /dev/null and b/client/src/assets/icons/star_off.png differ diff --git a/client/src/assets/icons/star_on.png b/client/src/assets/icons/star_on.png new file mode 100644 index 0000000..3221ba5 Binary files /dev/null and b/client/src/assets/icons/star_on.png differ diff --git a/client/src/assets/icons/stars_title.png b/client/src/assets/icons/stars_title.png new file mode 100644 index 0000000..bd19261 Binary files /dev/null and b/client/src/assets/icons/stars_title.png differ diff --git a/client/src/assets/icons/tag.png b/client/src/assets/icons/tag.png new file mode 100644 index 0000000..4fef1c3 Binary files /dev/null and b/client/src/assets/icons/tag.png differ diff --git a/client/src/assets/icons/wait.png b/client/src/assets/icons/wait.png new file mode 100644 index 0000000..d9c4c53 Binary files /dev/null and b/client/src/assets/icons/wait.png differ diff --git a/client/src/assets/images/brick.png b/client/src/assets/images/brick.png new file mode 100644 index 0000000..42b4a8e Binary files /dev/null and b/client/src/assets/images/brick.png differ diff --git a/client/src/assets/images/brick_mobile.png b/client/src/assets/images/brick_mobile.png new file mode 100644 index 0000000..2c1b39f Binary files /dev/null and b/client/src/assets/images/brick_mobile.png differ diff --git a/client/src/assets/images/logo.png b/client/src/assets/images/logo.png new file mode 100644 index 0000000..cf315f1 Binary files /dev/null and b/client/src/assets/images/logo.png differ diff --git a/client/src/assets/images/logo_tent.png b/client/src/assets/images/logo_tent.png new file mode 100644 index 0000000..11cf908 Binary files /dev/null and b/client/src/assets/images/logo_tent.png differ diff --git a/client/src/assets/images/tent.png b/client/src/assets/images/tent.png new file mode 100644 index 0000000..21b635f Binary files /dev/null and b/client/src/assets/images/tent.png differ diff --git a/client/src/components/auth/login-button.tsx b/client/src/components/auth/login-button.tsx new file mode 100644 index 0000000..f8b4acc --- /dev/null +++ b/client/src/components/auth/login-button.tsx @@ -0,0 +1,45 @@ +import styled from 'styled-components'; + +interface Inf { + login?: boolean; + github?: boolean; + signup?: boolean; +} + +const LoginButton = styled.button` + ${({ theme }) => theme.mobile} { + height: 66px; + font-size: 20px; + } + ${({ theme }) => theme.tablet} { + width: 380px; + height: 75px; + font-size: 23px; + } + ${({ theme }) => theme.laptop} { + width: 400px; + height: 85px; + font-size: 26px; + } + &:not(:first-child) { + margin-top: 10px; + } + &:hover { + opacity: 1; + font-weight: 600; + transform: translateY(-5px); + } + cursor: pointer; + border: 0; + display: flex; + align-items: center; + justify-content: center; + color: ${({ theme }) => theme.colorWhite}; + font-family: ${({ theme }) => theme.fontEuljiro}; + opacity: 0.9; + background: ${props => props.login && props.theme.colorLine}; + background: ${props => props.github && props.theme.colorGithub}; + background: ${props => props.signup && props.theme.colorSignup}; +`; + +export default LoginButton; diff --git a/client/src/components/auth/login-form.tsx b/client/src/components/auth/login-form.tsx new file mode 100644 index 0000000..f37bb46 --- /dev/null +++ b/client/src/components/auth/login-form.tsx @@ -0,0 +1,97 @@ +import React, { FC, useCallback } from 'react'; +import styled from 'styled-components'; +import baedal from 'assets/icons/baedalee.png'; +import github from 'assets/icons/github.png'; +import { useHistory } from 'lib/router'; +import LoginButton from './login-button'; +import LoginInput from './login-input'; + +const Div = styled.div` + display: flex; + flex-direction: column; + + ${({ theme }) => theme.mobile} { + width: 100%; + box-sizing: border-box; + } + ${({ theme }) => theme.tablet} { + margin: 15px; + max-width: 380px; + } + ${({ theme }) => theme.laptop} { + width: 380px; + } +`; + +const Form = styled.form` + display: flex; + flex-direction: column; +`; + +const Image = styled.img` + ${({ theme }) => theme.mobile} { + width: 40px; + } + ${({ theme }) => theme.tablet} { + width: 44px; + } + ${({ theme }) => theme.laptop} { + width: 48px; + } + margin-right: 10px; +`; + +const Error = styled.div` + color: ${props => props.theme.colorError}; + margin-top: 20px; + display: flex; + text-indent: 5px; +`; + +interface LoginProps { + id: string; + password: string; + onChange: (e: React.ChangeEvent) => void; + onSubmit: (e: React.FormEvent) => void; + error: string | null; + loading: boolean; +} + +const LoginForm: FC = ({ id, password, onChange, onSubmit, error, loading }) => { + const history = useHistory(); + const onClick = useCallback(() => { + history.push('/signup'); + }, [history]); + + return ( +
+
+ {loading &&
로딩중~~
} + + + {error} + + 배달이 + 로그인 + + + + 배달이 + 깃-헙으로 로그인 + + + 배달이 + 배민문구사로 회원가입 + +
+ ); +}; + +export default LoginForm; diff --git a/client/src/components/auth/login-input.tsx b/client/src/components/auth/login-input.tsx new file mode 100644 index 0000000..02cfbca --- /dev/null +++ b/client/src/components/auth/login-input.tsx @@ -0,0 +1,28 @@ +import styled from 'styled-components'; + +const LoginInput = styled.input` + font-family: ${props => props.theme.fontHannaAir}; + line-height: 1.5; + border: 0; + border-bottom: 1px solid ${({ theme }) => theme.colorInputLine}; + color: ${({ theme }) => theme.colorSoftBlack}; + text-indent: 5px; + background-color: transparent; + &::placeholder { + color: ${({ theme }) => theme.colorPlaceholder}; + } + &:not(:first-child) { + margin-top: 20px; + } + ${({ theme }) => theme.mobile} { + font-size: 20px; + } + ${({ theme }) => theme.tablet} { + font-size: 23px; + } + ${({ theme }) => theme.laptop} { + font-size: 26px; + } +`; + +export default LoginInput; diff --git a/client/src/components/common/__test__/logo.test.tsx b/client/src/components/common/__test__/logo.test.tsx new file mode 100644 index 0000000..69bce2e --- /dev/null +++ b/client/src/components/common/__test__/logo.test.tsx @@ -0,0 +1,10 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import Logo from '../logo'; + +describe('', () => { + it('matches snapshot', () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/client/src/components/common/__test__/navbar.test.tsx b/client/src/components/common/__test__/navbar.test.tsx new file mode 100644 index 0000000..f07bad2 --- /dev/null +++ b/client/src/components/common/__test__/navbar.test.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import Navbar from '../navbar'; + +describe('', () => { + it('matches snapshot', () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + + it('matches snapshot mobile', () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/client/src/components/common/layout.tsx b/client/src/components/common/layout.tsx deleted file mode 100644 index 1c8d63b..0000000 --- a/client/src/components/common/layout.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React, { ReactElement } from 'react'; - -const Layout = (): ReactElement => { - return ( -
-

layout

-
- ); -}; - -export default Layout; diff --git a/client/src/components/common/logo.tsx b/client/src/components/common/logo.tsx new file mode 100644 index 0000000..2f7a276 --- /dev/null +++ b/client/src/components/common/logo.tsx @@ -0,0 +1,33 @@ +import React, { FC } from 'react'; +import styled from 'styled-components'; + +import LogoImg from 'assets/images/logo.png'; +import LogoTentImg from 'assets/images/logo_tent.png'; +import LogoMobile from 'assets/icons/logo_mobile.png'; + +interface LogoProps { + className?: string; + width?: string; + full?: boolean; + mobile?: boolean; +} + +const Wrapper = styled.div` + width: fit-content; +`; + +const Logo: FC = ({ className = '', width = '350px', full = false, mobile = false }) => { + const getLogoSrc = (): string => { + if (mobile) return LogoMobile; + if (full) return LogoTentImg; + return LogoImg; + }; + + return ( + + logo + + ); +}; + +export default Logo; diff --git a/client/src/components/common/navbar.tsx b/client/src/components/common/navbar.tsx new file mode 100644 index 0000000..0fb18a5 --- /dev/null +++ b/client/src/components/common/navbar.tsx @@ -0,0 +1,76 @@ +import React, { FC } from 'react'; +import { Link } from 'lib/router'; +import styled from 'styled-components'; +import { Logo } from 'components'; + +import accountIcon from 'assets/icons/account.png'; +import cartIcon from 'assets/icons/cart.png'; +import logoutIcon from 'assets/icons/logout.png'; + +interface NavbarProps { + white?: boolean; + mobile?: boolean; +} + +interface WrapperStyleProps { + white: boolean; +} + +const Wrapper = styled.nav` + background-color: ${props => (props.white ? props.theme.colorWhite : props.theme.colorBg)}; + border-bottom: 1px solid ${props => props.theme.colorLineLight}; + padding: 10px 10%; + display: flex; + justify-content: flex-end; + position: relative; + + .nav-link { + font-size: 12px; + font-weight: ${props => props.theme.weightMid}; + color: ${props => props.theme.colorGreyDark}; + text-decoration: none; + padding: 0 14px; + } + + .nav-link:hover { + color: ${props => props.theme.colorGreyMid}; + } + + ${props => props.theme.mobile} { + background-color: ${props => props.theme.colorWhite}; + border: none; + box-shadow: 0px 1px 8px rgba(0, 0, 0, 0.2); + justify-content: space-between; + align-items: center; + padding: 14px 5%; + + .nav-link { + padding: 0 8px; + } + } +`; + +const Navbar: FC = ({ white = false, mobile = false }) => { + return ( + + {mobile && ( + + + + )} +
+ + {mobile ? user : '마이페이지'} + + + {mobile ? cart : '장바구니'} + + + {mobile ? logout : '로그아웃'} + +
+
+ ); +}; + +export default Navbar; diff --git a/client/src/components/index.ts b/client/src/components/index.ts new file mode 100644 index 0000000..f65aade --- /dev/null +++ b/client/src/components/index.ts @@ -0,0 +1,4 @@ +export { default as Logo } from './common/logo'; +export { default as Navbar } from './common/navbar'; + +export { default as Layout } from './layout'; diff --git a/client/src/components/layout/__test__/footer.test.tsx b/client/src/components/layout/__test__/footer.test.tsx new file mode 100644 index 0000000..3de8a0b --- /dev/null +++ b/client/src/components/layout/__test__/footer.test.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import Footer from '../footer'; + +describe('