├── .dockerignore ├── .gitignore ├── API.md ├── Dockerfile ├── README.md ├── app.py ├── exception.py ├── model.py ├── package-lock.json ├── package.json ├── requirements.txt └── results ├── AnJaeSeongS2 ├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .postcssrc.js ├── .prettierrc ├── README.md ├── babel.config.js ├── cypress.json ├── doc │ └── image │ │ ├── login.png │ │ └── userInfo.png ├── jest.config.js ├── package.json ├── pilot-auth api.postman_collection.json ├── public │ ├── favicon.ico │ └── icons │ │ ├── favicon-128x128.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ └── favicon-96x96.png ├── quasar.conf.js ├── quasar.extensions.json ├── quasar.testing.json ├── src │ ├── App.vue │ ├── assets │ │ └── quasar-logo-vertical.svg │ ├── boot │ │ ├── .gitkeep │ │ └── axios.ts │ ├── components │ │ └── models.ts │ ├── css │ │ ├── app.scss │ │ └── quasar.variables.scss │ ├── index.template.html │ ├── layouts │ │ └── MainLayout.vue │ ├── pages │ │ ├── Error404.vue │ │ ├── Index.vue │ │ ├── Login.vue │ │ └── users │ │ │ ├── Info.vue │ │ │ └── InfoItem.vue │ ├── router │ │ ├── index.ts │ │ └── routes.ts │ ├── shims-vue.d.ts │ └── store │ │ ├── index.ts │ │ ├── loginToken │ │ ├── actions.ts │ │ ├── getters.ts │ │ ├── index.ts │ │ ├── mutations.ts │ │ └── state.ts │ │ └── store-flag.d.ts ├── test │ ├── cypress │ │ ├── .eslintrc.js │ │ ├── .gitignore │ │ ├── fixtures │ │ │ └── example.json │ │ ├── integration │ │ │ └── home.spec.ts │ │ ├── plugins │ │ │ └── index.ts │ │ ├── support │ │ │ ├── commands.ts │ │ │ └── index.ts │ │ └── tsconfig.json │ └── jest │ │ ├── .eslintrc.js │ │ ├── .gitignore │ │ ├── __tests__ │ │ └── pages │ │ │ └── users │ │ │ └── Info.test.ts │ │ └── jest.setup.ts └── tsconfig.json ├── Kim-Jaemin420 └── pilot-react │ ├── .eslintrc │ ├── .gitignore │ ├── .nvmrc │ ├── .prettierrc │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt │ ├── src │ ├── App.test.js │ ├── App.tsx │ ├── FetchData │ │ ├── HttpFetch.ts │ │ ├── LoginData.ts │ │ └── UserData.ts │ ├── components │ │ ├── Home.tsx │ │ ├── Login.tsx │ │ └── common │ │ │ └── CommonBtn.tsx │ ├── hooks │ │ └── useInputChange.ts │ ├── index.tsx │ └── styles │ │ └── GlobalStyle.ts │ └── tsconfig.json ├── boksilab ├── .firebase │ └── hosting.YnVpbGQ.cache ├── .firebaserc ├── .gitignore ├── README.md ├── firebase.json ├── package-lock.json ├── package.json ├── public │ ├── Login.gltf │ ├── favicon.ico │ ├── font │ │ ├── D2.json │ │ └── Godo.json │ ├── image │ │ ├── blackhole.png │ │ └── skybox │ │ │ ├── B.jpg │ │ │ ├── D.jpg │ │ │ ├── F.jpg │ │ │ ├── L.jpg │ │ │ ├── R.jpg │ │ │ └── U.jpg │ ├── index.html │ └── sfx │ │ ├── fall1.wav │ │ ├── fall2.wav │ │ ├── fall3.wav │ │ └── fall4.wav ├── src │ ├── Api.tsx │ ├── App.test.tsx │ ├── App.tsx │ ├── Godo.ttf │ ├── Phase.ts │ ├── Response.ts │ ├── TabIndex.ts │ ├── UserInfo.ts │ ├── components │ │ ├── Blackhole.tsx │ │ ├── Button.tsx │ │ ├── Camera.tsx │ │ ├── Canvas.tsx │ │ ├── Card.tsx │ │ ├── Character.tsx │ │ ├── Credit.tsx │ │ ├── InputField.tsx │ │ ├── Lights.tsx │ │ ├── LogoutButton.tsx │ │ ├── ProgressBar.tsx │ │ ├── Skybox.tsx │ │ ├── Sound.tsx │ │ ├── StaticText.tsx │ │ ├── Text.tsx │ │ ├── TextStatic.tsx │ │ ├── UserInfoView.tsx │ │ └── Warp.tsx │ ├── index.css │ ├── index.tsx │ ├── react-app-env.d.ts │ ├── reportWebVitals.ts │ └── setupTests.ts └── tsconfig.json ├── byeongukchoi ├── .browserslistrc ├── .eslintrc.js ├── .gitignore ├── README.md ├── babel.config.js ├── package.json ├── public │ ├── favicon.ico │ └── index.html ├── src │ ├── App.vue │ ├── api │ │ └── index.ts │ ├── assets │ │ └── logo.png │ ├── components │ │ └── Profile.vue │ ├── main.ts │ ├── models │ │ ├── LoginRequest.ts │ │ ├── LoginResponse.ts │ │ ├── Token.ts │ │ └── User.ts │ ├── router │ │ └── index.ts │ ├── shims-tsx.d.ts │ ├── shims-vue.d.ts │ ├── store │ │ └── index.ts │ ├── utils │ │ └── cookies.ts │ └── views │ │ ├── Home.vue │ │ └── Login.vue ├── tests │ └── unit │ │ └── example.spec.ts └── tsconfig.json ├── cozy60 ├── .gitignore ├── .prettierrc ├── README.md ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt ├── src │ ├── App.css │ ├── App.test.tsx │ ├── App.tsx │ ├── components │ │ ├── Button │ │ │ ├── Button.tsx │ │ │ └── index.ts │ │ ├── Card │ │ │ ├── Card.tsx │ │ │ └── index.ts │ │ ├── ErrorMessage │ │ │ ├── ErrorMessage.tsx │ │ │ └── index.ts │ │ ├── Footer │ │ │ ├── Footer.tsx │ │ │ └── index.ts │ │ ├── Form │ │ │ ├── Form.tsx │ │ │ └── index.ts │ │ ├── Input │ │ │ ├── Input.tsx │ │ │ └── index.ts │ │ ├── Layouts │ │ │ ├── Container.tsx │ │ │ └── index.ts │ │ └── UserInfo │ │ │ ├── UserInfo.tsx │ │ │ └── index.ts │ ├── index.css │ ├── index.tsx │ ├── library │ │ ├── api │ │ │ ├── apiClient.ts │ │ │ └── auth │ │ │ │ └── auth.ts │ │ ├── styles │ │ │ └── palette.ts │ │ └── utils │ │ │ └── children.ts │ ├── pages │ │ ├── LoginPage.tsx │ │ └── UserInfoPage.tsx │ ├── react-app-env.d.ts │ └── setupTests.ts └── tsconfig.json ├── hayoung-jeremy ├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt ├── src │ ├── App.test.tsx │ ├── App.tsx │ ├── components │ │ ├── button │ │ │ ├── Button.tsx │ │ │ └── index.ts │ │ ├── form │ │ │ ├── Form.tsx │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── input │ │ │ ├── Input.tsx │ │ │ └── index.ts │ │ └── pageTemplate │ │ │ ├── PageTemplate.tsx │ │ │ └── index.ts │ ├── index.tsx │ ├── logo.svg │ ├── pages │ │ ├── Login │ │ │ ├── LoginPage.tsx │ │ │ └── index.ts │ │ ├── Profile │ │ │ ├── ProfilePage.tsx │ │ │ └── index.ts │ │ └── index.ts │ ├── react-app-env.d.ts │ ├── reportWebVitals.ts │ ├── service │ │ └── api.ts │ ├── setupTests.ts │ ├── store │ │ ├── authSlice.ts │ │ ├── loginSlice.ts │ │ ├── rootReducer.ts │ │ └── store.ts │ ├── style │ │ ├── GlobalStyle.ts │ │ ├── index.ts │ │ └── palette.ts │ └── types │ │ └── auth.ts └── tsconfig.json ├── hojongs ├── .browserslistrc ├── .eslintrc.js ├── .gitignore ├── README.md ├── jest.config.js ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ └── index.html ├── src │ ├── config.ts │ ├── dto │ │ ├── auth.ts │ │ └── user.ts │ ├── entry │ │ ├── main.ts │ │ └── user.ts │ ├── service │ │ ├── api_service.ts │ │ └── url_param_service.ts │ ├── shims-tsx.d.ts │ ├── shims-vue.d.ts │ └── view │ │ ├── Login.vue │ │ └── User.vue ├── tests │ └── unit │ │ └── service │ │ └── api_service.spec.ts ├── tsconfig.json └── vue.config.js ├── imhojeong ├── .eslinitignore ├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── README.md ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt ├── src │ ├── apis │ │ └── modules │ │ │ └── auth.ts │ ├── app │ │ ├── App.css │ │ ├── App.test.tsx │ │ ├── App.tsx │ │ ├── hooks.ts │ │ ├── react-app-env.d.ts │ │ └── setupTests.ts │ ├── components │ │ ├── LoginContainer.tsx │ │ └── UserContainer.tsx │ ├── index.css │ ├── index.tsx │ ├── pages │ │ ├── LoginPage.tsx │ │ └── UserInfoPage.tsx │ ├── react-app-env.d.ts │ ├── reducers │ │ └── user.ts │ ├── reportWebVitals.ts │ ├── routes │ │ └── index.tsx │ ├── store │ │ └── store.ts │ └── styles │ │ ├── global-style.ts │ │ ├── styled.d.ts │ │ └── theme.ts └── tsconfig.json ├── jho2301 ├── .eslintrc.json ├── .prettierrc ├── .storybook │ ├── main.js │ └── preview.js ├── README.md ├── REQUIREMENTS.md ├── package.json ├── public │ └── index.html ├── src │ ├── App.tsx │ ├── Global.styles.ts │ ├── __test__ │ │ ├── login.test.tsx │ │ ├── setupTests.ts │ │ ├── testUtil.tsx │ │ └── user.test.tsx │ ├── components │ │ ├── @shared │ │ │ ├── Button │ │ │ │ ├── Button.stories.tsx │ │ │ │ ├── Button.styles.ts │ │ │ │ └── Button.tsx │ │ │ ├── Input │ │ │ │ ├── Input.stories.tsx │ │ │ │ ├── Input.styles.ts │ │ │ │ └── Input.tsx │ │ │ └── Template │ │ │ │ ├── Template.styles.ts │ │ │ │ └── Template.tsx │ │ ├── Login │ │ │ └── Form │ │ │ │ ├── LoginForm.stories.tsx │ │ │ │ ├── LoginForm.styles.ts │ │ │ │ └── LoginForm.tsx │ │ ├── PrivateRoute │ │ │ └── PrivateRoute.tsx │ │ └── User │ │ │ └── UserInfo │ │ │ ├── UserInfo.stories.tsx │ │ │ ├── UserInfo.styles.ts │ │ │ └── UserInfo.tsx │ ├── constants │ │ ├── palette.ts │ │ └── storage.ts │ ├── index.tsx │ ├── mock │ │ ├── handlers.ts │ │ └── server.ts │ ├── pages │ │ ├── Login │ │ │ ├── LoginPage.stories.tsx │ │ │ └── LoginPage.tsx │ │ └── User │ │ │ ├── UserPage.stories.tsx │ │ │ └── UserPage.tsx │ ├── service │ │ ├── auth.ts │ │ ├── hooks │ │ │ ├── useAuth.ts │ │ │ ├── useLoginForm.ts │ │ │ └── useUser.ts │ │ └── request │ │ │ ├── index.ts │ │ │ ├── login.ts │ │ │ └── user.ts │ ├── state │ │ ├── login.ts │ │ └── user.ts │ ├── types.ts │ └── util │ │ └── API.ts ├── tsconfig.json └── webpack.config.ts ├── kimbiyam ├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt ├── src │ ├── App.tsx │ ├── api │ │ ├── apiClient.ts │ │ ├── authApi.ts │ │ └── userApi.ts │ ├── components │ │ ├── LoadingBackdrop.tsx │ │ ├── LoginForm.tsx │ │ ├── MainButton.tsx │ │ ├── MainTextField.tsx │ │ ├── PrivateRoute.tsx │ │ └── UserProfile.tsx │ ├── constants │ │ └── constants.ts │ ├── hooks │ │ ├── __test__ │ │ │ ├── useCheckUserEffect.test.tsx │ │ │ ├── useInput.test.tsx │ │ │ ├── useLogin.test.tsx │ │ │ └── useUserProfileQuery.test.tsx │ │ ├── useCheckUserEffect.ts │ │ ├── useInput.ts │ │ ├── useLogin.ts │ │ └── useUserProfileQuery.ts │ ├── index.tsx │ ├── models │ │ ├── LoginData.ts │ │ └── User.ts │ ├── pages │ │ ├── LoginPage.tsx │ │ ├── NotFoundPage.tsx │ │ └── UserProfilePage.tsx │ ├── react-app-env.d.ts │ ├── reportWebVitals.ts │ ├── setupTests.ts │ ├── styles │ │ └── globalTheme.ts │ └── utils │ │ └── tokenStorage.ts └── tsconfig.json ├── leehaeun0 ├── .env.development ├── .env.production ├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── README.md ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt ├── src │ ├── App.test.tsx │ ├── App.tsx │ ├── apis │ │ └── api.ts │ ├── components │ │ ├── Button.tsx │ │ ├── CenterBox.tsx │ │ ├── FormInput.tsx │ │ ├── LoginForm.tsx │ │ ├── Main.tsx │ │ ├── ReactHelmet.tsx │ │ └── UserInfo.tsx │ ├── hooks │ │ └── useAsync.ts │ ├── index.tsx │ ├── pages │ │ ├── LoadingPage.tsx │ │ ├── LoginPage.tsx │ │ └── UserPage.tsx │ ├── react-app-env.d.ts │ ├── reportWebVitals.ts │ ├── routes │ │ ├── MainRouter.tsx │ │ ├── PrivateRoute.tsx │ │ └── PublicRoute.tsx │ ├── setupTests.ts │ ├── styles │ │ ├── GlobalStyle.ts │ │ └── theme.ts │ └── utils │ │ ├── auth.ts │ │ └── img │ │ ├── profile-image.png │ │ └── result.gif └── tsconfig.json └── rolancia ├── .env.development ├── .gitignore ├── README.md ├── package.json ├── public ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png └── manifest.json ├── src ├── App.module.css ├── App.test.tsx ├── App.tsx ├── components │ ├── Login │ │ ├── Login.module.css │ │ └── Login.tsx │ └── UserInfo │ │ ├── UserInfo.module.css │ │ └── UserInfo.tsx ├── index.css ├── index.tsx ├── model │ ├── entity.ts │ └── interfaces.ts ├── react-app-env.d.ts ├── service │ └── httpClient.ts ├── setupTests.ts └── test │ └── httpClient.test.ts └── tsconfig.json /.dockerignore: -------------------------------------------------------------------------------- 1 | results 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3 2 | 3 | WORKDIR /app 4 | 5 | COPY . /app 6 | 7 | RUN pip install --no-cache-dir -r requirements.txt 8 | 9 | EXPOSE 5000 10 | 11 | CMD ["python", "./app.py"] 12 | -------------------------------------------------------------------------------- /exception.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from abc import ABCMeta, abstractproperty 4 | 5 | 6 | class PilotException(Exception, metaclass=ABCMeta): 7 | 8 | errors = None 9 | 10 | def __init__(self, errors=None): 11 | self.errors = errors 12 | super().__init__(self.message) 13 | 14 | @abstractproperty 15 | def code(self): 16 | pass 17 | 18 | @abstractproperty 19 | def message(self): 20 | pass 21 | 22 | 23 | class Unauthorized(PilotException): 24 | 25 | @property 26 | def code(self): 27 | return 401 28 | 29 | @property 30 | def message(self): 31 | return "로그인이 필요합니다." 32 | 33 | def __str__(self): 34 | return self.__class__.__name__ 35 | 36 | 37 | class AccessDenied(PilotException): 38 | 39 | @property 40 | def code(self): 41 | return 403 42 | 43 | @property 44 | def message(self): 45 | return "접근할 수 없습니다." 46 | 47 | 48 | class InvalidLogin(PilotException): 49 | 50 | @property 51 | def code(self): 52 | return 400 53 | 54 | @property 55 | def message(self): 56 | return "아이디 혹은 비밀번호가 옳바르지 않습니다." 57 | 58 | 59 | class InvalidRequest(PilotException): 60 | 61 | @property 62 | def code(self): 63 | return 400 64 | 65 | @property 66 | def message(self): 67 | return "입력값을 확인해주세요." 68 | -------------------------------------------------------------------------------- /model.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from marshmallow import Schema, fields, validate, EXCLUDE 4 | 5 | 6 | class Login(Schema): 7 | class Meta: 8 | unknown = EXCLUDE 9 | 10 | account = fields.Str(required=True, 11 | error_messages={"required": "아이디를 입력해주세요."}, 12 | validate=[validate.Length(min=1, max=10, error="1~3글자로 입력해주세요")]) 13 | password = fields.Str(required=True, 14 | error_messages={"required": "비밀번호를 입력해주세요."}) 15 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pilot-react", 3 | "lockfileVersion": 2, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "dependencies": { 8 | "prettier": "^2.3.2" 9 | } 10 | }, 11 | "node_modules/prettier": { 12 | "version": "2.3.2", 13 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz", 14 | "integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==", 15 | "bin": { 16 | "prettier": "bin-prettier.js" 17 | }, 18 | "engines": { 19 | "node": ">=10.13.0" 20 | } 21 | } 22 | }, 23 | "dependencies": { 24 | "prettier": { 25 | "version": "2.3.2", 26 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz", 27 | "integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==" 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "prettier": "^2.3.2" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==2.0.1 2 | marshmallow==3.12.1 3 | Flask-Cors==3.0.10 4 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["@babel/plugin-syntax-dynamic-import"], 3 | "env": { 4 | "test": { 5 | "plugins": ["dynamic-import-node"], 6 | "presets": [ 7 | [ 8 | "@babel/preset-env", 9 | { 10 | "modules": "commonjs", 11 | "targets": { 12 | "node": "current" 13 | } 14 | } 15 | ] 16 | ] 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/.eslintignore: -------------------------------------------------------------------------------- 1 | /dist 2 | /src-bex/www 3 | /src-capacitor 4 | /src-cordova 5 | /.quasar 6 | /node_modules 7 | .eslintrc.js 8 | babel.config.js 9 | /src-ssr -------------------------------------------------------------------------------- /results/AnJaeSeongS2/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .thumbs.db 3 | node_modules 4 | 5 | # Quasar core related directories 6 | .quasar 7 | /dist 8 | 9 | # Cordova related directories and files 10 | /src-cordova/node_modules 11 | /src-cordova/platforms 12 | /src-cordova/plugins 13 | /src-cordova/www 14 | 15 | # Capacitor related directories and files 16 | /src-capacitor/www 17 | /src-capacitor/node_modules 18 | 19 | # BEX related directories and files 20 | /src-bex/www 21 | /src-bex/js/core 22 | 23 | # Log files 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # Editor directories and files 29 | .idea 30 | *.suo 31 | *.ntvs* 32 | *.njsproj 33 | *.sln 34 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | plugins: [ 5 | // to edit target browsers: use "browserslist" field in package.json 6 | require('autoprefixer') 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "semi": true 4 | } 5 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/README.md: -------------------------------------------------------------------------------- 1 | # Pilot-auth-ui app 2 | 3 | ## 개요 4 | [Quasar Framework v2](https://quasar.dev/) 을 사용한 app 입니다. 따라서, vue.js v3 과 webpack v5 이 사용됐습니다. 5 | 6 | 1. postman을 사용하길 원한다면, [pilot-auth api.postman_collection.json](./pilot-auth api.postman_collection.json) 을 import하길 바랍니다. 7 | 2. 현재 server host를 http://localhost:5000 으로 가정하고 작성된 소스코드입니다. 따라서, 바꾸고 싶다면, [src/boot/axios.ts](./src/boot/axios.ts) 파일의 baseURL 값을 변경 바랍니다. 8 | 3. 앱 사진: 9 | 10 | 로그인 페이지 | 사용자 정보 페이지 11 | :-------------------------:|:-------------------------: 12 | ![로그인 페이지](./doc/image/login.png "로그인 페이지") | ![사용자 정보 페이지](./doc/image/userInfo.png "사용자 정보 페이지") 13 | 14 | [comment]: <> () 15 | 16 | ## Install the dependencies 17 | ```bash 18 | yarn 19 | ``` 20 | 21 | ### Start the app in development mode (hot-code reloading, error reporting, etc.) 22 | ```bash 23 | quasar dev 24 | ``` 25 | 26 | ### Lint the files 27 | ```bash 28 | yarn run lint 29 | ``` 30 | 31 | ### Build the app for production 32 | ```bash 33 | quasar build 34 | ``` 35 | 36 | ### Customize the configuration 37 | See [Configuring quasar.conf.js](https://v2.quasar.dev/quasar-cli/quasar-conf-js). 38 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/babel.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | // eslint-disable-next-line @typescript-eslint/no-var-requires 3 | const fs = require('fs-extra'); 4 | let extend = undefined; 5 | 6 | /** 7 | * The .babelrc file has been created to assist Jest for transpiling. 8 | * You should keep your application's babel rules in this file. 9 | */ 10 | 11 | if (fs.existsSync('./.babelrc')) { 12 | extend = './.babelrc'; 13 | } 14 | 15 | module.exports = { 16 | presets: ['@quasar/babel-preset-app'], 17 | extends: extend, 18 | }; 19 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "http://localhost:8080/", 3 | "fixturesFolder": "test/cypress/fixtures", 4 | "integrationFolder": "test/cypress/integration", 5 | "pluginsFile": "test/cypress/plugins/index.ts", 6 | "screenshotsFolder": "test/cypress/screenshots", 7 | "supportFile": "test/cypress/support/index.ts", 8 | "videosFolder": "test/cypress/videos", 9 | "video": true 10 | } 11 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/doc/image/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/AnJaeSeongS2/doc/image/login.png -------------------------------------------------------------------------------- /results/AnJaeSeongS2/doc/image/userInfo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/AnJaeSeongS2/doc/image/userInfo.png -------------------------------------------------------------------------------- /results/AnJaeSeongS2/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/AnJaeSeongS2/public/favicon.ico -------------------------------------------------------------------------------- /results/AnJaeSeongS2/public/icons/favicon-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/AnJaeSeongS2/public/icons/favicon-128x128.png -------------------------------------------------------------------------------- /results/AnJaeSeongS2/public/icons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/AnJaeSeongS2/public/icons/favicon-16x16.png -------------------------------------------------------------------------------- /results/AnJaeSeongS2/public/icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/AnJaeSeongS2/public/icons/favicon-32x32.png -------------------------------------------------------------------------------- /results/AnJaeSeongS2/public/icons/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/AnJaeSeongS2/public/icons/favicon-96x96.png -------------------------------------------------------------------------------- /results/AnJaeSeongS2/quasar.extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "@quasar/testing-e2e-cypress": { 3 | "options": [ 4 | "scripts", 5 | "typescript" 6 | ] 7 | }, 8 | "@quasar/testing-security": { 9 | "options": [], 10 | "zapbrowser": "Chrome" 11 | }, 12 | "@quasar/testing": { 13 | "harnesses": [ 14 | "unit-jest", 15 | "e2e-cypress", 16 | "security" 17 | ] 18 | }, 19 | "@quasar/testing-unit-jest": { 20 | "babel": "babelrc", 21 | "options": [ 22 | "scripts", 23 | "typescript" 24 | ] 25 | } 26 | } -------------------------------------------------------------------------------- /results/AnJaeSeongS2/quasar.testing.json: -------------------------------------------------------------------------------- 1 | { 2 | "unit-jest": { 3 | "runnerCommand": "jest --ci" 4 | }, 5 | "e2e-cypress": { 6 | "runnerCommand": "cross-env E2E_TEST=true start-test \"quasar dev\" http-get://localhost:8080 \"cypress run\"" 7 | } 8 | } -------------------------------------------------------------------------------- /results/AnJaeSeongS2/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 20 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/src/boot/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/AnJaeSeongS2/src/boot/.gitkeep -------------------------------------------------------------------------------- /results/AnJaeSeongS2/src/boot/axios.ts: -------------------------------------------------------------------------------- 1 | import { boot } from 'quasar/wrappers'; 2 | import axios, { AxiosInstance } from 'axios'; 3 | 4 | declare module '@vue/runtime-core' { 5 | interface ComponentCustomProperties { 6 | $axios: AxiosInstance; 7 | } 8 | } 9 | 10 | // Be careful when using SSR for cross-request state pollution 11 | // due to creating a Singleton instance here; 12 | // If any client changes this (global) instance, it might be a 13 | // good idea to move this instance creation inside of the 14 | // "export default () => {}" function below (which runs individually 15 | // for each client) 16 | const api = axios.create({ 17 | baseURL: 'http://localhost:5000', 18 | }); 19 | 20 | export default boot(({app}) => { 21 | // for use inside Vue files (Options API) through this.$axios and this.$api 22 | 23 | app.config.globalProperties.$axios = axios; 24 | // ^ ^ ^ this will allow you to use this.$axios (for Vue Options API form) 25 | // so you won't necessarily have to import axios in each vue file 26 | 27 | app.config.globalProperties.$api = api; 28 | // ^ ^ ^ this will allow you to use this.$api (for Vue Options API form) 29 | // so you can easily perform requests against your app's API 30 | }); 31 | 32 | export { api }; 33 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/src/components/models.ts: -------------------------------------------------------------------------------- 1 | export interface UserLoginFormat { 2 | account: string, 3 | password: string, 4 | } 5 | 6 | export interface LoginToken { 7 | accessToken: string, 8 | } 9 | 10 | export interface User { 11 | account: string, 12 | name: string, 13 | id: number, 14 | level: number, 15 | } 16 | 17 | export interface Response { 18 | code: number, 19 | message: string, 20 | validate: unknown, 21 | } 22 | 23 | export interface InfoItem { 24 | iconName: string, 25 | colorName: string, 26 | textLabel: string, 27 | textBody: string, 28 | } 29 | 30 | export interface Error { 31 | code: number, 32 | message: string, 33 | } 34 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/src/css/app.scss: -------------------------------------------------------------------------------- 1 | // app global css in SCSS form 2 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/src/css/quasar.variables.scss: -------------------------------------------------------------------------------- 1 | // Quasar SCSS (& Sass) Variables 2 | // -------------------------------------------------- 3 | // To customize the look and feel of this app, you can override 4 | // the Sass/SCSS variables found in Quasar's source Sass/SCSS files. 5 | 6 | // Check documentation for full list of Quasar variables 7 | 8 | // Your own variables (that are declared here) and Quasar's own 9 | // ones will be available out of the box in your .vue/.scss/.sass files 10 | 11 | // It's highly recommended to change the default colors 12 | // to match your app's branding. 13 | // Tip: Use the "Theme Builder" on Quasar's documentation website. 14 | 15 | $primary : #1976D2; 16 | $secondary : #26A69A; 17 | $accent : #9C27B0; 18 | 19 | $dark : #1D1D1D; 20 | 21 | $positive : #21BA45; 22 | $negative : #C10015; 23 | $info : #31CCEC; 24 | $warning : #F2C037; 25 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/src/index.template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <%= productName %> 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/src/pages/Error404.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 32 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/src/pages/Index.vue: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 25 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/src/pages/users/InfoItem.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 39 | 40 | 43 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/src/router/index.ts: -------------------------------------------------------------------------------- 1 | import { route } from 'quasar/wrappers'; 2 | import { 3 | createMemoryHistory, 4 | createRouter, 5 | createWebHashHistory, 6 | createWebHistory, 7 | } from 'vue-router'; 8 | import { StateInterface } from '../store'; 9 | import routes from './routes'; 10 | 11 | /* 12 | * If not building with SSR mode, you can 13 | * directly export the Router instantiation; 14 | * 15 | * The function below can be async too; either use 16 | * async/await or return a Promise which resolves 17 | * with the Router instance. 18 | */ 19 | 20 | export default route(function (/* { store, ssrContext } */) { 21 | const createHistory = process.env.SERVER 22 | ? createMemoryHistory 23 | : (process.env.VUE_ROUTER_MODE === 'history' ? createWebHistory : createWebHashHistory); 24 | 25 | const Router = createRouter({ 26 | scrollBehavior: () => ({left: 0, top: 0}), 27 | routes, 28 | 29 | // Leave this as is and make changes in quasar.conf.js instead! 30 | // quasar.conf.js -> build -> vueRouterMode 31 | // quasar.conf.js -> build -> publicPath 32 | history: createHistory( 33 | process.env.MODE === 'ssr' ? void 0 : process.env.VUE_ROUTER_BASE, 34 | ), 35 | }); 36 | 37 | return Router; 38 | }); 39 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/src/router/routes.ts: -------------------------------------------------------------------------------- 1 | import { RouteRecordRaw } from 'vue-router'; 2 | 3 | const routes: RouteRecordRaw[] = [ 4 | { 5 | path: '/', 6 | component: () => import('layouts/MainLayout.vue'), 7 | redirect: '/users/me', 8 | children: [{ 9 | path: 'users/me', 10 | component: () => import('pages/users/Info.vue'), 11 | }, { 12 | path: 'login', 13 | component: () => import('pages/Login.vue'), 14 | }], 15 | }, 16 | 17 | // Always leave this as last one, 18 | // but you can also remove it 19 | { 20 | path: '/:catchAll(.*)*', 21 | component: () => import('pages/Error404.vue'), 22 | }, 23 | ]; 24 | 25 | export default routes; 26 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | // Mocks all files ending in `.vue` showing them as plain Vue instances 2 | declare module '*.vue' { 3 | import { ComponentOptions } from 'vue' 4 | const component: ComponentOptions 5 | export default component 6 | } -------------------------------------------------------------------------------- /results/AnJaeSeongS2/src/store/loginToken/actions.ts: -------------------------------------------------------------------------------- 1 | import { ActionTree } from 'vuex'; 2 | import { StateInterface } from '../index'; 3 | import { LoginToken } from './state'; 4 | 5 | const actions: ActionTree = { 6 | someAction(/* context */) { 7 | // your code 8 | }, 9 | }; 10 | 11 | export default actions; 12 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/src/store/loginToken/getters.ts: -------------------------------------------------------------------------------- 1 | import { GetterTree } from 'vuex'; 2 | import { StateInterface } from '../index'; 3 | import { LoginToken } from './state'; 4 | 5 | const getters: GetterTree = { 6 | someGetter(/* context */) { 7 | // your code 8 | }, 9 | }; 10 | 11 | export default getters; 12 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/src/store/loginToken/index.ts: -------------------------------------------------------------------------------- 1 | import { Module } from 'vuex'; 2 | import { StateInterface } from '../index'; 3 | import state, { LoginToken } from './state'; 4 | import actions from './actions'; 5 | import getters from './getters'; 6 | import mutations from './mutations'; 7 | 8 | const loginToken: Module = { 9 | namespaced: true, 10 | actions, 11 | getters, 12 | mutations, 13 | state, 14 | }; 15 | 16 | export default loginToken; 17 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/src/store/loginToken/mutations.ts: -------------------------------------------------------------------------------- 1 | import { MutationTree } from 'vuex'; 2 | import { LoginToken } from './state'; 3 | 4 | const mutation: MutationTree = { 5 | saveLoginToken(state: LoginToken, nextState: LoginToken) { 6 | state.accessToken = nextState.accessToken; 7 | localStorage.setItem('accessToken', state.accessToken); 8 | }, 9 | clearLoginToken(state: LoginToken) { 10 | state.accessToken = ''; 11 | localStorage.removeItem('accessToken'); 12 | }, 13 | }; 14 | 15 | export default mutation; 16 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/src/store/loginToken/state.ts: -------------------------------------------------------------------------------- 1 | import { LoginToken } from 'components/models'; 2 | 3 | function state(): LoginToken { 4 | return { 5 | accessToken: '', 6 | }; 7 | } 8 | 9 | export default state; 10 | export { LoginToken }; 11 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/src/store/store-flag.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | // THIS FEATURE-FLAG FILE IS AUTOGENERATED, 3 | // REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING 4 | import 'quasar/dist/types/feature-flag'; 5 | 6 | declare module 'quasar/dist/types/feature-flag' { 7 | interface QuasarFeatureFlags { 8 | store: true; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/test/cypress/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // ESLint "parserOptions" options should be overrided to point to the same tsconfig used 3 | // by fork-ts-checker (check the app extension "index.js") or type errors won't be emitted (only linting ones will) 4 | parserOptions: { 5 | project: './tsconfig.json', 6 | tsconfigRootDir: __dirname 7 | }, 8 | 9 | extends: [ 10 | // Add Cypress-specific lint rules, globals and Cypress plugin 11 | // See https://github.com/cypress-io/eslint-plugin-cypress#rules 12 | 'plugin:cypress/recommended' 13 | ] 14 | }; 15 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/test/cypress/.gitignore: -------------------------------------------------------------------------------- 1 | videos/* 2 | screenshots/* -------------------------------------------------------------------------------- /results/AnJaeSeongS2/test/cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } -------------------------------------------------------------------------------- /results/AnJaeSeongS2/test/cypress/plugins/index.ts: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | // *********************************************************** 3 | // This example plugins/index.ts can be used to load plugins 4 | // 5 | // You can change the location of this file or turn off loading 6 | // the plugins file with the 'pluginsFile' configuration option. 7 | // 8 | // You can read more here: 9 | // https://on.cypress.io/plugins-guide 10 | // *********************************************************** 11 | 12 | // This function is called when a project is opened or re-opened (e.g. due to 13 | // the project's config changing) 14 | 15 | // cypress/plugins/index.ts 16 | 17 | const pluginConfig: Cypress.PluginConfig = (/*on, config*/) => { 18 | // 19 | }; 20 | 21 | export default pluginConfig; 22 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/test/cypress/support/index.ts: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands'; 18 | 19 | const resizeObserverLoopError = 'ResizeObserver loop limit exceeded'; 20 | 21 | Cypress.on('uncaught:exception', (err) => { 22 | if (err.message.includes(resizeObserverLoopError)) { 23 | // returning false here prevents Cypress from 24 | // failing the test 25 | return false; 26 | } 27 | }); 28 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/test/cypress/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig", 3 | "compilerOptions": { 4 | // If you enabled IE support while creating the project, root tsconfig target is set to ES5 instead 5 | // Cypress tests and support files are written in ES6 and this option enforce the right target regardless of root configuration 6 | "target": "es6", 7 | // Importing "cypress" types into project-root tsconfig won't work for unknown reasons, 8 | // using folder-local tsconfig is better to avoid globals conflicts (eg. with Jest) 9 | "types": ["cypress"] 10 | }, 11 | // Reset excluded files list, as it excluded Cypress files in the first place 12 | // and other exclusions do not apply into tests nested folder 13 | "exclude": [] 14 | } 15 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/test/jest/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [ 3 | // Removes 'no-undef' lint errors for Jest global functions (`describe`, `it`, etc), 4 | // add Jest-specific lint rules and Jest plugin 5 | // See https://github.com/jest-community/eslint-plugin-jest#recommended 6 | 'plugin:jest/recommended', 7 | // Uncomment following line to apply style rules 8 | // 'plugin:jest/style', 9 | ], 10 | }; 11 | -------------------------------------------------------------------------------- /results/AnJaeSeongS2/test/jest/.gitignore: -------------------------------------------------------------------------------- 1 | coverage/* -------------------------------------------------------------------------------- /results/AnJaeSeongS2/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@quasar/app/tsconfig-preset", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "esModuleInterop": true, 6 | "types": [ 7 | "jest", 8 | "quasar" 9 | ] 10 | }, 11 | "exclude": [ 12 | "test/cypress", 13 | "/dist", 14 | ".quasar", 15 | "node_modules" 16 | ] 17 | } -------------------------------------------------------------------------------- /results/Kim-Jaemin420/pilot-react/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | .env 26 | -------------------------------------------------------------------------------- /results/Kim-Jaemin420/pilot-react/.nvmrc: -------------------------------------------------------------------------------- 1 | 14.15.1 2 | -------------------------------------------------------------------------------- /results/Kim-Jaemin420/pilot-react/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "typescript", 3 | "singleQuote": true, 4 | "printWidth": 110, 5 | "tabWidth": 2, 6 | "useTabs": false, 7 | "semi": true, 8 | "quoteProps": "as-needed", 9 | "jsxSingleQuote": true, 10 | "trailingComma": "all", 11 | "arrowParens": "always", 12 | "endOfLine": "auto", 13 | "bracketSpacing": true, 14 | "jsxBracketSameLine": false, 15 | "requirePragma": false, 16 | "insertPragma": false, 17 | "proseWrap": "preserve", 18 | "vueIndentScriptAndStyle": false 19 | } 20 | -------------------------------------------------------------------------------- /results/Kim-Jaemin420/pilot-react/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/Kim-Jaemin420/pilot-react/public/favicon.ico -------------------------------------------------------------------------------- /results/Kim-Jaemin420/pilot-react/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/Kim-Jaemin420/pilot-react/public/logo192.png -------------------------------------------------------------------------------- /results/Kim-Jaemin420/pilot-react/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/Kim-Jaemin420/pilot-react/public/logo512.png -------------------------------------------------------------------------------- /results/Kim-Jaemin420/pilot-react/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /results/Kim-Jaemin420/pilot-react/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /results/Kim-Jaemin420/pilot-react/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { renderHook, act } from '@testing-library/react-hooks'; 4 | 5 | import useInputChange from '../src/hooks/useInputChange'; 6 | 7 | test('**useInputChange test**', () => { 8 | const { result } = renderHook(({ initialValue }) => useInputChange(initialValue), { 9 | initialProps: {initialValue: ''} 10 | }); 11 | 12 | act(() => { 13 | result.current[1]({target: {value: 'hello'}}); 14 | }); 15 | 16 | expect(result.current[0]).toBe('hello'); 17 | }); 18 | 19 | 20 | -------------------------------------------------------------------------------- /results/Kim-Jaemin420/pilot-react/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Switch, Route, BrowserRouter } from 'react-router-dom'; 3 | 4 | import Login from './components/Login'; 5 | import Home from './components/Home'; 6 | 7 | 8 | const App = () => { 9 | return ( 10 | 11 | 12 | 13 | 14 | 15 | 16 | ); 17 | } 18 | 19 | export default App; 20 | -------------------------------------------------------------------------------- /results/Kim-Jaemin420/pilot-react/src/FetchData/HttpFetch.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | class HttpFetch { 4 | private readonly url: string; 5 | private readonly data: any; 6 | 7 | constructor(url: string, data: any = null) { 8 | this.url = url; 9 | this.data = data; 10 | } 11 | 12 | PostFetch = async () => { 13 | try { 14 | const res = await axios.post(this.url, this.data); 15 | return res.data; 16 | 17 | } catch (e) { 18 | console.error(e); 19 | return e.response.data; 20 | } 21 | }; 22 | 23 | GetFetch = async () => { 24 | try { 25 | const res = await axios.get(this.url,{ 26 | headers: { 27 | Authorization: `Bearer ${sessionStorage.getItem('token')}`, 28 | }, 29 | }); 30 | return res; 31 | } catch (e) { 32 | console.error(e); 33 | return e; 34 | } 35 | }; 36 | } 37 | 38 | export default HttpFetch; 39 | -------------------------------------------------------------------------------- /results/Kim-Jaemin420/pilot-react/src/FetchData/LoginData.ts: -------------------------------------------------------------------------------- 1 | export class LoginData { 2 | account: string; 3 | password: string; 4 | 5 | constructor(account: string, password: string) { 6 | this.account = account; 7 | this.password = password; 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /results/Kim-Jaemin420/pilot-react/src/FetchData/UserData.ts: -------------------------------------------------------------------------------- 1 | export class UserData { 2 | account: string; 3 | id: number; 4 | level: number; 5 | name: string; 6 | 7 | constructor(info: { account: string, id: number, level: number, name: string} | null) { 8 | this.account = info ? info.account : ''; 9 | this.id = info ? info.id : 0; 10 | this.level = info ? info.level : 0; 11 | this.name = info ? info.name : ''; 12 | } 13 | 14 | } 15 | 16 | -------------------------------------------------------------------------------- /results/Kim-Jaemin420/pilot-react/src/components/common/CommonBtn.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import { Button } from 'antd'; 3 | 4 | const CommonButton = styled(Button)` 5 | background-color: #409eff; 6 | color: #fff; 7 | width: 150px; 8 | text-align: center; 9 | margin: 0 auto; 10 | `; 11 | 12 | const CommonBtn = ({children, onClick, type, style}: any) => { 13 | return {children} 14 | }; 15 | 16 | export default CommonBtn; 17 | 18 | -------------------------------------------------------------------------------- /results/Kim-Jaemin420/pilot-react/src/hooks/useInputChange.ts: -------------------------------------------------------------------------------- 1 | import { useState, useCallback } from 'react'; 2 | 3 | const useInputChange = (initialState = '') => { 4 | const [input, setInput] = useState(initialState); 5 | 6 | const onChange = useCallback(({ target }) => { 7 | setInput(target.value); 8 | }, []); 9 | 10 | return [input, onChange, setInput] as const; 11 | }; 12 | 13 | export default useInputChange; 14 | -------------------------------------------------------------------------------- /results/Kim-Jaemin420/pilot-react/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import 'antd/dist/antd.css'; 4 | import GlobalStyle from './styles/GlobalStyle'; 5 | 6 | import App from './App'; 7 | 8 | ReactDOM.render( 9 | 10 | 11 | 12 | , 13 | document.getElementById('root') 14 | ); 15 | -------------------------------------------------------------------------------- /results/Kim-Jaemin420/pilot-react/src/styles/GlobalStyle.ts: -------------------------------------------------------------------------------- 1 | import { createGlobalStyle } from 'styled-components'; 2 | import reset from 'styled-reset'; 3 | 4 | const GlobalStyle = createGlobalStyle` 5 | ${reset}; 6 | body { 7 | margin: 0; 8 | padding: 0; 9 | font-family: AppleSDGothicNeoR, AppleSDGothicNeo, "돋움", dotum, Helvetica, sans-serif; 10 | } 11 | h1 { 12 | font-size: 25px; 13 | font-weight: 600; 14 | } 15 | ul, li { 16 | margin: 0; 17 | padding: 0 30px; 18 | list-style: none; 19 | display: inline-block; 20 | } 21 | .a11y-hidden { 22 | position: absolute; 23 | width: 1px; 24 | height: 1px; 25 | overflow: hidden; 26 | margin: -1px; 27 | clip-path: polygon(0 0, 0 0, 0 0); 28 | clip: rect(0 0 0 0); 29 | clip: rect(0, 0, 0, 0); 30 | } 31 | `; 32 | 33 | export default GlobalStyle; 34 | -------------------------------------------------------------------------------- /results/Kim-Jaemin420/pilot-react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx" 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /results/boksilab/.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "project-login-34e2b" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /results/boksilab/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /results/boksilab/README.md: -------------------------------------------------------------------------------- 1 | ## LIVE DEMO 2 | [🚀DEMO](https://boksilab-login.netlify.app/) 3 | 4 | ## Available Scripts 5 | 6 | In the project directory, you can run: 7 | 8 | ### `npm start` 9 | 10 | Runs the app in the development mode.\ 11 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 12 | -------------------------------------------------------------------------------- /results/boksilab/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "build", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /results/boksilab/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/boksilab/public/favicon.ico -------------------------------------------------------------------------------- /results/boksilab/public/image/blackhole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/boksilab/public/image/blackhole.png -------------------------------------------------------------------------------- /results/boksilab/public/image/skybox/B.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/boksilab/public/image/skybox/B.jpg -------------------------------------------------------------------------------- /results/boksilab/public/image/skybox/D.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/boksilab/public/image/skybox/D.jpg -------------------------------------------------------------------------------- /results/boksilab/public/image/skybox/F.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/boksilab/public/image/skybox/F.jpg -------------------------------------------------------------------------------- /results/boksilab/public/image/skybox/L.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/boksilab/public/image/skybox/L.jpg -------------------------------------------------------------------------------- /results/boksilab/public/image/skybox/R.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/boksilab/public/image/skybox/R.jpg -------------------------------------------------------------------------------- /results/boksilab/public/image/skybox/U.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/boksilab/public/image/skybox/U.jpg -------------------------------------------------------------------------------- /results/boksilab/public/sfx/fall1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/boksilab/public/sfx/fall1.wav -------------------------------------------------------------------------------- /results/boksilab/public/sfx/fall2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/boksilab/public/sfx/fall2.wav -------------------------------------------------------------------------------- /results/boksilab/public/sfx/fall3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/boksilab/public/sfx/fall3.wav -------------------------------------------------------------------------------- /results/boksilab/public/sfx/fall4.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/boksilab/public/sfx/fall4.wav -------------------------------------------------------------------------------- /results/boksilab/src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, screen } from '@testing-library/react'; 3 | import App from './App'; 4 | 5 | test('renders learn react link', () => { 6 | render(); 7 | const linkElement = screen.getByText(/learn react/i); 8 | expect(linkElement).toBeInTheDocument(); 9 | }); 10 | -------------------------------------------------------------------------------- /results/boksilab/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { Suspense } from 'react'; 2 | import { SnackbarProvider } from 'notistack'; 3 | import Canvas from './components/Canvas'; 4 | import ProgressBar from './components/ProgressBar'; 5 | 6 | function App() { 7 | return ( 8 | 17 |
18 | }> 19 | 20 | 21 |
22 |
23 | ); 24 | } 25 | 26 | export default App; 27 | -------------------------------------------------------------------------------- /results/boksilab/src/Godo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/boksilab/src/Godo.ttf -------------------------------------------------------------------------------- /results/boksilab/src/Phase.ts: -------------------------------------------------------------------------------- 1 | export default class Phase { 2 | static initial = 0; 3 | static pending = 1; 4 | static error = 2; 5 | static glitch = 3; 6 | static warpToCamPos2 = 4; 7 | static warp1Complete = 5; 8 | static warpToCamPos3 = 6; 9 | static warp2Complete = 7; 10 | } 11 | -------------------------------------------------------------------------------- /results/boksilab/src/Response.ts: -------------------------------------------------------------------------------- 1 | import UserInfo from './UserInfo'; 2 | export default class Response { 3 | constructor(type: string, message?: string, userInfo?: UserInfo, token?: string) { 4 | this._type = type; 5 | this._message = message; 6 | this._userInfo = userInfo; 7 | this._token = token; 8 | } 9 | private _type: string; 10 | private _message: string | undefined; 11 | private _userInfo: UserInfo | undefined; 12 | private _token: string | undefined; 13 | 14 | get type() { 15 | return this._type; 16 | } 17 | get message() { 18 | return this._message; 19 | } 20 | get userInfo() { 21 | return this._userInfo; 22 | } 23 | get token() { 24 | return this._token; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /results/boksilab/src/TabIndex.ts: -------------------------------------------------------------------------------- 1 | export default class TabIndex { 2 | static none = 0; 3 | static input1 = 1; 4 | static input2 = 2; 5 | static button = 3; 6 | static next(value: number) { 7 | return value >= 3 ? 0 : value + 1; 8 | } 9 | static prev(value: number) { 10 | return value <= 0 ? 3 : value - 1; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /results/boksilab/src/UserInfo.ts: -------------------------------------------------------------------------------- 1 | export default class UserInfo { 2 | constructor(account: string, password?: string, id?: number, level?: number, name?: string) { 3 | this._account = account; 4 | this._password = password; 5 | this._id = id; 6 | this._level = level; 7 | this._name = name; 8 | } 9 | private _account: string; 10 | private _password: string | undefined; 11 | private _id: number | undefined; 12 | private _level: number | undefined; 13 | private _name: string | undefined; 14 | set id(value: number | undefined) { 15 | this._id = value; 16 | } 17 | set level(value: number | undefined) { 18 | this._level = value; 19 | } 20 | set name(value: string | undefined) { 21 | this._name = value; 22 | } 23 | get account() { 24 | return this._account; 25 | } 26 | get password(): string | undefined { 27 | return this._password; 28 | } 29 | get id(): number | undefined { 30 | return this._id; 31 | } 32 | get level(): number | undefined { 33 | return this._level; 34 | } 35 | get name(): string | undefined { 36 | return this._name; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /results/boksilab/src/components/Blackhole.tsx: -------------------------------------------------------------------------------- 1 | import React, { useRef } from 'react'; 2 | import * as Three from 'three'; 3 | import { useFrame } from '@react-three/fiber'; 4 | 5 | export default React.memo( 6 | function Blackhole({ blackholeTexture }: { blackholeTexture: Three.Texture }) { 7 | const mesh = useRef(null!); 8 | const geometry = useRef(null!); 9 | const material = useRef(null!); 10 | useFrame(() => { 11 | mesh.current.rotation.z -= 0.003; 12 | }); 13 | return ( 14 | 15 | 16 | 32 | 33 | ); 34 | }, 35 | () => true 36 | ); 37 | -------------------------------------------------------------------------------- /results/boksilab/src/components/Lights.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default React.memo( 4 | function Lights() { 5 | return ( 6 | <> 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ); 19 | }, 20 | () => true 21 | ); 22 | -------------------------------------------------------------------------------- /results/boksilab/src/components/ProgressBar.tsx: -------------------------------------------------------------------------------- 1 | import { useProgress } from '@react-three/drei'; 2 | 3 | // interface asset { 4 | // [key: string]: { 5 | // total: number; 6 | // loaded: number; 7 | // progress: number; 8 | // }; 9 | // } 10 | const numOfAssets = 16; 11 | export default function ProgressBar() { 12 | // const { item, total, progress, loaded } = useProgress(); 13 | const { loaded } = useProgress(); 14 | 15 | return ( 16 |
17 |
32 |
46 | 🚀 47 |
48 |
49 |
50 | ); 51 | } 52 | -------------------------------------------------------------------------------- /results/boksilab/src/components/Sound.tsx: -------------------------------------------------------------------------------- 1 | import React, { useRef, useState, useEffect } from 'react'; 2 | import * as Three from 'three'; 3 | import { useThree } from '@react-three/fiber'; 4 | import { MathUtils } from 'three'; 5 | 6 | export default function PositionalAudioScene({ 7 | sfxBuffer, 8 | distance, 9 | play, 10 | }: { 11 | sfxBuffer: AudioBuffer[]; 12 | distance: number; 13 | play: boolean; 14 | }) { 15 | const sound = useRef(); 16 | const { camera } = useThree(); 17 | const [listener] = useState(() => new Three.AudioListener()); 18 | 19 | useEffect(() => { 20 | sound.current?.setBuffer(sfxBuffer[MathUtils.randInt(0, 3)]); 21 | sound.current?.setRefDistance(distance); 22 | sound.current?.setVolume(0.2); 23 | camera.add(listener); 24 | return () => { 25 | camera.remove(listener); 26 | }; 27 | }, []); 28 | useEffect(() => { 29 | if (play) { 30 | sound.current?.play(); 31 | } 32 | }, [play]); 33 | return ( 34 | <> 35 | 36 | 37 | 38 | 39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /results/boksilab/src/components/StaticText.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TextStatic from './TextStatic'; 3 | import { ITextConfig } from './Canvas'; 4 | 5 | export default React.memo( 6 | function StaticText({ textConfig }: { textConfig: ITextConfig | undefined }) { 7 | return ( 8 | <> 9 | 16 | 23 | 30 | 31 | 32 | 39 | 40 | ); 41 | }, 42 | (prev, next) => prev.textConfig === next.textConfig 43 | ); 44 | -------------------------------------------------------------------------------- /results/boksilab/src/components/TextStatic.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ITextConfig } from './Canvas'; 3 | 4 | interface IProps { 5 | config: ITextConfig | undefined; 6 | children: string; 7 | position?: number[]; 8 | rotation?: number[]; 9 | color?: string; 10 | size?: number; 11 | } 12 | 13 | export default React.memo( 14 | function TextStatic({ config, position, rotation, children, color = 'black', size = 1 }: IProps) { 15 | return ( 16 | // @ts-ignore 17 | 18 | {config && ( 19 | 20 | 21 | 22 | 23 | )} 24 | 25 | ); 26 | }, 27 | (prev, next) => prev.config === next.config && prev.position === next.position 28 | ); 29 | -------------------------------------------------------------------------------- /results/boksilab/src/index.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Godo'; 3 | src: url('Godo.ttf'); 4 | } 5 | 6 | * { 7 | font-family: 'Godo'; 8 | user-select: none; 9 | } 10 | 11 | body { 12 | width: 100vw; 13 | height: 100vh; 14 | background-color: black; 15 | margin: 0; 16 | } 17 | 18 | #canvas-container { 19 | position: absolute; 20 | width: 100%; 21 | height: 100%; 22 | min-height: 600px; 23 | } 24 | -------------------------------------------------------------------------------- /results/boksilab/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | reportWebVitals(); 15 | -------------------------------------------------------------------------------- /results/boksilab/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /results/boksilab/src/reportWebVitals.ts: -------------------------------------------------------------------------------- 1 | import { ReportHandler } from 'web-vitals'; 2 | 3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => { 4 | if (onPerfEntry && onPerfEntry instanceof Function) { 5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 6 | getCLS(onPerfEntry); 7 | getFID(onPerfEntry); 8 | getFCP(onPerfEntry); 9 | getLCP(onPerfEntry); 10 | getTTFB(onPerfEntry); 11 | }); 12 | } 13 | }; 14 | 15 | export default reportWebVitals; 16 | -------------------------------------------------------------------------------- /results/boksilab/src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /results/boksilab/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx" 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /results/byeongukchoi/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /results/byeongukchoi/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true, 5 | }, 6 | extends: [ 7 | "plugin:vue/essential", 8 | "eslint:recommended", 9 | "@vue/typescript/recommended", 10 | "@vue/prettier", 11 | "@vue/prettier/@typescript-eslint", 12 | ], 13 | parserOptions: { 14 | ecmaVersion: 2020, 15 | }, 16 | rules: { 17 | "no-console": process.env.NODE_ENV === "production" ? "warn" : "off", 18 | "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off", 19 | }, 20 | overrides: [ 21 | { 22 | files: [ 23 | "**/__tests__/*.{j,t}s?(x)", 24 | "**/tests/unit/**/*.spec.{j,t}s?(x)", 25 | ], 26 | env: { 27 | mocha: true, 28 | }, 29 | }, 30 | ], 31 | }; 32 | -------------------------------------------------------------------------------- /results/byeongukchoi/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /results/byeongukchoi/README.md: -------------------------------------------------------------------------------- 1 | # pilot-vue 2 | 3 | ## spec 4 | - vue2 5 | - typescript 6 | 7 | ## 후기 8 | 저의 부족함을 많이 느끼게된 프로젝트였습니다. 9 | 테스트 코드 구현하지 못하였습니다. 10 | 11 | ### Run 12 | ``` 13 | yarn serve 14 | ``` 15 | -------------------------------------------------------------------------------- /results/byeongukchoi/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ["@vue/cli-plugin-babel/preset"], 3 | }; 4 | -------------------------------------------------------------------------------- /results/byeongukchoi/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/byeongukchoi/public/favicon.ico -------------------------------------------------------------------------------- /results/byeongukchoi/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | <%= htmlWebpackPlugin.options.title %> 12 | 13 | 14 | 17 | 18 |
19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /results/byeongukchoi/src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /results/byeongukchoi/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/byeongukchoi/src/assets/logo.png -------------------------------------------------------------------------------- /results/byeongukchoi/src/components/Profile.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 41 | -------------------------------------------------------------------------------- /results/byeongukchoi/src/main.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import App from "./App.vue"; 3 | import router from "./router"; 4 | import store from "./store"; 5 | 6 | Vue.config.productionTip = false; 7 | 8 | new Vue({ 9 | router, 10 | store, 11 | render: (h) => h(App), 12 | }).$mount("#app"); 13 | -------------------------------------------------------------------------------- /results/byeongukchoi/src/models/LoginRequest.ts: -------------------------------------------------------------------------------- 1 | export default class LoginRequest { 2 | account: string; 3 | password: string; 4 | 5 | constructor(account: string, password: string) { 6 | this.account = account; 7 | this.password = password; 8 | } 9 | 10 | public isValid(): boolean { 11 | return !(!this.account || !this.password); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /results/byeongukchoi/src/models/LoginResponse.ts: -------------------------------------------------------------------------------- 1 | export interface ILoginResponse { 2 | code: number; 3 | message: string; 4 | } 5 | 6 | export class LoginResponseDTO implements ILoginResponse { 7 | code = 0; 8 | message = ""; 9 | validate? = {}; 10 | } 11 | 12 | export default class LoginResponse extends LoginResponseDTO { 13 | constructor(dto: LoginResponseDTO) { 14 | super(); 15 | Object.assign(this, dto); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /results/byeongukchoi/src/models/Token.ts: -------------------------------------------------------------------------------- 1 | export default class LoginRequest { 2 | accessToken: string; 3 | 4 | constructor(accessToken: string) { 5 | this.accessToken = accessToken; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /results/byeongukchoi/src/models/User.ts: -------------------------------------------------------------------------------- 1 | export interface IUser { 2 | account: string; 3 | name: string; 4 | password: string; 5 | } 6 | 7 | export class UserDTO implements IUser { 8 | account = ""; 9 | name = ""; 10 | password = ""; 11 | } 12 | 13 | export default class User extends UserDTO { 14 | constructor(dto?: UserDTO) { 15 | super(); 16 | Object.assign(this, dto); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /results/byeongukchoi/src/router/index.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import VueRouter, { RouteConfig } from "vue-router"; 3 | import store from "../store"; 4 | import Home from "../views/Home.vue"; 5 | 6 | Vue.use(VueRouter); 7 | 8 | const routes: Array = [ 9 | { 10 | path: "/", 11 | name: "Home", 12 | component: Home, 13 | beforeEnter(to, from, next) { 14 | store.getters.isLoggedIn() ? next() : next("/login"); 15 | }, 16 | }, 17 | { 18 | path: "/login", 19 | name: "Login", 20 | component: () => import("../views/Login.vue"), 21 | beforeEnter(to, from, next) { 22 | store.getters.isLoggedIn() ? next("/") : next(); 23 | }, 24 | }, 25 | ]; 26 | 27 | const router = new VueRouter({ 28 | mode: "history", 29 | base: process.env.BASE_URL, 30 | routes, 31 | }); 32 | 33 | export default router; 34 | -------------------------------------------------------------------------------- /results/byeongukchoi/src/shims-tsx.d.ts: -------------------------------------------------------------------------------- 1 | import Vue, { VNode } from "vue"; 2 | 3 | declare global { 4 | namespace JSX { 5 | // tslint:disable no-empty-interface 6 | interface Element extends VNode {} 7 | // tslint:disable no-empty-interface 8 | interface ElementClass extends Vue {} 9 | interface IntrinsicElements { 10 | [elem: string]: any; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /results/byeongukchoi/src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.vue" { 2 | import Vue from "vue"; 3 | export default Vue; 4 | } 5 | -------------------------------------------------------------------------------- /results/byeongukchoi/src/utils/cookies.ts: -------------------------------------------------------------------------------- 1 | function saveAccessTokenToCookie(value: string): void { 2 | document.cookie = `devbadak_auth=${value}`; 3 | } 4 | 5 | function getAccessTokenFromCookie(): string { 6 | return document.cookie.replace( 7 | /(?:(?:^|.*;\s*)devbadak_auth\s*=\s*([^;]*).*$)|^.*$/, 8 | "$1" 9 | ); 10 | } 11 | 12 | function deleteAccessTokenFromCookie(): void { 13 | document.cookie = "devbadak_auth=; expires=Thu, 01 Jan 1970 00:00:01 GMT;"; 14 | } 15 | 16 | export { 17 | saveAccessTokenToCookie, 18 | getAccessTokenFromCookie, 19 | deleteAccessTokenFromCookie, 20 | }; 21 | -------------------------------------------------------------------------------- /results/byeongukchoi/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 24 | -------------------------------------------------------------------------------- /results/byeongukchoi/tests/unit/example.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { shallowMount } from "@vue/test-utils"; 3 | import Login from "@/views/Login.vue"; 4 | 5 | describe("HelloWorld.vue", () => { 6 | it("renders props.msg when passed", () => { 7 | const msg = "new message"; 8 | const wrapper = shallowMount(Login, { 9 | propsData: { msg }, 10 | }); 11 | expect(wrapper.text()).to.include(msg); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /results/byeongukchoi/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "strict": true, 6 | "jsx": "preserve", 7 | "importHelpers": true, 8 | "moduleResolution": "node", 9 | "skipLibCheck": true, 10 | "esModuleInterop": true, 11 | "allowSyntheticDefaultImports": true, 12 | "sourceMap": true, 13 | "baseUrl": ".", 14 | "types": [ 15 | "webpack-env", 16 | "mocha", 17 | "chai" 18 | ], 19 | "paths": { 20 | "@/*": [ 21 | "src/*" 22 | ] 23 | }, 24 | "lib": [ 25 | "esnext", 26 | "dom", 27 | "dom.iterable", 28 | "scripthost" 29 | ] 30 | }, 31 | "include": [ 32 | "src/**/*.ts", 33 | "src/**/*.tsx", 34 | "src/**/*.vue", 35 | "tests/**/*.ts", 36 | "tests/**/*.tsx" 37 | ], 38 | "exclude": [ 39 | "node_modules" 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /results/cozy60/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /results/cozy60/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "singleQuote": true, 4 | "endOfLine": "lf", 5 | "tabWidth": 2, 6 | "useTabs": false 7 | } 8 | -------------------------------------------------------------------------------- /results/cozy60/README.md: -------------------------------------------------------------------------------- 1 | # Pilot React Project 2 | 3 | ## 요구 사항 4 | 5 | - [x] git (github) 6 | - [ ] webstorm // vscode 사용했습니다 7 | - [x] React 8 | - [x] Typescript 9 | - [ ] Test Case 작성 10 | - [x] 자바스크립트 Object `{}` (type object 포함)의 사용을 하지말아보자! // 노력해봤는데 맞는 시도인지 자신이 없네요..^_ㅠ 11 | - [x] API 요청, 응답 데이터는 클래스를 이용 -------------------------------------------------------------------------------- /results/cozy60/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cozy60", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@emotion/core": "^11.0.0", 7 | "@emotion/react": "^11.4.0", 8 | "@testing-library/jest-dom": "^5.14.1", 9 | "@testing-library/react": "^11.2.7", 10 | "@testing-library/user-event": "^12.8.3", 11 | "@types/jest": "^26.0.24", 12 | "@types/node": "^12.20.16", 13 | "@types/react": "^17.0.14", 14 | "@types/react-dom": "^17.0.9", 15 | "axios": "^0.21.1", 16 | "react": "^17.0.2", 17 | "react-dom": "^17.0.2", 18 | "react-router-dom": "^5.2.0", 19 | "react-scripts": "4.0.3", 20 | "typescript": "^4.3.5", 21 | "web-vitals": "^1.1.2" 22 | }, 23 | "scripts": { 24 | "start": "react-scripts start", 25 | "build": "react-scripts build", 26 | "test": "react-scripts test", 27 | "eject": "react-scripts eject" 28 | }, 29 | "eslintConfig": { 30 | "extends": [ 31 | "react-app", 32 | "react-app/jest" 33 | ] 34 | }, 35 | "browserslist": { 36 | "production": [ 37 | ">0.2%", 38 | "not dead", 39 | "not op_mini all" 40 | ], 41 | "development": [ 42 | "last 1 chrome version", 43 | "last 1 firefox version", 44 | "last 1 safari version" 45 | ] 46 | }, 47 | "devDependencies": { 48 | "@types/react-router-dom": "^5.1.8" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /results/cozy60/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/cozy60/public/favicon.ico -------------------------------------------------------------------------------- /results/cozy60/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/cozy60/public/logo192.png -------------------------------------------------------------------------------- /results/cozy60/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/cozy60/public/logo512.png -------------------------------------------------------------------------------- /results/cozy60/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /results/cozy60/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /results/cozy60/src/App.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | -------------------------------------------------------------------------------- /results/cozy60/src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, screen } from '@testing-library/react'; 3 | import App from './App'; 4 | 5 | test('renders learn react link', () => { 6 | render(); 7 | const linkElement = screen.getByText(/learn react/i); 8 | expect(linkElement).toBeInTheDocument(); 9 | }); 10 | -------------------------------------------------------------------------------- /results/cozy60/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './App.css'; 3 | import { Route } from 'react-router-dom'; 4 | import LoginPage from './pages/LoginPage'; 5 | import UserInfoPage from './pages/UserInfoPage'; 6 | 7 | function App() { 8 | return ( 9 |
10 | 11 | 12 |
13 | ); 14 | } 15 | 16 | export default App; 17 | -------------------------------------------------------------------------------- /results/cozy60/src/components/Button/Button.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { css } from '@emotion/react'; 3 | import React from 'react'; 4 | import palette from '../../library/styles/palette'; 5 | import Children from '../../library/utils/children'; 6 | 7 | export class ButtonType extends Children { 8 | type: 'button' | 'submit' | 'reset'; 9 | color: 'blue' | 'red'; 10 | 11 | constructor( 12 | type: 'button' | 'submit' | 'reset', 13 | color: 'blue' | 'red', 14 | children: React.ReactNode 15 | ) { 16 | super(children); 17 | this.type = type; 18 | this.color = color; 19 | } 20 | } 21 | 22 | function Button({ type, color, children }: ButtonType) { 23 | return ( 24 | 27 | ); 28 | } 29 | 30 | const buttonStyle = (color: 'blue' | 'red') => css` 31 | display: block; 32 | width: 100%; 33 | padding: 10px; 34 | font-weight: 700; 35 | cursor: pointer; 36 | border: none; 37 | border-radius: 8px; 38 | color: ${palette.white}; 39 | background-color: ${palette[color]}; 40 | 41 | :focus { 42 | outline: none; 43 | } 44 | 45 | :active { 46 | opacity: 0.7; 47 | } 48 | `; 49 | 50 | export default Button; 51 | -------------------------------------------------------------------------------- /results/cozy60/src/components/Button/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './Button'; 2 | -------------------------------------------------------------------------------- /results/cozy60/src/components/Card/Card.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { css } from '@emotion/react'; 3 | import React from 'react'; 4 | import palette from '../../library/styles/palette'; 5 | import Children from '../../library/utils/children'; 6 | 7 | function Card({ children }: Children) { 8 | return ( 9 |
10 |
{children}
11 |
12 | ); 13 | } 14 | 15 | const sectionStyle = css` 16 | display: flex; 17 | width: 100%; 18 | height: 100vh; 19 | justify-content: center; 20 | align-items: center; 21 | `; 22 | 23 | const borderStyle = css` 24 | padding: 30px 40px; 25 | background-color: ${palette.white}; 26 | border: 2px solid ${palette.border}; 27 | border-radius: 9px; 28 | `; 29 | 30 | export default Card; 31 | -------------------------------------------------------------------------------- /results/cozy60/src/components/Card/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './Card'; 2 | -------------------------------------------------------------------------------- /results/cozy60/src/components/ErrorMessage/ErrorMessage.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { css } from '@emotion/react'; 3 | import React from 'react'; 4 | import palette from '../../library/styles/palette'; 5 | import Children from '../../library/utils/children'; 6 | 7 | function ErrorMessage({ children }: Children) { 8 | return

{children}

; 9 | } 10 | 11 | const errorMessageStyle = css` 12 | font-family: 'Noto Sans KR', sans-serif; 13 | font-weight: 600; 14 | text-align: center; 15 | color: ${palette.red}; 16 | `; 17 | 18 | export default ErrorMessage; 19 | -------------------------------------------------------------------------------- /results/cozy60/src/components/ErrorMessage/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './ErrorMessage'; 2 | -------------------------------------------------------------------------------- /results/cozy60/src/components/Footer/Footer.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { css } from '@emotion/react'; 3 | import React from 'react'; 4 | import Children from '../../library/utils/children'; 5 | 6 | function Footer({ children }: Children) { 7 | return
{children}
; 8 | } 9 | 10 | const footerStyle = css` 11 | margin-top: 20px; 12 | margin-bottom: 14px; 13 | `; 14 | 15 | export default Footer; 16 | -------------------------------------------------------------------------------- /results/cozy60/src/components/Footer/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './Footer'; 2 | -------------------------------------------------------------------------------- /results/cozy60/src/components/Form/Form.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { css } from '@emotion/react'; 3 | import React from 'react'; 4 | import palette from '../../library/styles/palette'; 5 | import Children from '../../library/utils/children'; 6 | 7 | class FormType extends Children { 8 | onSubmit?: React.FormEventHandler; 9 | 10 | constructor( 11 | onSubmit: React.FormEventHandler, 12 | children: React.ReactNode 13 | ) { 14 | super(children); 15 | this.onSubmit = onSubmit; 16 | } 17 | } 18 | 19 | function Form({ onSubmit, children }: FormType) { 20 | return ( 21 |
22 |
{children}
23 |
24 | ); 25 | } 26 | 27 | const formStyle = css` 28 | display: flex; 29 | justify-content: center; 30 | 31 | fieldset { 32 | width: 100%; 33 | border: none; 34 | } 35 | 36 | label { 37 | display: block; 38 | font: bold 15px/24px 'Haas Grot Text R Web', 'Helvetica Neue', Helvetica, 39 | Arial, sans-serif; 40 | margin: 14px 0 4px; 41 | color: ${palette.dark}; 42 | } 43 | 44 | footer { 45 | margin-top: 20px; 46 | margin-bottom: 14px; 47 | } 48 | `; 49 | 50 | export default Form; 51 | -------------------------------------------------------------------------------- /results/cozy60/src/components/Form/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './Form'; 2 | -------------------------------------------------------------------------------- /results/cozy60/src/components/Input/Input.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { css } from '@emotion/react'; 3 | import React from 'react'; 4 | import palette from '../../library/styles/palette'; 5 | 6 | class InputProps { 7 | type: string; 8 | name: string; 9 | id: string; 10 | onChange?: React.ChangeEventHandler; 11 | 12 | constructor( 13 | type: string, 14 | name: string, 15 | id: string, 16 | onChange: React.ChangeEventHandler 17 | ) { 18 | this.type = type; 19 | this.name = name; 20 | this.id = id; 21 | this.onChange = onChange; 22 | } 23 | } 24 | 25 | function Input({ type, name, id, onChange }: InputProps) { 26 | return ( 27 | 34 | ); 35 | } 36 | 37 | const inputStyle = css` 38 | width: 300px; 39 | height: 36px; 40 | background-color: ${palette.input}; 41 | font-size: 14px; 42 | padding: 10px 16px; 43 | border: 1px solid ${palette.border}; 44 | border-radius: 8px; 45 | 46 | :focus { 47 | outline: none; 48 | } 49 | `; 50 | 51 | export default Input; 52 | -------------------------------------------------------------------------------- /results/cozy60/src/components/Input/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './Input'; 2 | -------------------------------------------------------------------------------- /results/cozy60/src/components/Layouts/Container.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import React from 'react'; 3 | import { css } from '@emotion/react'; 4 | import Children from '../../library/utils/children'; 5 | import palette from '../../library/styles/palette'; 6 | 7 | function Container({ children }: Children) { 8 | return
{children}
; 9 | } 10 | 11 | const containerStyle = css` 12 | /* display: flex; 13 | width: 100%; 14 | height: 100vh; 15 | max-width: 400px; 16 | justify-content: center; 17 | align-items: center; */ 18 | `; 19 | 20 | export default Container; 21 | -------------------------------------------------------------------------------- /results/cozy60/src/components/Layouts/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Container } from './Container'; 2 | -------------------------------------------------------------------------------- /results/cozy60/src/components/UserInfo/UserInfo.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { css } from '@emotion/react'; 3 | import React from 'react'; 4 | 5 | class UsreInfoType { 6 | dt: string; 7 | dd: string | number | undefined; 8 | 9 | constructor(dt: string, dd: string | number | undefined) { 10 | this.dt = dt; 11 | this.dd = dd; 12 | } 13 | } 14 | 15 | function UserInfo({ dt, dd }: UsreInfoType) { 16 | return ( 17 |
18 |
{dt}
19 |
{dd}
20 |
21 | ); 22 | } 23 | 24 | const userInfoStyle = css` 25 | & { 26 | font-family: 'Noto Sans KR', sans-serif; 27 | } 28 | 29 | dt, 30 | dd { 31 | display: inline-block; 32 | } 33 | 34 | dt { 35 | margin-right: 16px; 36 | font-weight: 700; 37 | } 38 | 39 | dd { 40 | margin: 0; 41 | } 42 | `; 43 | 44 | export default UserInfo; 45 | -------------------------------------------------------------------------------- /results/cozy60/src/components/UserInfo/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './UserInfo'; 2 | -------------------------------------------------------------------------------- /results/cozy60/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /results/cozy60/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import { BrowserRouter } from 'react-router-dom'; 4 | import './index.css'; 5 | import App from './App'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | 11 | 12 | , 13 | document.getElementById('root') 14 | ); 15 | -------------------------------------------------------------------------------- /results/cozy60/src/library/api/apiClient.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | const apiClient = axios.create({ 4 | baseURL: 'http://localhost:5000', 5 | }); 6 | 7 | const token = window.sessionStorage.getItem('accessToken'); 8 | 9 | apiClient.defaults.headers['Access-Control-Allow-Origin'] = 10 | 'http://localhost:5000'; 11 | apiClient.defaults.headers['Access-Control-Allow-Credentials'] = 'true'; 12 | apiClient.defaults.headers['Authorization'] = `Bearer ${token}`; 13 | 14 | export default apiClient; 15 | -------------------------------------------------------------------------------- /results/cozy60/src/library/api/auth/auth.ts: -------------------------------------------------------------------------------- 1 | import apiClient from '../apiClient'; 2 | 3 | export class AuthApi { 4 | static async signIn(account: string, password: string) { 5 | const res = await apiClient.post('/auth/login', { 6 | account: account, 7 | password: password, 8 | }); 9 | window.sessionStorage.setItem('accessToken', res.data?.accessToken); 10 | 11 | return res; 12 | } 13 | 14 | static async signOut() { 15 | const res = await apiClient.get('/auth/logout'); 16 | sessionStorage.clear(); 17 | 18 | return res; 19 | } 20 | 21 | static async getUserInfo() { 22 | const res = await apiClient.get('/v1/users/me'); 23 | 24 | return res; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /results/cozy60/src/library/styles/palette.ts: -------------------------------------------------------------------------------- 1 | class Palette { 2 | black: string; 3 | dark: string; 4 | input: string; 5 | border: string; 6 | red: string; 7 | blue: string; 8 | white: string; 9 | 10 | constructor() { 11 | this.black = '#000'; 12 | this.dark = '#191a20'; 13 | this.input = '#f3f3f4'; 14 | this.border = '#e0e2e7'; 15 | this.red = '#f86d7d'; 16 | this.blue = '#3da5f5'; 17 | this.white = '#fff'; 18 | } 19 | } 20 | 21 | const palette = new Palette(); 22 | 23 | export default palette; 24 | -------------------------------------------------------------------------------- /results/cozy60/src/library/utils/children.ts: -------------------------------------------------------------------------------- 1 | class Children { 2 | children: React.ReactNode; 3 | 4 | constructor(children: React.ReactNode) { 5 | this.children = children; 6 | } 7 | } 8 | 9 | export default Children; 10 | -------------------------------------------------------------------------------- /results/cozy60/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /results/cozy60/src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /results/cozy60/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx" 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/hayoung-jeremy/public/favicon.ico -------------------------------------------------------------------------------- /results/hayoung-jeremy/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/hayoung-jeremy/public/logo192.png -------------------------------------------------------------------------------- /results/hayoung-jeremy/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/hayoung-jeremy/public/logo512.png -------------------------------------------------------------------------------- /results/hayoung-jeremy/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, screen } from '@testing-library/react'; 3 | import App from './App'; 4 | 5 | test('renders learn react link', () => { 6 | render(); 7 | const linkElement = screen.getByText(/learn react/i); 8 | expect(linkElement).toBeInTheDocument(); 9 | }); 10 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import GlobalStyle from "./style/GlobalStyle"; 3 | import { BrowserRouter, Route, Switch, Redirect } from "react-router-dom"; 4 | import { LoginPage, ProfilePage } from "pages"; 5 | 6 | function App() { 7 | return ( 8 | <> 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ); 19 | } 20 | 21 | export default App; 22 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/src/components/button/Button.tsx: -------------------------------------------------------------------------------- 1 | import React, { ButtonHTMLAttributes } from "react"; 2 | import styled from "styled-components"; 3 | import { lighten, darken } from "polished"; 4 | 5 | // custom 6 | import { PALETTE } from "style"; 7 | 8 | const Button = ({ 9 | children, 10 | ...rest 11 | }: ButtonHTMLAttributes) => { 12 | return {children}; 13 | }; 14 | 15 | // style 16 | const StyledButton = styled.button` 17 | display: inline-flex; 18 | justify-content: center; 19 | align-items: center; 20 | width: 100%; 21 | padding: 12px 20px; 22 | border: 1px solid ${PALETTE.GRAY}; 23 | border-radius: 4px; 24 | color: ${darken(0.2, PALETTE.GRAY)}; 25 | font-size: 14px; 26 | background-color: transparent; 27 | transition: 0.2s; 28 | 29 | &:not(:first-of-type) { 30 | margin-top: 8px; 31 | } 32 | &:hover { 33 | border-color: ${PALETTE.MAIN}; 34 | color: ${darken(0.1, PALETTE.MAIN)}; 35 | transform: perspective(1000px) translateZ(-5px); 36 | } 37 | &:active { 38 | border-color: ${darken(0.08, PALETTE.MAIN)}; 39 | background-color: ${lighten(0.185, PALETTE.MAIN)}; 40 | transform: perspective(1000px) translateZ(-15px); 41 | } 42 | `; 43 | 44 | export default Button; 45 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/src/components/button/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from "./Button"; 2 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/src/components/form/Form.tsx: -------------------------------------------------------------------------------- 1 | import React, { FormHTMLAttributes } from "react"; 2 | import styled from "styled-components"; 3 | // custom 4 | import { PALETTE } from "style"; 5 | 6 | const Form = ({ children, ...rest }: FormHTMLAttributes) => { 7 | return {children}; 8 | }; 9 | 10 | // style 11 | const StyledForm = styled.form` 12 | padding: 40px 0; 13 | & .errorMessage { 14 | height: 14px; 15 | margin-bottom: 60px; 16 | text-indent: 8px; 17 | font-size: 14px; 18 | color: ${PALETTE.RED}; 19 | } 20 | `; 21 | 22 | export default Form; 23 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/src/components/form/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from "./Form"; 2 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export { default as PageTemplate } from "./pageTemplate"; 2 | export { default as Form } from "./form"; 3 | export { default as Button } from "./button"; 4 | export { default as Input } from "./input"; 5 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/src/components/input/Input.tsx: -------------------------------------------------------------------------------- 1 | import React, { InputHTMLAttributes } from "react"; 2 | import styled, { css } from "styled-components"; 3 | import { PALETTE } from "style"; 4 | import { darken, lighten } from "polished"; 5 | 6 | const Input = (props: InputHTMLAttributes) => { 7 | return ; 8 | }; 9 | 10 | // style 11 | const StyledInput = styled.input` 12 | width: 100%; 13 | padding: 8px 12px; 14 | outline: none; 15 | border: none; 16 | border-bottom: 1px solid ${PALETTE.GRAY}; 17 | 18 | font-size: 16px; 19 | transition: 0.2s; 20 | ${(props) => 21 | props.value !== "" 22 | ? css` 23 | color: ${darken(0.2, PALETTE.MAIN)}; 24 | border-color: ${PALETTE.MAIN}; 25 | ` 26 | : css` 27 | color: ${lighten(0.2, PALETTE.BLACK)}; 28 | `} 29 | 30 | &:not(:first-of-type) { 31 | margin-top: 16px; 32 | } 33 | &:last-of-type { 34 | margin-bottom: 12px; 35 | } 36 | &::placeholder { 37 | color: ${PALETTE.GRAY}; 38 | transition: 0.3s; 39 | } 40 | &:focus { 41 | border-color: ${PALETTE.MAIN}; 42 | color: ${darken(0.2, PALETTE.MAIN)}; 43 | &::placeholder { 44 | color: transparent; 45 | } 46 | } 47 | `; 48 | 49 | export default Input; 50 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/src/components/input/index.ts: -------------------------------------------------------------------------------- 1 | export {default} from "./Input" -------------------------------------------------------------------------------- /results/hayoung-jeremy/src/components/pageTemplate/PageTemplate.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import styled from "styled-components"; 3 | import { darken, lighten } from "polished"; 4 | 5 | // custom 6 | import { PALETTE } from "style"; 7 | 8 | interface PageProps { 9 | children?: React.ReactNode; 10 | title?: string; 11 | } 12 | const PageTemplate = ({ children, title }: PageProps) => { 13 | return ( 14 | 15 |
16 |

{title}

17 | {children} 18 |
19 |
20 | ); 21 | }; 22 | 23 | // style 24 | const StyledMain = styled.main` 25 | height: 100%; 26 | display: flex; 27 | justify-content: center; 28 | align-items: center; 29 | & .container { 30 | width: 520px; 31 | margin-top: 4vw; 32 | padding: 32px 24px; 33 | border-radius: 12px; 34 | background-color: white; 35 | box-shadow: 0 0 4px rgba(0, 0, 0, 0.1); 36 | } 37 | & .title { 38 | margin-bottom: 20px; 39 | font-size: 28px; 40 | font-weight: 500; 41 | color: ${lighten(0.2, PALETTE.BLACK)}; 42 | } 43 | & .userInfo { 44 | margin-bottom: 20px; 45 | font-size: 20px; 46 | color: ${darken(0.2, PALETTE.MAIN)}; 47 | } 48 | `; 49 | 50 | export default PageTemplate; 51 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/src/components/pageTemplate/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from "./PageTemplate"; 2 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import { Provider } from "react-redux"; 4 | 5 | // custom 6 | import App from "./App"; 7 | import reportWebVitals from "./reportWebVitals"; 8 | import { store } from "store/store"; 9 | 10 | ReactDOM.render( 11 | 12 | 13 | 14 | 15 | , 16 | document.getElementById("root") 17 | ); 18 | 19 | // If you want to start measuring performance in your app, pass a function 20 | // to log results (for example: reportWebVitals(console.log)) 21 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 22 | reportWebVitals(); 23 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/src/pages/Login/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from "./LoginPage"; 2 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/src/pages/Profile/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from "./ProfilePage"; 2 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/src/pages/index.ts: -------------------------------------------------------------------------------- 1 | export { default as LoginPage } from "./Login"; 2 | export { default as ProfilePage } from "./Profile"; 3 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/src/reportWebVitals.ts: -------------------------------------------------------------------------------- 1 | import { ReportHandler } from 'web-vitals'; 2 | 3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => { 4 | if (onPerfEntry && onPerfEntry instanceof Function) { 5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 6 | getCLS(onPerfEntry); 7 | getFID(onPerfEntry); 8 | getFCP(onPerfEntry); 9 | getLCP(onPerfEntry); 10 | getTTFB(onPerfEntry); 11 | }); 12 | } 13 | }; 14 | 15 | export default reportWebVitals; 16 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/src/store/rootReducer.ts: -------------------------------------------------------------------------------- 1 | import { combineReducers } from "@reduxjs/toolkit"; 2 | import { loginReducer } from "./loginSlice"; 3 | import { getUserReducer } from "./authSlice"; 4 | 5 | const rootReducer = combineReducers({ 6 | login: loginReducer, 7 | getUser: getUserReducer, 8 | }); 9 | 10 | export default rootReducer; 11 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/src/store/store.ts: -------------------------------------------------------------------------------- 1 | import { configureStore } from "@reduxjs/toolkit"; 2 | import rootReducer from "./rootReducer"; 3 | import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux"; 4 | 5 | export const store = configureStore({ 6 | reducer: rootReducer, 7 | }); 8 | 9 | export type RootState = ReturnType; 10 | export type AppDispatch = typeof store.dispatch; 11 | 12 | // hooks : 13 | // 각각의 component 에서 useSelector 를 사용할 때마다 훅의 parameter 로 매번 RootState 를 가져와서 선언해주는 수고로움을 덜어줌 14 | // dispatch 역시 위와 동일 15 | export const useTypedSelector: TypedUseSelectorHook = useSelector; 16 | export const useAppDispatch = () => useDispatch(); 17 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/src/style/GlobalStyle.ts: -------------------------------------------------------------------------------- 1 | import { createGlobalStyle } from "styled-components"; 2 | import { reset } from "styled-reset"; 3 | import PALETTE from "./palette"; 4 | 5 | const GlobalStyle = createGlobalStyle` 6 | ${reset} 7 | *,*:before,*:after{ 8 | box-sizing: border-box; 9 | } 10 | body{ 11 | font-family: "Montserrat", "Noto Sans KR", sans-serif; 12 | background-color: ${PALETTE.BACKGROUND}; 13 | } 14 | a{ 15 | text-decoration: none; 16 | } 17 | button{ 18 | outline: none; 19 | font-family: "Montserrat", "Noto Sans KR", sans-serif; 20 | cursor: pointer; 21 | } 22 | `; 23 | 24 | export default GlobalStyle; 25 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/src/style/index.ts: -------------------------------------------------------------------------------- 1 | export { default as GlobalStyle } from "./GlobalStyle"; 2 | export { default as PALETTE } from "./palette"; 3 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/src/style/palette.ts: -------------------------------------------------------------------------------- 1 | const PALETTE = { 2 | MAIN: "#97d8ff", 3 | BACKGROUND: "#f7f7f7", 4 | BLACK: "#333", 5 | GRAY: "#e5e5e5", 6 | RED: "#f7989b", 7 | }; 8 | 9 | export default PALETTE; 10 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/src/types/auth.ts: -------------------------------------------------------------------------------- 1 | export interface loginInfo { 2 | account: string; 3 | password: string; 4 | } 5 | 6 | export interface userInfo { 7 | id?: number; 8 | account?: string; 9 | name?: string; 10 | level?: number; 11 | } 12 | -------------------------------------------------------------------------------- /results/hayoung-jeremy/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "baseUrl": "./src", 10 | "allowJs": true, 11 | "skipLibCheck": true, 12 | "esModuleInterop": true, 13 | "allowSyntheticDefaultImports": true, 14 | "strict": true, 15 | "forceConsistentCasingInFileNames": true, 16 | "noFallthroughCasesInSwitch": true, 17 | "module": "esnext", 18 | "moduleResolution": "node", 19 | "resolveJsonModule": true, 20 | "isolatedModules": true, 21 | "noEmit": true, 22 | "jsx": "react-jsx" 23 | }, 24 | "include": [ 25 | "src" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /results/hojongs/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /results/hojongs/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | 'extends': [ 7 | 'plugin:vue/essential', 8 | 'eslint:recommended', 9 | '@vue/typescript/recommended' 10 | ], 11 | parserOptions: { 12 | ecmaVersion: 2020 13 | }, 14 | rules: { 15 | 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 16 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off' 17 | }, 18 | overrides: [ 19 | { 20 | files: [ 21 | '**/__tests__/*.{j,t}s?(x)', 22 | '**/tests/unit/**/*.spec.{j,t}s?(x)' 23 | ], 24 | env: { 25 | jest: true 26 | } 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /results/hojongs/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /results/hojongs/README.md: -------------------------------------------------------------------------------- 1 | # hojongs 2 | 3 | hojongs's pilot project based on Vue.js 2 4 | 5 | ## Project setup 6 | ``` 7 | npm install 8 | ``` 9 | 10 | ### Compiles and hot-reloads for development 11 | ``` 12 | npm run serve 13 | ``` 14 | 15 | ### Compiles and minifies for production 16 | ``` 17 | npm run build 18 | ``` 19 | 20 | ### Run your unit tests 21 | ``` 22 | npm run test:unit 23 | ``` 24 | 25 | ### Lints and fixes files 26 | ``` 27 | npm run lint 28 | ``` 29 | 30 | ### Customize configuration 31 | See [Configuration Reference](https://cli.vuejs.org/config/). 32 | -------------------------------------------------------------------------------- /results/hojongs/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: '@vue/cli-plugin-unit-jest/presets/typescript' 3 | } 4 | -------------------------------------------------------------------------------- /results/hojongs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hojongs", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "test:unit": "vue-cli-service test:unit", 9 | "lint": "vue-cli-service lint" 10 | }, 11 | "dependencies": { 12 | "vue": "^2.6.11", 13 | "vue-class-component": "^7.2.3", 14 | "vue-property-decorator": "^9.1.2" 15 | }, 16 | "devDependencies": { 17 | "@types/jest": "^24.0.19", 18 | "@typescript-eslint/eslint-plugin": "^4.18.0", 19 | "@typescript-eslint/parser": "^4.18.0", 20 | "@vue/cli-plugin-eslint": "~4.5.0", 21 | "@vue/cli-plugin-typescript": "~4.5.0", 22 | "@vue/cli-plugin-unit-jest": "~4.5.0", 23 | "@vue/cli-service": "~4.5.0", 24 | "@vue/eslint-config-typescript": "^7.0.0", 25 | "@vue/test-utils": "^1.0.3", 26 | "eslint": "^6.7.2", 27 | "eslint-plugin-vue": "^6.2.2", 28 | "typescript": "~4.1.5", 29 | "vue-template-compiler": "^2.6.11" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /results/hojongs/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/hojongs/public/favicon.ico -------------------------------------------------------------------------------- /results/hojongs/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /results/hojongs/src/config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | baseUrl: "http://localhost:5000" 3 | } 4 | -------------------------------------------------------------------------------- /results/hojongs/src/dto/auth.ts: -------------------------------------------------------------------------------- 1 | export default class Auth { 2 | account: string; 3 | password: string; 4 | 5 | constructor(account: string, password: string) { 6 | this.account = account; 7 | this.password = password; 8 | } 9 | 10 | public toString(): string { 11 | return `Auth(account=${this.account},password=${this.password})`; 12 | } 13 | } -------------------------------------------------------------------------------- /results/hojongs/src/dto/user.ts: -------------------------------------------------------------------------------- 1 | export default class User { 2 | id: number; 3 | account: string; 4 | name: string; 5 | level: number; 6 | 7 | constructor(id: number, account: string, name: string, level: number) { 8 | this.id = id; 9 | this.account = account; 10 | this.name = name; 11 | this.level = level; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /results/hojongs/src/entry/main.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Login from '@/view/login.vue' 3 | 4 | Vue.config.productionTip = false 5 | 6 | new Vue({ 7 | render: h => h(Login), 8 | }).$mount('#app') 9 | -------------------------------------------------------------------------------- /results/hojongs/src/entry/user.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import User from '@/view/user.vue' 3 | 4 | Vue.config.productionTip = false 5 | 6 | new Vue({ 7 | render: h => h(User), 8 | }).$mount('#app') 9 | -------------------------------------------------------------------------------- /results/hojongs/src/service/url_param_service.ts: -------------------------------------------------------------------------------- 1 | export default class UrlParamService { 2 | getAccessTokenOrThrow(): string { 3 | const accessToken = new URL(location.href).searchParams.get("accessToken"); 4 | if (accessToken == null) throw "accessToken was null"; 5 | return accessToken; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /results/hojongs/src/shims-tsx.d.ts: -------------------------------------------------------------------------------- 1 | import Vue, { VNode } from 'vue' 2 | 3 | declare global { 4 | namespace JSX { 5 | // tslint:disable no-empty-interface 6 | interface Element extends VNode {} 7 | // tslint:disable no-empty-interface 8 | interface ElementClass extends Vue {} 9 | interface IntrinsicElements { 10 | [elem: string]: any 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /results/hojongs/src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import Vue from 'vue' 3 | export default Vue 4 | } 5 | -------------------------------------------------------------------------------- /results/hojongs/src/view/Login.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 41 | 42 | 44 | -------------------------------------------------------------------------------- /results/hojongs/src/view/User.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 41 | 42 | 44 | -------------------------------------------------------------------------------- /results/hojongs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "esnext", 5 | "strict": true, 6 | "jsx": "preserve", 7 | "importHelpers": true, 8 | "moduleResolution": "node", 9 | "experimentalDecorators": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "sourceMap": true, 14 | "baseUrl": ".", 15 | "types": [ 16 | "webpack-env", 17 | "jest" 18 | ], 19 | "paths": { 20 | "@/*": [ 21 | "src/*" 22 | ] 23 | }, 24 | "lib": [ 25 | "esnext", 26 | "dom", 27 | "dom.iterable", 28 | "scripthost" 29 | ] 30 | }, 31 | "include": [ 32 | "src/**/*.ts", 33 | "src/**/*.tsx", 34 | "src/**/*.vue", 35 | "tests/**/*.ts", 36 | "tests/**/*.tsx" 37 | ], 38 | "exclude": [ 39 | "node_modules" 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /results/hojongs/vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // https://cli.vuejs.org/config/#pages 3 | pages: { 4 | index: 'src/entry/main.ts', 5 | user: 'src/entry/user.ts', 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /results/imhojeong/.eslinitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist -------------------------------------------------------------------------------- /results/imhojeong/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | browser: true, 5 | node: true, 6 | }, 7 | extends: [ 8 | 'eslint:recommended', 9 | 'plugin:@typescript-eslint/eslint-recommended', 10 | 'plugin:@typescript-eslint/recommended', 11 | ], 12 | plugins: ['prettier', '@typescript-eslint'], 13 | rules: { 14 | 'prettier/prettier': [ 15 | 'error', 16 | { 17 | singleQuote: true, 18 | semi: true, 19 | useTabs: false, 20 | tabWidth: 2, 21 | printWidth: 80, 22 | bracketSpacing: true, 23 | arrowParens: 'avoid', 24 | endOfLine: 'auto', 25 | }, 26 | ], 27 | }, 28 | parserOptions: { 29 | parser: '@typescript-eslint/parser', 30 | }, 31 | }; 32 | -------------------------------------------------------------------------------- /results/imhojeong/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /results/imhojeong/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote" : true, 3 | "parser": "typescript", 4 | "semi": true, 5 | "useTabs" : false, 6 | "tabWidth" : 2, 7 | "printWidth": 120, 8 | "arrowParens": "always", 9 | } -------------------------------------------------------------------------------- /results/imhojeong/README.md: -------------------------------------------------------------------------------- 1 | ### Login Test 페이지 입니다. 2 | 3 | - 부족한 개발 실력으로 한번 작성해 보았습니다. -------------------------------------------------------------------------------- /results/imhojeong/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/imhojeong/public/favicon.ico -------------------------------------------------------------------------------- /results/imhojeong/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/imhojeong/public/logo192.png -------------------------------------------------------------------------------- /results/imhojeong/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/imhojeong/public/logo512.png -------------------------------------------------------------------------------- /results/imhojeong/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /results/imhojeong/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /results/imhojeong/src/app/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /results/imhojeong/src/app/App.tsx: -------------------------------------------------------------------------------- 1 | import LoginPage from '../pages/LoginPage'; 2 | import './App.css'; 3 | 4 | function App(): JSX.Element { 5 | return ( 6 | <> 7 | 8 | 9 | ); 10 | } 11 | 12 | export default App; 13 | -------------------------------------------------------------------------------- /results/imhojeong/src/app/hooks.ts: -------------------------------------------------------------------------------- 1 | import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'; 2 | import type { RootState, AppDispatch } from '../store/store'; 3 | 4 | export const useAppDispatch = () => useDispatch(); 5 | export const useAppSelector: TypedUseSelectorHook = useSelector; 6 | -------------------------------------------------------------------------------- /results/imhojeong/src/app/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /results/imhojeong/src/app/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /results/imhojeong/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /results/imhojeong/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import reportWebVitals from './reportWebVitals'; 5 | import { store } from './store/store'; 6 | import { Provider } from 'react-redux'; 7 | import { Router } from './routes'; 8 | import { ThemeProvider } from 'styled-components'; 9 | import { theme } from './styles/theme'; 10 | import GlobalStyle from './styles/global-style'; 11 | 12 | ReactDOM.render( 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | , 21 | document.getElementById('root') 22 | ); 23 | 24 | // If you want to start measuring performance in your app, pass a function 25 | // to log results (for example: reportWebVitals(console.log)) 26 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 27 | reportWebVitals(); 28 | -------------------------------------------------------------------------------- /results/imhojeong/src/pages/LoginPage.tsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react'; 2 | import { LoginContainer } from '../components/LoginContainer'; 3 | import { store } from '../store/store'; 4 | 5 | function LoginPage(): JSX.Element { 6 | const [isLoggedIn, setIsLoggedIn] = useState(false); 7 | useEffect(() => { 8 | setIsLoggedIn(store.getState().user.isLoggedIn); 9 | }, [isLoggedIn]); 10 | return ( 11 | <> 12 | 13 | 14 | ); 15 | } 16 | 17 | export default LoginPage; 18 | -------------------------------------------------------------------------------- /results/imhojeong/src/pages/UserInfoPage.tsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react'; 2 | import { UserContainer } from '../components/UserContainer'; 3 | import { store } from '../store/store'; 4 | 5 | function UserInfoPage(): JSX.Element { 6 | const [isLoggedIn, setIsLoggedIn] = useState(false); 7 | useEffect(() => { 8 | setIsLoggedIn(store.getState().user.isLoggedIn); 9 | }, [isLoggedIn]); 10 | return ( 11 | <> 12 | 13 | 14 | ); 15 | } 16 | 17 | export default UserInfoPage; 18 | -------------------------------------------------------------------------------- /results/imhojeong/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /results/imhojeong/src/reducers/user.ts: -------------------------------------------------------------------------------- 1 | import { createSlice, PayloadAction } from '@reduxjs/toolkit'; 2 | import type { RootState } from '../store/store'; 3 | 4 | interface UserState { 5 | id: string; 6 | password: string; 7 | isLoggedIn: boolean; 8 | accessToken: string; 9 | } 10 | 11 | const initialState: UserState = { 12 | id: '', 13 | password: '', 14 | isLoggedIn: false, 15 | accessToken: '', 16 | }; 17 | 18 | export const userSlice = createSlice({ 19 | name: 'user', 20 | initialState, 21 | reducers: { 22 | change: (state, action: PayloadAction) => { 23 | state.id = action.payload[0]; 24 | state.password = action.payload[1]; 25 | }, 26 | changeLoggedState: state => { 27 | state.isLoggedIn = !state.isLoggedIn; 28 | }, 29 | changeAccessToken: (state, action: PayloadAction) => { 30 | state.accessToken = action.payload; 31 | }, 32 | }, 33 | }); 34 | 35 | export const { change, changeLoggedState, changeAccessToken } = 36 | userSlice.actions; 37 | 38 | export const userCount = (state: RootState) => state.user.id; 39 | 40 | export default userSlice.reducer; 41 | -------------------------------------------------------------------------------- /results/imhojeong/src/reportWebVitals.ts: -------------------------------------------------------------------------------- 1 | import { ReportHandler } from 'web-vitals'; 2 | 3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => { 4 | if (onPerfEntry && onPerfEntry instanceof Function) { 5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 6 | getCLS(onPerfEntry); 7 | getFID(onPerfEntry); 8 | getFCP(onPerfEntry); 9 | getLCP(onPerfEntry); 10 | getTTFB(onPerfEntry); 11 | }); 12 | } 13 | }; 14 | 15 | export default reportWebVitals; 16 | -------------------------------------------------------------------------------- /results/imhojeong/src/routes/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { BrowserRouter, Switch, Route, Redirect } from 'react-router-dom'; 3 | import LoginPage from '../pages/LoginPage'; 4 | import UserInfoPage from '../pages/UserInfoPage'; 5 | 6 | export const Router: React.FC = () => ( 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | ); 15 | -------------------------------------------------------------------------------- /results/imhojeong/src/store/store.ts: -------------------------------------------------------------------------------- 1 | import { configureStore } from '@reduxjs/toolkit'; 2 | import userReducer from '../reducers/user'; 3 | 4 | export const store = configureStore({ 5 | reducer: { 6 | user: userReducer, 7 | }, 8 | }); 9 | 10 | export type RootState = ReturnType; 11 | 12 | export type AppDispatch = typeof store.dispatch; 13 | -------------------------------------------------------------------------------- /results/imhojeong/src/styles/global-style.ts: -------------------------------------------------------------------------------- 1 | import { createGlobalStyle } from 'styled-components'; 2 | import { normalize } from 'styled-normalize'; 3 | 4 | export const GlobalStyle = createGlobalStyle` 5 | ${normalize} 6 | 7 | html, 8 | body { 9 | overflow: hidden; 10 | } 11 | 12 | * { 13 | box-sizing: border-box; 14 | } 15 | 16 | `; 17 | 18 | export default GlobalStyle; 19 | -------------------------------------------------------------------------------- /results/imhojeong/src/styles/styled.d.ts: -------------------------------------------------------------------------------- 1 | import 'styled-components'; 2 | 3 | declare module 'styled-components' { 4 | export interface DefaultTheme { 5 | basicWidth: string; 6 | 7 | color: { 8 | main: string; 9 | sub: string; 10 | }; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /results/imhojeong/src/styles/theme.ts: -------------------------------------------------------------------------------- 1 | import { DefaultTheme } from 'styled-components'; 2 | 3 | const theme: DefaultTheme = { 4 | basicWidth: '320px', 5 | 6 | color: { 7 | main: '#1c1f25', 8 | sub: '#fff', 9 | }, 10 | }; 11 | 12 | const nextTheme: DefaultTheme = { 13 | basicWidth: '320px', 14 | 15 | color: { 16 | main: '#1c1f25', 17 | sub: '#fff', 18 | }, 19 | }; 20 | 21 | export { theme, nextTheme }; 22 | -------------------------------------------------------------------------------- /results/imhojeong/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | 10 | "noImplicitAny": true, 11 | "allowJs": true, 12 | "skipLibCheck": true, 13 | "esModuleInterop": true, 14 | "allowSyntheticDefaultImports": true, 15 | "strict": true, 16 | "forceConsistentCasingInFileNames": true, 17 | "noFallthroughCasesInSwitch": true, 18 | "module": "esnext", 19 | "moduleResolution": "node", 20 | "resolveJsonModule": true, 21 | "isolatedModules": true, 22 | "noEmit": true, 23 | "jsx": "react-jsx", 24 | "outDir" : "./dist", 25 | "typeRoots": ["./node_modules/@types", "types"] 26 | }, 27 | "include": [ 28 | "src", 29 | "./src/**/*" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /results/jho2301/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true, 5 | "node": true 6 | }, 7 | "extends": [ 8 | "eslint:recommended", 9 | "plugin:react/recommended", 10 | "plugin:@typescript-eslint/recommended" 11 | ], 12 | "parser": "@typescript-eslint/parser", 13 | "parserOptions": { 14 | "ecmaFeatures": { 15 | "jsx": true 16 | }, 17 | "ecmaVersion": 12, 18 | "sourceType": "module" 19 | }, 20 | "plugins": ["react", "@typescript-eslint"], 21 | "rules": { 22 | "react/react-in-jsx-scope": "off", 23 | "@typescript-eslint/explicit-module-boundary-types": "off", 24 | "@typescript-eslint/no-empty-function": "off" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /results/jho2301/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "singleQuote": true, 4 | "quoteProps": "consistent" 5 | } 6 | -------------------------------------------------------------------------------- /results/jho2301/.storybook/main.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "stories": [ 3 | "../src/**/*.stories.mdx", 4 | "../src/**/*.stories.@(js|jsx|ts|tsx)" 5 | ], 6 | "addons": [ 7 | "@storybook/addon-links", 8 | "@storybook/addon-essentials" 9 | ] 10 | } -------------------------------------------------------------------------------- /results/jho2301/.storybook/preview.js: -------------------------------------------------------------------------------- 1 | import { RecoilRoot } from 'recoil'; 2 | import GlobalStyle from '../src/Global.styles'; 3 | 4 | export const parameters = { 5 | actions: { argTypesRegex: '^on[A-Z].*' }, 6 | controls: { 7 | matchers: { 8 | color: /(background|color)$/i, 9 | date: /Date$/, 10 | }, 11 | }, 12 | }; 13 | 14 | export const decorators = [ 15 | (Story) => ( 16 | <> 17 | 18 | 19 |
20 | 21 |
22 |
23 | 24 | ), 25 | ]; 26 | -------------------------------------------------------------------------------- /results/jho2301/README.md: -------------------------------------------------------------------------------- 1 | ## Pilot React App 2 | 3 | 로그인 과정을 구현합니다! 4 | -------------------------------------------------------------------------------- /results/jho2301/REQUIREMENTS.md: -------------------------------------------------------------------------------- 1 | # 기능 요구 사항 2 | 3 | - 사용자는 로그인을 할 수 있다. 4 | 5 | - 회원이 아닐시 에러를 표시한다. 6 | 7 | - 사용자는 로그아웃을 할 수 있다. 8 | 9 | - 로그인한 사용자는 회원정보를 확인할 수 있다. 10 | -------------------------------------------------------------------------------- /results/jho2301/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | React Pilot App 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /results/jho2301/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { Suspense } from 'react'; 2 | import { ErrorBoundary } from 'react-error-boundary'; 3 | import { Switch } from 'react-router-dom'; 4 | import { useRecoilValue } from 'recoil'; 5 | 6 | import PrivateRoute from './components/PrivateRoute/PrivateRoute'; 7 | import LoginPage from './pages/Login/LoginPage'; 8 | import UserPage from './pages/User/UserPage'; 9 | import { accessTokenState } from './state/login'; 10 | 11 | const App = () => { 12 | const accessToken = useRecoilValue(accessTokenState); 13 | 14 | return ( 15 |
16 | 17 | 24 | error발생!
}> 25 | 26 | 32 | 33 | 34 | 35 | 36 | ); 37 | }; 38 | 39 | export default App; 40 | -------------------------------------------------------------------------------- /results/jho2301/src/Global.styles.ts: -------------------------------------------------------------------------------- 1 | import { createGlobalStyle } from 'styled-components'; 2 | import reset from 'styled-reset'; 3 | 4 | import PALETTE from '../src/constants/palette'; 5 | 6 | const GlobalStyle = createGlobalStyle` 7 | ${reset} 8 | 9 | * { 10 | box-sizing: border-box; 11 | outline: none; 12 | color: ${PALETTE.GRAY_900}; 13 | user-select: none; 14 | } 15 | `; 16 | 17 | export default GlobalStyle; 18 | -------------------------------------------------------------------------------- /results/jho2301/src/__test__/setupTests.ts: -------------------------------------------------------------------------------- 1 | import { server } from '../mock/server'; 2 | 3 | beforeAll(() => { 4 | global.fetch = require('node-fetch'); 5 | server.listen(); 6 | }); 7 | 8 | afterEach(() => { 9 | server.resetHandlers(); 10 | }); 11 | 12 | afterAll(() => { 13 | server.close(); 14 | }); 15 | -------------------------------------------------------------------------------- /results/jho2301/src/__test__/testUtil.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react'; 2 | import { Suspense } from 'react'; 3 | import { BrowserRouter } from 'react-router-dom'; 4 | import { RecoilRoot } from 'recoil'; 5 | 6 | export const createPushMock = () => { 7 | const pushMock = jest.fn(); 8 | 9 | jest.mock('react-router-dom', () => ({ 10 | ...Object.assign({}, jest.requireActual('react-router-dom')), 11 | useHistory: () => ({ push: pushMock }), 12 | })); 13 | 14 | return pushMock; 15 | }; 16 | 17 | export const createAlertMock = () => { 18 | const alertMock = jest.fn(); 19 | 20 | global.alert = alertMock; 21 | 22 | return alertMock; 23 | }; 24 | 25 | export const myRender = (children: React.ReactNode) => 26 | render( 27 | 28 | 29 | {children} 30 | 31 | 32 | ); 33 | -------------------------------------------------------------------------------- /results/jho2301/src/__test__/user.test.tsx: -------------------------------------------------------------------------------- 1 | import { fireEvent, screen, waitFor } from '@testing-library/react'; 2 | 3 | import UserPage from '../pages/User/UserPage'; 4 | import { myRender } from './testUtil'; 5 | 6 | describe('USER', () => { 7 | test('로그인한 사용자는 회원정보를 확인할 수 있다.', async () => { 8 | myRender(); 9 | 10 | await screen.findByText(/닉네임/g); 11 | await screen.findByText(/999/g); 12 | }); 13 | 14 | test('사용자는 로그아웃을 할 수 있다.', async () => { 15 | myRender(); 16 | 17 | const $logoutButton = screen.getByText('로그아웃'); 18 | 19 | fireEvent.click($logoutButton); 20 | 21 | await waitFor(() => expect(window.location.pathname).toEqual('/login')); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /results/jho2301/src/components/@shared/Button/Button.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import Button from './Button'; 4 | 5 | export default { 6 | title: 'Components/shared/Button', 7 | component: Button, 8 | } as Meta; 9 | 10 | const Template: Story = (args) => { 11 | return ; 12 | }; 13 | 14 | export const Default = Template.bind({}); 15 | 16 | Default.args = {}; 17 | -------------------------------------------------------------------------------- /results/jho2301/src/components/@shared/Button/Button.styles.ts: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | import PALETTE from '../../../constants/palette'; 4 | 5 | const StyledButton = styled.button` 6 | background-color: transparent; 7 | border: 1px solid ${PALETTE.GRAY_400}; 8 | padding: 0.75rem 2rem; 9 | border-radius: 0.375rem; 10 | cursor: pointer; 11 | transition: 0.2s all; 12 | width: 100%; 13 | 14 | &:hover { 15 | background-color: ${PALETTE.GRAY_100}; 16 | border: 1px solid ${PALETTE.GRAY_200}; 17 | } 18 | 19 | &:active { 20 | background-color: ${PALETTE.GRAY_200}; 21 | border: 1px solid ${PALETTE.GRAY_400}; 22 | } 23 | `; 24 | 25 | export default StyledButton; 26 | -------------------------------------------------------------------------------- /results/jho2301/src/components/@shared/Button/Button.tsx: -------------------------------------------------------------------------------- 1 | import { ButtonHTMLAttributes } from 'react'; 2 | 3 | import StyledButton from './Button.styles'; 4 | 5 | const Button = ({ children, ...props }: ButtonHTMLAttributes) => { 6 | return {children}; 7 | }; 8 | 9 | export default Button; 10 | -------------------------------------------------------------------------------- /results/jho2301/src/components/@shared/Input/Input.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import Input from './Input'; 4 | 5 | export default { 6 | title: 'Components/shared/Input', 7 | component: Input, 8 | } as Meta; 9 | 10 | const Template: Story = (args) => { 11 | return ; 12 | }; 13 | 14 | export const Default = Template.bind({}); 15 | 16 | Default.args = { 17 | placeholder: '입력해주세요.', 18 | }; 19 | -------------------------------------------------------------------------------- /results/jho2301/src/components/@shared/Input/Input.styles.ts: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | import PALETTE from '../../../constants/palette'; 4 | 5 | const StyledInput = styled.input` 6 | border: none; 7 | border-bottom: 1px solid ${PALETTE.GRAY_200}; 8 | padding: 0.5rem; 9 | width: 100%; 10 | transition: 0.8s border-bottom; 11 | 12 | &:focus { 13 | border-bottom: 1px solid ${PALETTE.GRAY_900}; 14 | } 15 | 16 | &::placeholder { 17 | color: ${PALETTE.GRAY_400}; 18 | } 19 | `; 20 | 21 | export default StyledInput; 22 | -------------------------------------------------------------------------------- /results/jho2301/src/components/@shared/Input/Input.tsx: -------------------------------------------------------------------------------- 1 | import { InputHTMLAttributes } from 'react'; 2 | import StyledInput from './Input.styles'; 3 | 4 | const Input = (props: InputHTMLAttributes) => { 5 | return ; 6 | }; 7 | 8 | export default Input; 9 | -------------------------------------------------------------------------------- /results/jho2301/src/components/@shared/Template/Template.styles.ts: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const StyledTemplate = styled.main` 4 | width: 100vw; 5 | height: 100vh; 6 | display: flex; 7 | justify-content: center; 8 | align-items: center; 9 | `; 10 | -------------------------------------------------------------------------------- /results/jho2301/src/components/@shared/Template/Template.tsx: -------------------------------------------------------------------------------- 1 | import { StyledTemplate } from './Template.styles'; 2 | 3 | interface TemplateProps { 4 | children: React.ReactNode; 5 | } 6 | 7 | const Template = ({ children }: TemplateProps) => { 8 | return {children}; 9 | }; 10 | 11 | export default Template; 12 | -------------------------------------------------------------------------------- /results/jho2301/src/components/Login/Form/LoginForm.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import LoginForm from './LoginForm'; 4 | 5 | export default { 6 | title: 'Components/LoginForm', 7 | component: LoginForm, 8 | } as Meta; 9 | 10 | const Template: Story = (args) => { 11 | return ; 12 | }; 13 | 14 | export const Default = Template.bind({}); 15 | 16 | Default.args = {}; 17 | -------------------------------------------------------------------------------- /results/jho2301/src/components/Login/Form/LoginForm.styles.ts: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import PALETTE from '../../../constants/palette'; 3 | import Input from '../../@shared/Input/Input'; 4 | 5 | export const StyledLoginForm = styled.form` 6 | width: 26rem; 7 | display: flex; 8 | flex-direction: column; 9 | padding: 2.25rem 3rem 2rem; 10 | border: 1px solid ${PALETTE.GRAY_200}; 11 | align-items: center; 12 | border-radius: 1rem; 13 | `; 14 | 15 | export const LoginTitle = styled.h1` 16 | font-size: 1.75rem; 17 | font-weight: 700; 18 | margin-bottom: 2.25rem; 19 | `; 20 | 21 | export const LoginInput = styled(Input)` 22 | margin-bottom: 2rem; 23 | 24 | & + & { 25 | margin-bottom: 1rem; 26 | } 27 | `; 28 | 29 | export const MemoryCheckboxLabel = styled.label` 30 | display: flex; 31 | align-items: center; 32 | align-self: flex-end; 33 | margin-bottom: 2rem; 34 | font-size: 0.75rem; 35 | `; 36 | -------------------------------------------------------------------------------- /results/jho2301/src/components/PrivateRoute/PrivateRoute.tsx: -------------------------------------------------------------------------------- 1 | import { Redirect, Route, RouteProps, useHistory } from 'react-router-dom'; 2 | 3 | interface PrivateRouteProps extends RouteProps { 4 | isAuthed: boolean; 5 | redirectTo: string; 6 | } 7 | 8 | const PrivateRoute = ({ isAuthed, redirectTo, ...props }: PrivateRouteProps) => { 9 | return isAuthed ? : ; 10 | }; 11 | 12 | export default PrivateRoute; 13 | -------------------------------------------------------------------------------- /results/jho2301/src/components/User/UserInfo/UserInfo.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import UserInfo from './UserInfo'; 4 | 5 | export default { 6 | title: 'Components/UserInfo', 7 | component: UserInfo, 8 | } as Meta; 9 | 10 | const Template: Story = (args) => { 11 | return ; 12 | }; 13 | 14 | export const Default = Template.bind({}); 15 | 16 | Default.args = {}; 17 | -------------------------------------------------------------------------------- /results/jho2301/src/components/User/UserInfo/UserInfo.styles.ts: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import PALETTE from '../../../constants/palette'; 3 | import Button from '../../@shared/Button/Button'; 4 | import Input from '../../@shared/Input/Input'; 5 | 6 | export const StyledUserInfo = styled.section` 7 | width: 26rem; 8 | height: 20rem; 9 | display: flex; 10 | flex-direction: column; 11 | padding: 0 3rem; 12 | border: 1px solid ${PALETTE.GRAY_200}; 13 | align-items: center; 14 | border-radius: 1rem; 15 | `; 16 | 17 | export const UserInfoTitle = styled.h1` 18 | font-size: 1.75rem; 19 | font-weight: 700; 20 | margin: 2.25rem 0; 21 | `; 22 | 23 | export const UserInfoText = styled.p` 24 | font-size: 1.125rem; 25 | font-weight: 500; 26 | margin: 1.5rem 0; 27 | align-self: flex-start; 28 | `; 29 | 30 | export const LogoutButton = styled(Button)` 31 | margin-top: 1rem; 32 | `; 33 | -------------------------------------------------------------------------------- /results/jho2301/src/components/User/UserInfo/UserInfo.tsx: -------------------------------------------------------------------------------- 1 | import { LogoutButton, StyledUserInfo, UserInfoText, UserInfoTitle } from './UserInfo.styles'; 2 | import useUser from '../../../service/hooks/useUser'; 3 | import useAuth from '../../../service/hooks/useAuth'; 4 | 5 | const UserInfo = () => { 6 | const { userInfo } = useUser(); 7 | const { logout } = useAuth(); 8 | 9 | return ( 10 | 11 | 회원 정보 12 | 이름: {userInfo.name} 13 | 레벨: {userInfo.level} 14 | 로그아웃 15 | 16 | ); 17 | }; 18 | 19 | export default UserInfo; 20 | -------------------------------------------------------------------------------- /results/jho2301/src/constants/palette.ts: -------------------------------------------------------------------------------- 1 | const PALETTE = { 2 | GRAY_100: '#eeeeee', 3 | GRAY_200: '#dddddd', 4 | GRAY_400: '#999999', 5 | GRAY_600: '#777777', 6 | GRAY_800: '#555555', 7 | GRAY_900: '#222222', 8 | 9 | GREEN_200: '#ebffeb', 10 | GREEN_300: '##d9fad9', 11 | GREEN_400: '#b2f7b0', 12 | GREEN_500: '#9ad698', 13 | GREEN_600: '#8bc28a', 14 | }; 15 | 16 | export default PALETTE; 17 | -------------------------------------------------------------------------------- /results/jho2301/src/constants/storage.ts: -------------------------------------------------------------------------------- 1 | export const STORAGE_KEY = { 2 | ACCESS_TOKEN: 'accessToken', 3 | }; 4 | -------------------------------------------------------------------------------- /results/jho2301/src/index.tsx: -------------------------------------------------------------------------------- 1 | import ReactDOM from 'react-dom'; 2 | import { BrowserRouter } from 'react-router-dom'; 3 | import { RecoilRoot } from 'recoil'; 4 | 5 | import App from './App'; 6 | import GlobalStyle from './Global.styles'; 7 | 8 | const $root = document.getElementById('root'); 9 | 10 | ReactDOM.render( 11 | <> 12 | 13 | 14 | 15 | 16 | 17 | 18 | , 19 | $root 20 | ); 21 | -------------------------------------------------------------------------------- /results/jho2301/src/mock/handlers.ts: -------------------------------------------------------------------------------- 1 | import { LoginForm, User } from './../types'; 2 | import { rest } from 'msw'; 3 | 4 | export const loginHandlers = [ 5 | rest.post('http://localhost:5000/auth/login', (req, res, ctx) => { 6 | const { account, password } = req.body; 7 | 8 | if (account !== 'devbadak' || password !== '1234') { 9 | return res(ctx.status(400), ctx.json({ message: 'wrong!' })); 10 | } 11 | 12 | return res( 13 | ctx.json({ 14 | accessToken: 'xxxxxxxxxxxxxxx', 15 | }) 16 | ); 17 | }), 18 | rest.get('http://localhost:5000/auth/logout', (req, res, ctx) => { 19 | return res(ctx.status(204), ctx.text('')); 20 | }), 21 | ]; 22 | 23 | export const userHandlers = [ 24 | rest.get('http://localhost:5000/v1/users/me', (req, res, ctx) => { 25 | return res( 26 | ctx.json({ 27 | name: '닉네임', 28 | level: 999, 29 | }) 30 | ); 31 | }), 32 | ]; 33 | -------------------------------------------------------------------------------- /results/jho2301/src/mock/server.ts: -------------------------------------------------------------------------------- 1 | import { loginHandlers, userHandlers } from './handlers'; 2 | import { setupServer } from 'msw/node'; 3 | 4 | export const server = setupServer(...loginHandlers, ...userHandlers); 5 | -------------------------------------------------------------------------------- /results/jho2301/src/pages/Login/LoginPage.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import LoginPage from './LoginPage'; 4 | 5 | export default { 6 | title: 'Pages/Login', 7 | component: LoginPage, 8 | } as Meta; 9 | 10 | const Template: Story = (args) => { 11 | return ; 12 | }; 13 | 14 | export const Default = Template.bind({}); 15 | 16 | Default.args = {}; 17 | -------------------------------------------------------------------------------- /results/jho2301/src/pages/Login/LoginPage.tsx: -------------------------------------------------------------------------------- 1 | import LoginForm from '../../components/Login/Form/LoginForm'; 2 | import Template from '../../components/@shared/Template/Template'; 3 | 4 | const LoginPage = () => { 5 | return ( 6 | 9 | ); 10 | }; 11 | 12 | export default LoginPage; 13 | -------------------------------------------------------------------------------- /results/jho2301/src/pages/User/UserPage.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import UserPage from './UserPage'; 4 | 5 | export default { 6 | title: 'Pages/User', 7 | component: UserPage, 8 | } as Meta; 9 | 10 | const Template: Story = (args) => { 11 | return ; 12 | }; 13 | 14 | export const Default = Template.bind({}); 15 | 16 | Default.args = {}; 17 | -------------------------------------------------------------------------------- /results/jho2301/src/pages/User/UserPage.tsx: -------------------------------------------------------------------------------- 1 | import Template from '../../components/@shared/Template/Template'; 2 | import UserInfo from '../../components/User/UserInfo/UserInfo'; 3 | 4 | const LoginPage = () => { 5 | return ( 6 | 9 | ); 10 | }; 11 | 12 | export default LoginPage; 13 | -------------------------------------------------------------------------------- /results/jho2301/src/service/auth.ts: -------------------------------------------------------------------------------- 1 | import { STORAGE_KEY } from '../constants/storage'; 2 | 3 | export const clearAccessTokenStorage = () => { 4 | sessionStorage.removeItem(STORAGE_KEY.ACCESS_TOKEN); 5 | localStorage.removeItem(STORAGE_KEY.ACCESS_TOKEN); 6 | }; 7 | -------------------------------------------------------------------------------- /results/jho2301/src/service/hooks/useLoginForm.ts: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | 3 | import { LoginForm } from './../../types'; 4 | 5 | const useLoginForm = () => { 6 | const [form, setForm] = useState({ account: '', password: '' }); 7 | const [willTokenStored, setWillTokenStored] = useState(false); 8 | 9 | const setAccount = (account: string) => setForm({ ...form, account }); 10 | 11 | const setPassword = (password: string) => setForm({ ...form, password }); 12 | 13 | return { form, willTokenStored, setAccount, setPassword, setWillTokenStored }; 14 | }; 15 | 16 | export default useLoginForm; 17 | -------------------------------------------------------------------------------- /results/jho2301/src/service/hooks/useUser.ts: -------------------------------------------------------------------------------- 1 | import { useRecoilValueLoadable, useSetRecoilState } from 'recoil'; 2 | 3 | import { clearAccessTokenStorage } from '../../service/auth'; 4 | import { accessTokenState } from '../../state/login'; 5 | import { userInfoQuery } from '../../state/user'; 6 | import { User } from '../../types'; 7 | 8 | const useUser = () => { 9 | const userInfoLoadable = useRecoilValueLoadable(userInfoQuery); 10 | const setAccessToken = useSetRecoilState(accessTokenState); 11 | 12 | const userInfo: User = 13 | userInfoLoadable.state === 'hasValue' 14 | ? userInfoLoadable.contents 15 | : { account: '', name: '', id: -1, level: -1 }; 16 | 17 | if (userInfoLoadable.state === 'hasError') { 18 | clearAccessTokenStorage(); 19 | setAccessToken(''); 20 | } 21 | 22 | return { userInfo }; 23 | }; 24 | 25 | export default useUser; 26 | -------------------------------------------------------------------------------- /results/jho2301/src/service/request/index.ts: -------------------------------------------------------------------------------- 1 | import APIClient from '../../util/API'; 2 | 3 | const BASE_URL = 'http://localhost:5000'; 4 | 5 | const apiClient = new APIClient(BASE_URL); 6 | 7 | export default apiClient; 8 | -------------------------------------------------------------------------------- /results/jho2301/src/service/request/login.ts: -------------------------------------------------------------------------------- 1 | import apiClient from '.'; 2 | 3 | import { LoginForm } from './../../types'; 4 | 5 | export const requestLogin = (form: LoginForm): Promise<{ accessToken: string }> => 6 | apiClient.post('/auth/login', form); 7 | 8 | export const requestLogout = () => apiClient.get('/auth/logout'); 9 | -------------------------------------------------------------------------------- /results/jho2301/src/service/request/user.ts: -------------------------------------------------------------------------------- 1 | import apiClient from '.'; 2 | import { User } from '../../types'; 3 | 4 | export const requestGetUserInfo = (accessToken: string) => { 5 | return apiClient.get('/v1/users/me', accessToken); 6 | }; 7 | -------------------------------------------------------------------------------- /results/jho2301/src/state/login.ts: -------------------------------------------------------------------------------- 1 | import { atom } from 'recoil'; 2 | 3 | import { STORAGE_KEY } from '../constants/storage'; 4 | 5 | const getAccessTokenDefaultValue = () => { 6 | const local = localStorage.getItem(STORAGE_KEY.ACCESS_TOKEN); 7 | const session = sessionStorage.getItem(STORAGE_KEY.ACCESS_TOKEN); 8 | 9 | if (local) return local; 10 | if (session) return session; 11 | return ''; 12 | }; 13 | 14 | export const accessTokenState = atom({ 15 | key: 'accessToken', 16 | default: getAccessTokenDefaultValue(), 17 | }); 18 | -------------------------------------------------------------------------------- /results/jho2301/src/state/user.ts: -------------------------------------------------------------------------------- 1 | import { selector } from 'recoil'; 2 | 3 | import { requestGetUserInfo } from '../service/request/user'; 4 | import { User } from '../types'; 5 | import { accessTokenState } from './login'; 6 | 7 | export const userInfoQuery = selector({ 8 | key: 'userInfoQuery', 9 | get: ({ get }) => { 10 | const accessToken = get(accessTokenState); 11 | 12 | return requestGetUserInfo(accessToken); 13 | }, 14 | }); 15 | -------------------------------------------------------------------------------- /results/jho2301/src/types.ts: -------------------------------------------------------------------------------- 1 | export interface LoginForm { 2 | account: string; 3 | password: string; 4 | } 5 | 6 | export type UserId = number; 7 | 8 | export type Level = number; 9 | 10 | export interface User { 11 | id: UserId; 12 | account: string; 13 | name: string; 14 | level: Level; 15 | } 16 | -------------------------------------------------------------------------------- /results/jho2301/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "CommonJS", 4 | "target": "es5", 5 | "jsx": "react-jsx", 6 | "sourceMap": true, 7 | "allowJs": true, 8 | "strict": true, 9 | "allowSyntheticDefaultImports": true, 10 | "esModuleInterop": true 11 | }, 12 | "files": ["src/index.tsx"] 13 | } 14 | -------------------------------------------------------------------------------- /results/kimbiyam/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /results/kimbiyam/README.md: -------------------------------------------------------------------------------- 1 | # Pilot React 2 | 3 | ## Project Stack 4 | 5 | - React 6 | - Typescript 7 | - React Router Dom 8 | - React Query 9 | - jest 10 | - React Testing Library 11 | - Material-Ui 12 | 13 | ### Run 14 | ```shell 15 | $ npm run start 16 | ``` 17 | 18 | ### Test 19 | ```shell 20 | $ npm run test 21 | ``` -------------------------------------------------------------------------------- /results/kimbiyam/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/kimbiyam/public/favicon.ico -------------------------------------------------------------------------------- /results/kimbiyam/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/kimbiyam/public/logo192.png -------------------------------------------------------------------------------- /results/kimbiyam/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/kimbiyam/public/logo512.png -------------------------------------------------------------------------------- /results/kimbiyam/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /results/kimbiyam/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /results/kimbiyam/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { Switch, Route } from "react-router-dom"; 2 | import useCheckUserEffect from "./hooks/useCheckUserEffect"; 3 | import LoginPage from "./pages/LoginPage"; 4 | import NotFoundPage from "./pages/NotFoundPage"; 5 | import UserProfilePage from "./pages/UserProfilePage"; 6 | import tokenStorage from "./utils/tokenStorage"; 7 | 8 | const App = () => { 9 | const isLoggedIn = !!tokenStorage.getToken(); 10 | 11 | useCheckUserEffect({ 12 | isLoggedIn: isLoggedIn, 13 | successPagePath: "/user/profile", 14 | failurePagePath: "/", 15 | }); 16 | 17 | return ( 18 | 19 | 20 | 21 | 22 | 23 | ); 24 | }; 25 | 26 | export default App; 27 | -------------------------------------------------------------------------------- /results/kimbiyam/src/api/apiClient.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { SERVER_URL, TOKEN_PREFIX } from "../constants/constants"; 3 | import tokenStorage from "../utils/tokenStorage"; 4 | 5 | const apiClient = axios.create({ baseURL: SERVER_URL }); 6 | 7 | apiClient.interceptors.request.use((config) => { 8 | const accessToken = tokenStorage.getToken(); 9 | 10 | config.headers.Authorization = `${TOKEN_PREFIX} ${accessToken}` || ""; 11 | 12 | return config; 13 | }); 14 | 15 | export default apiClient; 16 | -------------------------------------------------------------------------------- /results/kimbiyam/src/api/authApi.ts: -------------------------------------------------------------------------------- 1 | import LoginData from "../models/LoginData"; 2 | import apiClient from "./apiClient"; 3 | 4 | const API_LOGIN = "/auth/login"; 5 | const API_LOGOUT = "/auth/logout"; 6 | 7 | const login = async (loginData: LoginData) => { 8 | try { 9 | const response = await apiClient.post(API_LOGIN, loginData.toJson()); 10 | const { data } = response; 11 | 12 | const { accessToken } = data; 13 | 14 | return accessToken; 15 | } catch (e) { 16 | const { message } = e.response.data; 17 | throw message; 18 | } 19 | }; 20 | 21 | const logout = async () => { 22 | try { 23 | const response = await apiClient.get(API_LOGOUT); 24 | const { data } = response; 25 | 26 | return data; 27 | } catch (e) { 28 | throw e; 29 | } 30 | }; 31 | 32 | const authApi = { login, logout }; 33 | 34 | export default authApi; 35 | -------------------------------------------------------------------------------- /results/kimbiyam/src/api/userApi.ts: -------------------------------------------------------------------------------- 1 | import User from "../models/User"; 2 | import apiClient from "./apiClient"; 3 | 4 | const API_USERS_ME = "/v1/users/me"; 5 | 6 | const getUserProfile = async () => { 7 | try { 8 | const response = await apiClient.get(API_USERS_ME); 9 | const { data } = response; 10 | 11 | const user = new User({ ...data }); 12 | 13 | return user; 14 | } catch (e) { 15 | console.error(e); 16 | throw e; 17 | } 18 | }; 19 | 20 | const userApi = { getUserProfile }; 21 | 22 | export default userApi; 23 | -------------------------------------------------------------------------------- /results/kimbiyam/src/components/LoadingBackdrop.tsx: -------------------------------------------------------------------------------- 1 | import { Backdrop, CircularProgress, makeStyles } from "@material-ui/core"; 2 | 3 | const useStyles = makeStyles({ 4 | backdrop: { 5 | zIndex: 10, 6 | color: "#fff", 7 | }, 8 | }); 9 | 10 | export type LoadingBackdropProps = { 11 | open: boolean; 12 | }; 13 | 14 | const LoadingBackdrop = ({ open }: LoadingBackdropProps) => { 15 | const classes = useStyles(); 16 | 17 | return ( 18 | 19 | 20 | 21 | ); 22 | }; 23 | 24 | export default LoadingBackdrop; 25 | -------------------------------------------------------------------------------- /results/kimbiyam/src/components/MainButton.tsx: -------------------------------------------------------------------------------- 1 | import { Button, ButtonProps, makeStyles } from "@material-ui/core"; 2 | 3 | const useStyles = makeStyles({ 4 | button: { 5 | width: "120px", 6 | }, 7 | }); 8 | 9 | export type MainButtonProps = ButtonProps & { 10 | label: string; 11 | }; 12 | 13 | const MainButton = ({ label, ...rest }: MainButtonProps) => { 14 | const classes = useStyles(); 15 | 16 | return ( 17 | 25 | ); 26 | }; 27 | 28 | export default MainButton; 29 | -------------------------------------------------------------------------------- /results/kimbiyam/src/components/MainTextField.tsx: -------------------------------------------------------------------------------- 1 | import { makeStyles, TextField, TextFieldProps } from "@material-ui/core"; 2 | import { memo } from "react"; 3 | 4 | const useStyles = makeStyles({ 5 | input: { 6 | margin: "16px 0", 7 | }, 8 | }); 9 | 10 | export type MainTextFieldProps = TextFieldProps & { 11 | label: string; 12 | }; 13 | 14 | const MainTextField = memo(({ label, ...rest }: MainTextFieldProps) => { 15 | const classes = useStyles(); 16 | 17 | return ( 18 | 24 | ); 25 | }); 26 | 27 | export default MainTextField; 28 | -------------------------------------------------------------------------------- /results/kimbiyam/src/components/PrivateRoute.tsx: -------------------------------------------------------------------------------- 1 | import { Redirect, Route, RouteProps } from "react-router"; 2 | 3 | export type PrivateRouteProps = RouteProps & { 4 | isLoggedIn: boolean; 5 | redirect: string; 6 | }; 7 | 8 | const PrivateRoute = ({ isLoggedIn, redirect, ...rest }: PrivateRouteProps) => { 9 | return isLoggedIn ? : ; 10 | }; 11 | 12 | export default PrivateRoute; 13 | -------------------------------------------------------------------------------- /results/kimbiyam/src/constants/constants.ts: -------------------------------------------------------------------------------- 1 | export const SERVER_URL = "http://localhost:5000"; 2 | export const TOKEN_PREFIX = "Bearer"; 3 | -------------------------------------------------------------------------------- /results/kimbiyam/src/hooks/__test__/useInput.test.tsx: -------------------------------------------------------------------------------- 1 | import { renderHook, act } from "@testing-library/react-hooks"; 2 | import { ChangeEvent } from "react"; 3 | import useInput from "../useInput"; 4 | import faker from "faker"; 5 | 6 | describe("useInput hook", () => { 7 | it("should change value when use onChange function", async () => { 8 | // given 9 | const { result } = renderHook(() => useInput()); 10 | const input = faker.internet.userName(); 11 | 12 | // when 13 | act(() => { 14 | const event = { 15 | target: { 16 | value: input, 17 | }, 18 | } as ChangeEvent; 19 | 20 | result.current.onChange(event); 21 | }); 22 | 23 | //then 24 | expect(result.current.value).toEqual(input); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /results/kimbiyam/src/hooks/useCheckUserEffect.ts: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | import { useHistory } from "react-router-dom"; 3 | 4 | const useCheckUserEffect = ({ 5 | isLoggedIn, 6 | successPagePath, 7 | failurePagePath, 8 | }: { 9 | isLoggedIn: boolean; 10 | successPagePath: string; 11 | failurePagePath: string; 12 | }) => { 13 | const history = useHistory(); 14 | 15 | useEffect(() => { 16 | if (isLoggedIn) { 17 | history.push(successPagePath); 18 | return; 19 | } 20 | 21 | history.push(failurePagePath); 22 | }, [isLoggedIn, successPagePath, failurePagePath, history]); 23 | }; 24 | 25 | export default useCheckUserEffect; 26 | -------------------------------------------------------------------------------- /results/kimbiyam/src/hooks/useInput.ts: -------------------------------------------------------------------------------- 1 | import { ChangeEvent, useState } from "react"; 2 | 3 | const useInput = () => { 4 | const [value, setValue] = useState(""); 5 | 6 | const onChange = (e: ChangeEvent) => { 7 | const { value } = e.target; 8 | setValue(value); 9 | }; 10 | 11 | return { value, onChange }; 12 | }; 13 | 14 | export default useInput; 15 | -------------------------------------------------------------------------------- /results/kimbiyam/src/hooks/useLogin.ts: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import { useHistory } from "react-router-dom"; 3 | import authApi from "../api/authApi"; 4 | import LoginData from "../models/LoginData"; 5 | import tokenStorage from "../utils/tokenStorage"; 6 | 7 | const useLogin = () => { 8 | const history = useHistory(); 9 | const [errMsg, setErrMsg] = useState(""); 10 | const [isLoading, setIsLoading] = useState(false); 11 | 12 | const login = async (loginData: LoginData) => { 13 | try { 14 | setIsLoading(true); 15 | setErrMsg(""); 16 | 17 | const accessToken = await authApi.login(loginData); 18 | 19 | setIsLoading(false); 20 | 21 | tokenStorage.setToken(accessToken); 22 | history.push("/user/profile"); 23 | } catch (e) { 24 | setErrMsg(e); 25 | setIsLoading(false); 26 | } 27 | }; 28 | 29 | return { errMsg, isLoading, login }; 30 | }; 31 | 32 | export default useLogin; 33 | -------------------------------------------------------------------------------- /results/kimbiyam/src/hooks/useUserProfileQuery.ts: -------------------------------------------------------------------------------- 1 | import { AxiosError } from "axios"; 2 | import { useQuery, UseQueryOptions } from "react-query"; 3 | import userApi from "../api/userApi"; 4 | import User from "../models/User"; 5 | 6 | const useUserProfileQuery = ( 7 | options: UseQueryOptions = {} 8 | ) => { 9 | return useQuery("myProfile", userApi.getUserProfile, { ...options }); 10 | }; 11 | 12 | export default useUserProfileQuery; 13 | -------------------------------------------------------------------------------- /results/kimbiyam/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import App from "./App"; 4 | import reportWebVitals from "./reportWebVitals"; 5 | import CssBaseline from "@material-ui/core/CssBaseline"; 6 | import { ThemeProvider } from "@material-ui/styles"; 7 | import { globalTheme } from "./styles/globalTheme"; 8 | import { QueryClientProvider, QueryClient } from "react-query"; 9 | import { BrowserRouter as Router } from "react-router-dom"; 10 | 11 | const queryClient = new QueryClient(); 12 | 13 | ReactDOM.render( 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | , 22 | document.getElementById("root") 23 | ); 24 | 25 | // If you want to start measuring performance in your app, pass a function 26 | // to log results (for example: reportWebVitals(console.log)) 27 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 28 | reportWebVitals(); 29 | -------------------------------------------------------------------------------- /results/kimbiyam/src/models/LoginData.ts: -------------------------------------------------------------------------------- 1 | class LoginData { 2 | constructor(account: string, password: string) { 3 | this._account = account; 4 | this._password = password; 5 | } 6 | 7 | private _account: string; 8 | private _password: string; 9 | 10 | toJson = () => { 11 | return { account: this._account, password: this._password }; 12 | }; 13 | } 14 | 15 | export default LoginData; 16 | -------------------------------------------------------------------------------- /results/kimbiyam/src/models/User.ts: -------------------------------------------------------------------------------- 1 | class User { 2 | constructor({ 3 | id, 4 | account, 5 | name, 6 | level, 7 | }: { 8 | id: number; 9 | account: string; 10 | name: string; 11 | level: number; 12 | }) { 13 | this._id = id; 14 | this._account = account; 15 | this._name = name; 16 | this._level = level; 17 | } 18 | 19 | private _id: number; 20 | private _account: string; 21 | private _name: string; 22 | private _level: number; 23 | 24 | getId = () => this._id; 25 | getAccount = () => this._account; 26 | getName = () => this._name; 27 | getLevel = () => this._level; 28 | } 29 | 30 | export default User; 31 | -------------------------------------------------------------------------------- /results/kimbiyam/src/pages/LoginPage.tsx: -------------------------------------------------------------------------------- 1 | import { makeStyles, Box } from "@material-ui/core"; 2 | import LoginForm from "../components/LoginForm"; 3 | 4 | const useStyles = makeStyles({ 5 | box: { 6 | width: "100%", 7 | height: "100%", 8 | display: "flex", 9 | flexDirection: "column", 10 | justifyContent: "center", 11 | alignItems: "center", 12 | }, 13 | inner: { 14 | width: "50%", 15 | height: "50%", 16 | border: "black 1px solid", 17 | display: "flex", 18 | flexDirection: "column", 19 | justifyContent: "center", 20 | alignItems: "center", 21 | }, 22 | }); 23 | 24 | const LoginPage = () => { 25 | const classes = useStyles(); 26 | 27 | return ( 28 | 29 | 30 | 31 | ); 32 | }; 33 | 34 | export default LoginPage; 35 | -------------------------------------------------------------------------------- /results/kimbiyam/src/pages/NotFoundPage.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from "@material-ui/core"; 2 | 3 | export type NotFoundPageProps = {}; 4 | 5 | const NotFoundPage = () => { 6 | return Not Found!; 7 | }; 8 | 9 | export default NotFoundPage; 10 | -------------------------------------------------------------------------------- /results/kimbiyam/src/pages/UserProfilePage.tsx: -------------------------------------------------------------------------------- 1 | import { makeStyles } from "@material-ui/core/styles"; 2 | import UserProfile from "../components/UserProfile"; 3 | import { Box, CircularProgress } from "@material-ui/core"; 4 | import useUserProfileQuery from "../hooks/useUserProfileQuery"; 5 | import tokenStorage from "../utils/tokenStorage"; 6 | import { useHistory } from "react-router-dom"; 7 | import authApi from "../api/authApi"; 8 | 9 | const useStyles = makeStyles({ 10 | box: { 11 | width: "100%", 12 | height: "100%", 13 | display: "flex", 14 | justifyContent: "center", 15 | alignItems: "center", 16 | }, 17 | }); 18 | 19 | const UserProfilePage = () => { 20 | const classes = useStyles(); 21 | const history = useHistory(); 22 | const { data: user, isLoading, isSuccess } = useUserProfileQuery(); 23 | 24 | const handleOnClickLogout = async () => { 25 | await authApi.logout(); 26 | tokenStorage.clearToken(); 27 | history.push("/"); 28 | }; 29 | 30 | return ( 31 | 32 | {isLoading && } 33 | {isSuccess && user && ( 34 | 35 | )} 36 | 37 | ); 38 | }; 39 | 40 | export default UserProfilePage; 41 | -------------------------------------------------------------------------------- /results/kimbiyam/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /results/kimbiyam/src/reportWebVitals.ts: -------------------------------------------------------------------------------- 1 | import { ReportHandler } from 'web-vitals'; 2 | 3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => { 4 | if (onPerfEntry && onPerfEntry instanceof Function) { 5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 6 | getCLS(onPerfEntry); 7 | getFID(onPerfEntry); 8 | getFCP(onPerfEntry); 9 | getLCP(onPerfEntry); 10 | getTTFB(onPerfEntry); 11 | }); 12 | } 13 | }; 14 | 15 | export default reportWebVitals; 16 | -------------------------------------------------------------------------------- /results/kimbiyam/src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /results/kimbiyam/src/styles/globalTheme.ts: -------------------------------------------------------------------------------- 1 | import { createTheme } from "@material-ui/core"; 2 | 3 | export const globalTheme = createTheme({ 4 | overrides: { 5 | MuiCssBaseline: { 6 | "@global": { 7 | "html, body, div#root": { 8 | width: "100%", 9 | height: "100%", 10 | }, 11 | }, 12 | }, 13 | }, 14 | }); 15 | -------------------------------------------------------------------------------- /results/kimbiyam/src/utils/tokenStorage.ts: -------------------------------------------------------------------------------- 1 | const ACCESS_TOKEN = "ACCESS_TOKEN"; 2 | 3 | const getToken = () => { 4 | return localStorage.getItem(ACCESS_TOKEN); 5 | }; 6 | 7 | const setToken = (accessToken: string) => { 8 | localStorage.setItem(ACCESS_TOKEN, accessToken); 9 | }; 10 | 11 | const clearToken = () => { 12 | localStorage.removeItem(ACCESS_TOKEN); 13 | }; 14 | 15 | const tokenStorage = { 16 | getToken, 17 | setToken, 18 | clearToken, 19 | }; 20 | 21 | export default tokenStorage; 22 | -------------------------------------------------------------------------------- /results/kimbiyam/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx" 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /results/leehaeun0/.env.development: -------------------------------------------------------------------------------- 1 | REACT_APP_BASEURL=http://localhost:5000 -------------------------------------------------------------------------------- /results/leehaeun0/.env.production: -------------------------------------------------------------------------------- 1 | REACT_APP_BASEURL=http://localhost:5000 -------------------------------------------------------------------------------- /results/leehaeun0/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | plugins: ['@typescript-eslint', 'simple-import-sort', 'prettier', 'react', 'react-hooks'], 4 | extends: [ 5 | 'plugin:react/recommended', 6 | 'plugin:import/errors', 7 | 'plugin:import/warnings', 8 | 'plugin:@typescript-eslint/recommended', 9 | 'plugin:prettier/recommended', 10 | 'prettier', 11 | ], 12 | rules: { 13 | // eslint rules 14 | 'react/prop-types': 'off', 15 | 'react/jsx-filename-extension': 0, 16 | '@typescript-eslint/explicit-module-boundary-types': 'off', 17 | // simple-import-sort plugin 18 | 'simple-import-sort/imports': 'warn', 19 | // react-hooks plugin 20 | 'react-hooks/rules-of-hooks': 'error', 21 | 'react-hooks/exhaustive-deps': 'warn', 22 | }, 23 | settings: { 24 | 'import/resolver': { 25 | typescript: {}, 26 | node: { 27 | extensions: ['.js', '.jsx', '.ts', '.tsx'], 28 | }, 29 | }, 30 | }, 31 | }; 32 | -------------------------------------------------------------------------------- /results/leehaeun0/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /results/leehaeun0/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "semi": true, 6 | "singleQuote": true, 7 | "printWidth": 100 8 | } -------------------------------------------------------------------------------- /results/leehaeun0/README.md: -------------------------------------------------------------------------------- 1 | # Pilot React App 2 | 3 | [Leehaeun0](https://github.com/Leehaeun0)'s pilot project based on React 4 | 5 | ## 구현 6 | 7 | ![result](/results/leehaeun0/src/utils/img/result.gif) 8 | 9 | ## 요구사항 10 | 11 | - [x] git (github) 12 | - [x] webstorm 13 | - [x] React 14 | - [x] Typescript 15 | - [ ] Test Case 작성 16 | - [x] 자바스크립트 Object `{}` (type object 포함)의 사용을 하지말아보자! 17 | - [x] API 요청, 응답 데이터는 클래스를 이용 18 | 19 | ## local 실행 20 | 21 | ```bash 22 | $ yarn install 23 | $ yarn start 24 | ``` 25 | 26 | ## 후기 27 | 28 | 리액트는 형식이 자유로운 게 양날의 검이라는 걸 다시 한번 느꼈습니다...ㅎㅎ 컴포넌트나 파일 구조 짜는 게 제일 고민인 것 같습니다. 29 | 테스트 코드는 정말 아쉽지만 혼자서 시간 내서 더 공부해봐야 할 것 같습니다ㅠ 30 | 프론트엔드로 재밌는 이벤트 열어주셔서 감사합니다!! 덕분에 다른 분들 코드도 보면서 공부 많이 되었습니다. 31 | -------------------------------------------------------------------------------- /results/leehaeun0/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/leehaeun0/public/favicon.ico -------------------------------------------------------------------------------- /results/leehaeun0/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/leehaeun0/public/logo192.png -------------------------------------------------------------------------------- /results/leehaeun0/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/leehaeun0/public/logo512.png -------------------------------------------------------------------------------- /results/leehaeun0/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /results/leehaeun0/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /results/leehaeun0/src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import React from 'react'; 3 | 4 | import App from './App'; 5 | 6 | test('renders learn react link', () => { 7 | render(); 8 | const linkElement = screen.getByText(/learn react/i); 9 | expect(linkElement).toBeInTheDocument(); 10 | }); 11 | -------------------------------------------------------------------------------- /results/leehaeun0/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { SnackbarProvider } from 'notistack'; 2 | import React, { Suspense } from 'react'; 3 | import { HelmetProvider } from 'react-helmet-async'; 4 | import { BrowserRouter } from 'react-router-dom'; 5 | import { ThemeProvider } from 'styled-components'; 6 | 7 | import LoadingPage from './pages/LoadingPage'; 8 | import MainRouter from './routes/MainRouter'; 9 | import GlobalStyle from './styles/GlobalStyle'; 10 | import theme from './styles/theme'; 11 | 12 | function App() { 13 | return ( 14 |
15 | 16 | 17 | 18 | 24 | 25 | }> 26 | 27 | 28 | 29 | 30 | 31 | 32 |
33 | ); 34 | } 35 | 36 | export default App; 37 | -------------------------------------------------------------------------------- /results/leehaeun0/src/apis/api.ts: -------------------------------------------------------------------------------- 1 | import axios, { AxiosInstance } from 'axios'; 2 | 3 | import { AsyncFc } from '../hooks/useAsync'; 4 | import Auth from '../utils/auth'; 5 | 6 | export type AuthResponse = { 7 | accessToken: string; 8 | }; 9 | 10 | export type User = { 11 | id: number; 12 | account: string; 13 | name: string; 14 | level: number; 15 | }; 16 | 17 | class Api { 18 | private readonly apiClient: AxiosInstance; 19 | 20 | constructor() { 21 | this.apiClient = axios.create({ 22 | baseURL: process.env.REACT_APP_BASEURL, 23 | timeout: 1000, 24 | }); 25 | } 26 | 27 | public login: AsyncFc = async (config, payload) => { 28 | const response = await this.apiClient.post('/auth/login', payload, config); 29 | 30 | Auth.set(response.data.accessToken); 31 | return response.data; 32 | }; 33 | 34 | public logout: AsyncFc = async (config) => { 35 | const response = await this.apiClient.get('/auth/logout', config); 36 | 37 | Auth.remove(); 38 | return response.data; 39 | }; 40 | 41 | public getUser: AsyncFc = async (config): Promise => { 42 | const response = await this.apiClient.get('/v1/users/me', config); 43 | 44 | return response.data; 45 | }; 46 | } 47 | 48 | export default new Api(); 49 | -------------------------------------------------------------------------------- /results/leehaeun0/src/components/Button.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | interface ButtonProps extends React.ButtonHTMLAttributes { 5 | children: React.ReactChild; 6 | icon?: React.ReactNode | null; 7 | } 8 | 9 | function Button({ children, icon, ...rest }: ButtonProps) { 10 | return ( 11 | 12 | {children} 13 | {icon} 14 | 15 | ); 16 | } 17 | 18 | const StyledButton = styled.button` 19 | display: flex; 20 | align-items: center; 21 | justify-content: center; 22 | width: 100%; 23 | padding: 14px; 24 | color: white; 25 | border: none; 26 | border-radius: 3px; 27 | background-color: ${({ theme }) => theme.color.main}; 28 | 29 | div.MuiCircularProgress-root { 30 | margin-left: 8px; 31 | svg circle { 32 | color: white; 33 | } 34 | } 35 | `; 36 | 37 | export default Button; 38 | -------------------------------------------------------------------------------- /results/leehaeun0/src/components/CenterBox.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | type CenterBoxProps = { 5 | children: React.ReactNode; 6 | }; 7 | 8 | function CenterBox({ children }: CenterBoxProps) { 9 | return ( 10 | 11 |
{children}
12 |
13 | ); 14 | } 15 | 16 | const StyledWrapper = styled.div` 17 | position: fixed; 18 | top: 50%; 19 | left: 50%; 20 | transform: translate(-50%, -50%); 21 | display: flex; 22 | justify-content: center; 23 | width: 460px; 24 | max-width: 90%; 25 | padding: 50px 0; 26 | border-radius: 12px; 27 | background-color: ${({ theme }) => theme.color.white}; 28 | box-shadow: ${({ theme }) => theme.boxShadow}; 29 | 30 | & > div { 31 | width: 73%; 32 | text-align: center; 33 | } 34 | `; 35 | 36 | export default CenterBox; 37 | -------------------------------------------------------------------------------- /results/leehaeun0/src/components/FormInput.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | interface FormInputProps extends React.InputHTMLAttributes { 5 | id: string; 6 | label: string; 7 | } 8 | 9 | function FormInput({ id, label, ...rest }: FormInputProps) { 10 | return ( 11 | <> 12 | 15 | 16 | 17 | ); 18 | } 19 | 20 | const StyledInput = styled.input` 21 | display: block; 22 | min-width: 100%; 23 | max-width: 100%; 24 | width: 300px; 25 | padding: 11px 46px 11px 16px; 26 | font-size: 16px; 27 | border: 1px solid transparent; 28 | border-radius: 3px; 29 | background-color: ${({ theme }) => theme.color.lightGray}; 30 | outline: 0; 31 | transition: all 0.3s; 32 | 33 | &::placeholder { 34 | color: ${({ theme }) => theme.color.gray}; 35 | } 36 | &:focus { 37 | border-color: ${({ theme }) => theme.color.main}; 38 | } 39 | `; 40 | 41 | export default FormInput; 42 | -------------------------------------------------------------------------------- /results/leehaeun0/src/components/Main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | type MainProps = { 5 | children: React.ReactNode; 6 | }; 7 | 8 | function Main({ children }: MainProps) { 9 | return {children}; 10 | } 11 | 12 | const StyledMain = styled.main` 13 | min-height: 100vh; 14 | background-color: ${({ theme }) => theme.color.lightGray}; 15 | `; 16 | 17 | export default Main; 18 | -------------------------------------------------------------------------------- /results/leehaeun0/src/components/ReactHelmet.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Helmet } from 'react-helmet-async'; 3 | 4 | type ReactHelmetProps = { 5 | title: string; 6 | description: string; 7 | }; 8 | 9 | function ReactHelmet({ title, description }: ReactHelmetProps) { 10 | return ( 11 | 12 | {title} 13 | 14 | 15 | ); 16 | } 17 | 18 | export default ReactHelmet; 19 | -------------------------------------------------------------------------------- /results/leehaeun0/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root'), 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /results/leehaeun0/src/pages/LoadingPage.tsx: -------------------------------------------------------------------------------- 1 | import CircularProgress from '@material-ui/core/CircularProgress'; 2 | import React from 'react'; 3 | import styled from 'styled-components'; 4 | 5 | import Main from '../components/Main'; 6 | 7 | const LoadingPage: React.FC = () => { 8 | return ( 9 |
10 | 11 | 12 | 13 |
14 | ); 15 | }; 16 | 17 | const StyledWrapper = styled.div` 18 | position: fixed; 19 | top: 50%; 20 | left: 50%; 21 | transform: translate(-50%, -50%); 22 | z-index: 100; 23 | svg circle { 24 | color: ${({ theme }) => theme.color.main}; 25 | } 26 | `; 27 | 28 | export default LoadingPage; 29 | -------------------------------------------------------------------------------- /results/leehaeun0/src/pages/LoginPage.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import LoginForm from '../components/LoginForm'; 4 | import ReactHelmet from '../components/ReactHelmet'; 5 | 6 | function LoginPage() { 7 | return ( 8 | <> 9 | 10 | 11 | 12 | ); 13 | } 14 | 15 | export default LoginPage; 16 | -------------------------------------------------------------------------------- /results/leehaeun0/src/pages/UserPage.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import ReactHelmet from '../components/ReactHelmet'; 4 | import UserInfo from '../components/UserInfo'; 5 | 6 | function UserPage() { 7 | return ( 8 | <> 9 | 10 | 11 | 12 | ); 13 | } 14 | 15 | export default UserPage; 16 | -------------------------------------------------------------------------------- /results/leehaeun0/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /results/leehaeun0/src/reportWebVitals.ts: -------------------------------------------------------------------------------- 1 | import { ReportHandler } from 'web-vitals'; 2 | 3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => { 4 | if (onPerfEntry && onPerfEntry instanceof Function) { 5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 6 | getCLS(onPerfEntry); 7 | getFID(onPerfEntry); 8 | getFCP(onPerfEntry); 9 | getLCP(onPerfEntry); 10 | getTTFB(onPerfEntry); 11 | }); 12 | } 13 | }; 14 | 15 | export default reportWebVitals; 16 | -------------------------------------------------------------------------------- /results/leehaeun0/src/routes/MainRouter.tsx: -------------------------------------------------------------------------------- 1 | import { lazy } from '@loadable/component'; 2 | import React from 'react'; 3 | import { Redirect, Switch } from 'react-router-dom'; 4 | 5 | import Auth from '../utils/auth'; 6 | import PrivateRoute from './PrivateRoute'; 7 | import PublicRoute from './PublicRoute'; 8 | 9 | const LoginPage = lazy(() => import('../pages/LoginPage')); 10 | const UserPage = lazy(() => import('../pages/UserPage')); 11 | 12 | function MainRouter() { 13 | const accessToken = Auth.get(); 14 | 15 | return ( 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | {accessToken ? : } 24 | 25 | ); 26 | } 27 | 28 | export default MainRouter; 29 | -------------------------------------------------------------------------------- /results/leehaeun0/src/routes/PrivateRoute.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Redirect, Route, RouteProps } from 'react-router-dom'; 3 | 4 | import Auth from '../utils/auth'; 5 | 6 | interface PrivateRouteProps extends RouteProps { 7 | children: React.ReactChild; 8 | path: string; 9 | redirect: string; 10 | } 11 | 12 | function PrivateRoute({ children, path, redirect, ...rest }: PrivateRouteProps) { 13 | const accessToken = Auth.get(); 14 | 15 | return ( 16 | 17 | {accessToken ? children : } 18 | 19 | ); 20 | } 21 | 22 | export default PrivateRoute; 23 | -------------------------------------------------------------------------------- /results/leehaeun0/src/routes/PublicRoute.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Redirect, Route, RouteProps } from 'react-router-dom'; 3 | 4 | import Auth from '../utils/auth'; 5 | 6 | interface PublicRouteProps extends RouteProps { 7 | children: React.ReactChild; 8 | path: string; 9 | redirect: string; 10 | } 11 | 12 | function PublicRoute({ children, path, redirect, ...rest }: PublicRouteProps) { 13 | const accessToken = Auth.get(); 14 | 15 | return ( 16 | 17 | {!accessToken ? children : } 18 | 19 | ); 20 | } 21 | 22 | export default PublicRoute; 23 | -------------------------------------------------------------------------------- /results/leehaeun0/src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /results/leehaeun0/src/styles/GlobalStyle.ts: -------------------------------------------------------------------------------- 1 | import { createGlobalStyle } from 'styled-components'; 2 | import reset from 'styled-reset'; 3 | 4 | import theme from './theme'; 5 | 6 | const GlobalStyle = createGlobalStyle` 7 | ${reset} 8 | 9 | * { 10 | box-sizing: border-box; 11 | color: ${theme.color.black}; 12 | font-size: 16px; 13 | font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Ubuntu,Arial,sans-serif; 14 | } 15 | 16 | .a11yHidden { 17 | position: absolute; 18 | width: 1px; 19 | height: 1px; 20 | overflow: hidden; 21 | margin: -1px; 22 | clip: rect(0, 0, 0, 0); 23 | } 24 | `; 25 | 26 | export default GlobalStyle; 27 | -------------------------------------------------------------------------------- /results/leehaeun0/src/styles/theme.ts: -------------------------------------------------------------------------------- 1 | const theme = { 2 | color: { 3 | white: '#FFFFFF', 4 | lightGray: '#F7F7F7', 5 | gray: '#B0B0B0', 6 | main: '#396afc', 7 | error: '#FF1616', 8 | black: '#222222', 9 | }, 10 | boxShadow: 'rgb(100 100 111 / 15%) 7px 23px 62px', 11 | }; 12 | 13 | export default theme; 14 | -------------------------------------------------------------------------------- /results/leehaeun0/src/utils/auth.ts: -------------------------------------------------------------------------------- 1 | class Auth { 2 | private readonly storageKey: string; 3 | 4 | constructor() { 5 | this.storageKey = 'AUTH_KEY'; 6 | } 7 | 8 | public get = () => sessionStorage.getItem(this.storageKey); 9 | 10 | public set = (token: string) => sessionStorage.setItem(this.storageKey, token); 11 | 12 | public remove = () => sessionStorage.removeItem(this.storageKey); 13 | } 14 | 15 | export default new Auth(); 16 | -------------------------------------------------------------------------------- /results/leehaeun0/src/utils/img/profile-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/leehaeun0/src/utils/img/profile-image.png -------------------------------------------------------------------------------- /results/leehaeun0/src/utils/img/result.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/leehaeun0/src/utils/img/result.gif -------------------------------------------------------------------------------- /results/leehaeun0/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx", 22 | "baseUrl": "./src" 23 | }, 24 | "include": [ 25 | "src" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /results/rolancia/.env.development: -------------------------------------------------------------------------------- 1 | REACT_APP_API_END_POINT = http://localhost:5000 -------------------------------------------------------------------------------- /results/rolancia/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /results/rolancia/README.md: -------------------------------------------------------------------------------- 1 | # Pilot Project 2 | 3 | ## 요구 사항 4 | 5 | - [x] git (github) 6 | - [ ] webstorm // vscode 사용... 7 | - [x] React 8 | - [x] Typescript 9 | - [ ] Test Case 작성 // 미숙 10 | - [x] 자바스크립트 Object {} (type object 포함)의 사용을 하지말아보자! 11 | - [x] API 요청, 응답 데이터는 클래스를 이용 12 | 13 | ## 후기 14 | 15 | 개인적으로 프로젝트 초기 세팅과 테스트 관련해서 부족함을 많이 느꼈습니다... 주니어 개발자를 위해서 이런 이벤트를 기획해주셔서 감사합니다. 16 | -------------------------------------------------------------------------------- /results/rolancia/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rolancia", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.11.4", 7 | "@testing-library/react": "^11.1.0", 8 | "@testing-library/user-event": "^12.1.10", 9 | "@types/jest": "^26.0.15", 10 | "@types/node": "^12.0.0", 11 | "@types/react": "^17.0.0", 12 | "@types/react-dom": "^17.0.0", 13 | "@types/react-router-dom": "^5.1.8", 14 | "axios": "^0.21.1", 15 | "react": "^17.0.2", 16 | "react-dom": "^17.0.2", 17 | "react-scripts": "4.0.3", 18 | "typescript": "^4.1.2", 19 | "web-vitals": "^1.0.1" 20 | }, 21 | "scripts": { 22 | "start": "react-scripts start", 23 | "build": "react-scripts build", 24 | "test": "react-scripts test", 25 | "eject": "react-scripts eject" 26 | }, 27 | "eslintConfig": { 28 | "extends": [ 29 | "react-app", 30 | "react-app/jest" 31 | ] 32 | }, 33 | "browserslist": { 34 | "production": [ 35 | ">0.2%", 36 | "not dead", 37 | "not op_mini all" 38 | ], 39 | "development": [ 40 | "last 1 chrome version", 41 | "last 1 firefox version", 42 | "last 1 safari version" 43 | ] 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /results/rolancia/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/rolancia/public/favicon.ico -------------------------------------------------------------------------------- /results/rolancia/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/rolancia/public/logo192.png -------------------------------------------------------------------------------- /results/rolancia/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaycoke/pilot-react/9098444a3f7b6c3438ed1d8749375ef1278222d0/results/rolancia/public/logo512.png -------------------------------------------------------------------------------- /results/rolancia/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /results/rolancia/src/App.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | justify-content: center; 6 | height: 100vh; 7 | } 8 | -------------------------------------------------------------------------------- /results/rolancia/src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, screen } from '@testing-library/react'; 3 | import App from './App'; 4 | 5 | test('renders learn react link', () => { 6 | render(); 7 | const linkElement = screen.getByText(/learn react/i); 8 | expect(linkElement).toBeInTheDocument(); 9 | }); 10 | -------------------------------------------------------------------------------- /results/rolancia/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import styles from "./App.module.css"; 3 | import { BrowserRouter, Switch, Route } from "react-router-dom"; 4 | import Login from "./components/Login/Login"; 5 | import UserInfo from "./components/UserInfo/UserInfo"; 6 | import { HttpClientProps } from "./model/interfaces"; 7 | 8 | const App: React.FC = ({ httpClient }: HttpClientProps) => { 9 | return ( 10 | 11 | 12 | 13 |
14 | 15 |
16 |
17 | 18 |
19 | 20 |
21 |
22 |
23 |
24 | ); 25 | }; 26 | 27 | export default App; 28 | -------------------------------------------------------------------------------- /results/rolancia/src/components/Login/Login.module.css: -------------------------------------------------------------------------------- 1 | .form { 2 | display: flex; 3 | flex-direction: column; 4 | width: 25em; 5 | } 6 | 7 | .form__row { 8 | display: flex; 9 | width: 100%; 10 | } 11 | 12 | .form__row.two { 13 | display: flex; 14 | justify-content: space-between; 15 | align-items: center; 16 | } 17 | 18 | .input__id, 19 | .input__pwd { 20 | font-size: 1rem; 21 | width: 100%; 22 | padding: 1em; 23 | margin: 0.5em; 24 | border-radius: 0.3em; 25 | outline: none; 26 | border: 0.5px solid #d7dbe6; 27 | } 28 | 29 | .input__id::placeholder, 30 | .input__pwd::placeholder { 31 | color: #c2c4cb; 32 | } 33 | 34 | .save__id { 35 | display: flex; 36 | align-items: center; 37 | } 38 | 39 | #save__id__check { 40 | zoom: 1.5; 41 | } 42 | 43 | .save__id__label { 44 | font-weight: bolder; 45 | } 46 | 47 | .menus { 48 | display: flex; 49 | list-style: none; 50 | padding-left: 0; 51 | } 52 | 53 | .menu { 54 | font-size: 0.8rem; 55 | font-weight: bold; 56 | color: #ab9e9f; 57 | margin: 0.2em; 58 | } 59 | 60 | .menu__btn { 61 | color: #ab9e9f; 62 | } 63 | 64 | .login__btn { 65 | width: 100%; 66 | background-color: #3d5cff; 67 | color: white; 68 | font-size: 1.2rem; 69 | font-weight: bold; 70 | padding: 0.5em 0.3em; 71 | margin: 0.3em; 72 | border-radius: 0.3em; 73 | } 74 | -------------------------------------------------------------------------------- /results/rolancia/src/components/UserInfo/UserInfo.module.css: -------------------------------------------------------------------------------- 1 | .userInfo { 2 | display: flex; 3 | flex-direction: column; 4 | width: 25em; 5 | } 6 | 7 | .userInfo .form__row { 8 | display: flex; 9 | align-items: center; 10 | width: 100%; 11 | } 12 | 13 | .userInfo__label { 14 | flex: 20%; 15 | font-weight: bold; 16 | } 17 | 18 | .userInfo input { 19 | flex: 80%; 20 | } 21 | 22 | .input__id, 23 | .input__pwd { 24 | font-size: 1rem; 25 | width: 100%; 26 | padding: 1em; 27 | margin: 0.5em; 28 | border-radius: 0.3em; 29 | outline: none; 30 | border: 0.5px solid #d7dbe6; 31 | } 32 | 33 | .input__id::placeholder, 34 | .input__pwd::placeholder { 35 | color: #c2c4cb; 36 | } 37 | 38 | .logout__btn { 39 | width: 100%; 40 | background-color: #3d5cff; 41 | color: white; 42 | font-size: 1.2rem; 43 | font-weight: bold; 44 | padding: 0.5em 0.3em; 45 | margin: 0.3em; 46 | border-radius: 0.3em; 47 | } 48 | -------------------------------------------------------------------------------- /results/rolancia/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", 4 | "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; 5 | -webkit-font-smoothing: antialiased; 6 | -moz-osx-font-smoothing: grayscale; 7 | box-sizing: border-box; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; 12 | } 13 | 14 | button { 15 | outline: none; 16 | border: none; 17 | background-color: transparent; 18 | cursor: pointer; 19 | } 20 | -------------------------------------------------------------------------------- /results/rolancia/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import HttpClient from './service/httpClient'; 6 | 7 | const httpClient = new HttpClient(); 8 | 9 | ReactDOM.render( 10 | 11 | 12 | , 13 | document.getElementById('root') 14 | ); 15 | -------------------------------------------------------------------------------- /results/rolancia/src/model/entity.ts: -------------------------------------------------------------------------------- 1 | export class LoginEntity { 2 | constructor(private readonly account: string, private readonly password: string) {} 3 | } 4 | 5 | export class UserEntity { 6 | constructor( 7 | public readonly id: string, 8 | public readonly account: string, 9 | public readonly name: string, 10 | public readonly level: string 11 | ) {} 12 | } 13 | -------------------------------------------------------------------------------- /results/rolancia/src/model/interfaces.ts: -------------------------------------------------------------------------------- 1 | import HttpClient from "../service/httpClient"; 2 | 3 | export interface HttpClientProps { 4 | httpClient: HttpClient; 5 | } 6 | -------------------------------------------------------------------------------- /results/rolancia/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /results/rolancia/src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /results/rolancia/src/test/httpClient.test.ts: -------------------------------------------------------------------------------- 1 | import { LoginEntity } from "../model/entity"; 2 | import HttpClient from "../service/httpClient"; 3 | 4 | // 테스트는... 잘 안되서 나중에 제대로 공부하려고 합니다... 흑흑... 삽질을 엄청했어요.. 5 | describe("httpClient.ts", () => { 6 | it("login test", async () => { 7 | let httpClient = new HttpClient(); 8 | const res = await httpClient.login(new LoginEntity("devbadak", "1234")); 9 | const accessToken = res.data.accessToken; 10 | expect(accessToken).toMatch("idonknow"); 11 | }); 12 | 13 | it("getUserinfo test", async () => { 14 | let httpClient = new HttpClient(); 15 | const userInfo = await httpClient.getUserInfo(); 16 | expect(userInfo).toMatch("maybe... devbadak's info?"); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /results/rolancia/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx" 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | --------------------------------------------------------------------------------