diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..3046430d --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +.idea +.git +.gitignore +.dockerignore +Dockerfile +*.md +*.sh +node_modules diff --git a/.eslintrc b/.eslintrc index 2c8a2a50..49d41fb5 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,132 +1,28 @@ { - "extends": [ - "airbnb-base", - "airbnb/rules/react", - ], - "plugins": [ - "@typescript-eslint", - "simple-import-sort" - ], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaVersion": 2018, - "sourceType": "module" - }, - "rules": { - "react/prefer-stateless-function": 0, - "react/jsx-filename-extension": 0, - "react/jsx-one-expression-per-line": 0, - "react/jsx-props-no-spreading": 0, - "react/state-in-constructor": "off", - "react/destructuring-assignment": "warn", - "react/no-unused-state": "warn", - "react/button-has-type": "warn", - "react/no-array-index-key": "warn", - "react/sort-comp": "off", - "react/prop-types": "warn", - "react/require-default-props": "warn", - "import/prefer-default-export": "warn", - "import/named": "warn", - "import/no-named-as-default": "off", - "import/extensions": [ - "error", - "ignorePackages", - { - "js": "never", - "jsx": "never", - "ts": "never", - "tsx": "never" - } - ], - "@typescript-eslint/type-annotation-spacing": ["warn", { "before": false, "after": true, "overrides": { "colon": { "before": true, "after": true }, "arrow": { "before": true, "after": true } } }], - "arrow-parens": ["warn", "as-needed"], - "no-nested-ternary": "off", - "no-unused-expressions": "off", - "no-unused-vars": "off", - "@typescript-eslint/no-unused-vars": "off", - "no-useless-constructor": "off", - "@typescript-eslint/no-useless-constructor": "warn", - "space-before-function-paren": ["warn", "always"], - "no-spaced-func": "off", - "func-call-spacing": ["warn", "always"], - "no-underscore-dangle": "off", - "no-mixed-spaces-and-tabs": "error", - "no-shadow": "warn", - "max-len": ["warn", 150], - "no-console": ["warn", { "allow": ["warn", "error"] }], - "func-names": "off", - "no-plusplus": ["warn", { - "allowForLoopAfterthoughts": true - }], - "no-trailing-spaces": "warn", - "indent": ["warn", 2], - "semi": ["warn", "always"], - "no-param-reassign": ["warn", { "props": true, "ignorePropertyModificationsFor": ["draft"] }], - "simple-import-sort/sort": [ - 1, - { - "groups": [ - ["^\\u0000"], - [ - "^react$", - "^prop-types$", - "^react-router-dom$", - "^react-redux$", - "^react", - "^styled-components$", - "^[^.]" - ], - [ - "^containers", - "^components", - "^atoms", - "^molecules", - "^organisms", - "^templates", - "^pages" - ], - [ - "^store", - "^hoc", - "^hooks", - "^lib" - ], - [ - "^(static)", - "^(?!(assets|static)($|/))\\w" - ], - ["^\\."] - ] - } - ] + "settings": { + "react": { + "version": "detect" + } }, "env": { - "browser": true + "browser": true, + "node": true, + "jest": true }, - "settings": { - "import/resolver": { - "node": { - "moduleDirectory": ["node_modules", "src", "src/components"], - "extensions": [".js",".jsx",".ts",".tsx"] - } - }, - "import/extensions": [".js",".jsx",".ts",".tsx"], - "import/parsers": { - "@typescript-eslint/parser": [".ts",".tsx"] - } + "extends": [ + "eslint:recommended", + "plugin:react/recommended", + "plugin:react-hooks/recommended", + "plugin:@typescript-eslint/recommended", + "plugin:import/typescript", + "prettier" + ], + "rules": { + "react/prop-types": "warn" }, - "overrides": [ - { - "files": ["*.stories.js", "*.test.js"], - "rules": { - "import/no-extraneous-dependencies": "off", - } - }, - { - "files": ["*.test.js"], - "env": { - "jest": true - } - } - ] + "parser": "@typescript-eslint/parser", + "root": true, + "parserOptions": { + "project": "./tsconfig.json" + } } diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..f214c9eb --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,31 @@ +--- +name: Bug report +about: Create a report to help us improve +title: "[Bug] Bug title" +labels: bug +assignees: '' + +--- + +# Describe the bug + + + +A clear and concise description of what the bug is. + +# To Reproduce + + + +Steps to reproduce the behavior: + +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +# Screenshots + + + +If applicable, add screenshots to help explain your problem. diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md new file mode 100644 index 00000000..175ef281 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -0,0 +1,18 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: issue title +labels: enhancement +assignees: '' + +--- + +# Summary + +It implements ... + +# Tasks + +- [ ] Task 1 +- [ ] Task 2 +- [ ] Task 3 diff --git a/.github/ISSUE_TEMPLATE/issue-template.md b/.github/ISSUE_TEMPLATE/issue-template.md new file mode 100644 index 00000000..bd0e8abb --- /dev/null +++ b/.github/ISSUE_TEMPLATE/issue-template.md @@ -0,0 +1,9 @@ +# Summary + +It implements ... + +# Tasks + +- [ ] Task 1 +- [ ] Task 2 +- [ ] Task 3 diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..60233827 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,13 @@ +# Summary + + + +It closes #issue_number + +# Extra info + +# Images or Screenshots + +# Further Work + +- Do something... diff --git a/.github/workflows/dev-build-image.yaml b/.github/workflows/dev-build-image.yaml new file mode 100644 index 00000000..f8c9a516 --- /dev/null +++ b/.github/workflows/dev-build-image.yaml @@ -0,0 +1,36 @@ +name: Build docker image on push to develop + +on: + push: + branches: ["develop"] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Cache Docker layers + uses: actions/cache@v3 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + - name: Log in to GitHub Container Registry + run: echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u USERNAME --password-stdin + - name: Build and push Image + id: docker-build + uses: docker/build-push-action@v5 + env: + IMAGE_TAG: dev + with: + push: true + tags: "ghcr.io/sparcs-kaist/zabo-front:${{ env.IMAGE_TAG }}" + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache-new + - name: Remove old cache + run: | + rm -rf /tmp/.buildx-cache + mv /tmp/.buildx-cache-new /tmp/.buildx-cache diff --git a/.github/workflows/dev-deploy.yaml b/.github/workflows/dev-deploy.yaml new file mode 100644 index 00000000..be5abca2 --- /dev/null +++ b/.github/workflows/dev-deploy.yaml @@ -0,0 +1,32 @@ +name: Deploy to dev server + +# when dev image build action is completed, run this action +on: + workflow_run: + workflows: ["Build docker image on push to develop"] + types: + - completed + +jobs: + if_workflow_success: + name: Deploy to dev server + runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion == 'success' }} + + steps: + - name: pull the image and restart the container + uses: appleboy/ssh-action@v1.0.0 + with: + host: ${{ secrets.DEV_HOST }} + port: ${{ secrets.DEV_PORT }} + username: ${{ secrets.DEV_USERNAME }} + password: ${{ secrets.DEV_PASSWORD }} + proxy_host: ${{ secrets.DEV_PROXY_HOST }} + proxy_port: ${{ secrets.DEV_PROXY_PORT }} + proxy_username: ${{ secrets.DEV_PROXY_USERNAME }} + proxy_password: ${{ secrets.DEV_PROXY_PASSWORD }} + script_stop: true # stop script if any command has failed + script: | + docker pull ghcr.io/sparcs-kaist/zabo-front:dev + docker rm -f zabo-front + docker run --restart always -d -p ${{ secrets.DEV_CONTAINER_PORT }}:80 --name zabo-front ghcr.io/sparcs-kaist/zabo-front:dev diff --git a/.github/workflows/prod-build-image.yaml b/.github/workflows/prod-build-image.yaml new file mode 100644 index 00000000..03873c47 --- /dev/null +++ b/.github/workflows/prod-build-image.yaml @@ -0,0 +1,40 @@ +name: Build docker image on release tag created + +on: + push: + tags: + - v** + +jobs: + build: + name: Build and push Image to GitHub Container Registry + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Cache Docker layers + uses: actions/cache@v3 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + - name: Log in to GitHub Container Registry + run: echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u USERNAME --password-stdin + - name: Build and push Image + id: docker-build + uses: docker/build-push-action@v5 + env: + IMAGE_TAG: ${{github.ref_name}} + with: + push: true + tags: | + "ghcr.io/sparcs-kaist/zabo-front:${{ env.IMAGE_TAG }}" + "ghcr.io/sparcs-kaist/zabo-front:latest" + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache-new + - name: Remove old cache + run: | + rm -rf /tmp/.buildx-cache + mv /tmp/.buildx-cache-new /tmp/.buildx-cache diff --git a/.github/workflows/prod-deploy.yaml b/.github/workflows/prod-deploy.yaml new file mode 100644 index 00000000..46ea8637 --- /dev/null +++ b/.github/workflows/prod-deploy.yaml @@ -0,0 +1,32 @@ +name: Deploy to prod server + +# when prod image build action is completed, run this action +on: + workflow_run: + workflows: ["Build docker image on release tag created"] + types: + - completed + +jobs: + if_workflow_success: + name: Deploy to dev server + runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion == 'success' }} + + steps: + - name: pull the image and restart the container + uses: appleboy/ssh-action@v1.0.0 + with: + host: ${{ secrets.PROD_HOST }} + port: ${{ secrets.PROD_PORT }} + username: ${{ secrets.PROD_USERNAME }} + password: ${{ secrets.PROD_PASSWORD }} + proxy_host: ${{ secrets.PROD_PROXY_HOST }} + proxy_port: ${{ secrets.PROD_PROXY_PORT }} + proxy_username: ${{ secrets.PROD_PROXY_USERNAME }} + proxy_password: ${{ secrets.PROD_PROXY_PASSWORD }} + script_stop: true # stop script if any command has failed + script: | + docker pull ghcr.io/sparcs-kaist/zabo-front:latest + docker rm -f zabo-front + docker run --restart always -d -p ${{ secrets.PROD_CONTAINER_PORT }}:80 --name zabo-front ghcr.io/sparcs-kaist/zabo-front:latest diff --git a/.github/workflows/prod-release-tag.yaml b/.github/workflows/prod-release-tag.yaml new file mode 100644 index 00000000..2782f047 --- /dev/null +++ b/.github/workflows/prod-release-tag.yaml @@ -0,0 +1,23 @@ +# This workflow was created by Ted Park +# Source: https://medium.com/prnd/github%EC%97%90%EC%84%9C-release-tag-%EC%9E%90%EB%8F%99%EC%9C%BC%EB%A1%9C-%EB%A7%8C%EB%93%A4%EC%96%B4-%EC%A3%BC%EA%B8%B0-1%EB%B6%84%EB%A7%8C%EC%97%90-%EC%84%A4%EC%A0%95-5c09a383fb08 + +name: Create Release Tag on push to main +on: + push: + branches: + - main +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Extract tag version + run: echo "##[set-output name=version;]$(echo '${{ github.event.head_commit.message }}' | egrep -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')" + id: extract_version_name + - name: Create release with tag + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ steps.extract_version_name.outputs.version }} + release_name: ${{ steps.extract_version_name.outputs.version }} diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 00000000..5a182ef1 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +yarn lint-staged diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..dac255d2 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v16.15.1 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..e8433a1c --- /dev/null +++ b/.prettierignore @@ -0,0 +1,12 @@ +build +deploy +.husky +.storybook +docs +public +yarn.lock +package.json +tools +.eslintrc +.stylelintrc +*.md diff --git a/.prettierrc b/.prettierrc index ad7a4d97..bae2e962 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,14 +1,9 @@ { "printWidth": 100, "tabWidth": 2, - "useTabs": true, - "semi": false, - "trailingComma": "es5", - "jsxBracketSameLine": false, - "overrides": [ - { - "files": ".prettierrc", - "options": { "parser": "json" } - } - ] + "useTabs": false, + "semi": true, + "singleQuote": false, + "trailingComma": "all", + "jsxSingleQuote": false } diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..01395d9b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,23 @@ +FROM node:16-alpine AS builder +WORKDIR '/app' + +COPY package.json . +COPY yarn.lock . + +RUN yarn + +COPY . . +RUN yarn build + +FROM node:16-alpine + +WORKDIR '/usr/src/app' + +COPY --from=builder /app/build ./build + +# Install requirements +RUN npm install serve -g + +# Run container +EXPOSE 80 +CMD ["sh", "-c", "serve -s build -l 80"] diff --git a/README.md b/README.md index 2b449559..2b5066eb 100644 --- a/README.md +++ b/README.md @@ -65,11 +65,11 @@ If you're looking for backend codes, you can find it in [here](https://github.co ## Prerequisites -**You’ll need to have Node 8.10.0 or local development and production machine**. You can use [nvm](https://github.com/creationix/nvm#installation) (macOS/Linux) or [nvm-windows](https://github.com/coreybutler/nvm-windows#node-version-manager-nvm-for-windows) to easily switch Node versions between different projects. +**You’ll need to have Node 16.15.1 or local development and production machine**. You can use [nvm](https://github.com/creationix/nvm#installation) (macOS/Linux) or [nvm-windows](https://github.com/coreybutler/nvm-windows#node-version-manager-nvm-for-windows) to easily switch Node versions between different projects. Node.js. That's all you need. ```sh -node -v // v10.16.3 +node -v // v16.15.1 ``` ## Getting Started diff --git a/netlify.toml b/netlify.toml index 86ac32d6..de052586 100644 --- a/netlify.toml +++ b/netlify.toml @@ -1,4 +1,4 @@ [[redirects]] from = "/api/*" - to = "https://dev.zabo.sparcs.org/api/:splat" + to = "https://zabo.dev.sparcs.org/api/:splat" status = 200 diff --git a/package.json b/package.json index bc75302c..d1c684c0 100644 --- a/package.json +++ b/package.json @@ -11,18 +11,15 @@ "eject": "react-scripts eject", "storybook": "start-storybook -p 9009 -s public", "build-storybook": "build-storybook -s public", - "postbuild": "gzipper --verbose --brotli ./build && gzipper --verbose ./build && ./tools/moveBuildFolder.sh", + "postbuild": "gzipper --verbose --brotli ./build && gzipper --verbose ./build", "generate": "python tools/generate-component.py", - "lint:css": "stylelint './src/**/*.js' './src/**/*.ts*'" - }, - "husky": { - "hooks": { - "pre-commit": "$npm_execpath lint-staged" - } + "lint:css": "stylelint './src/**/*.js' './src/**/*.ts*'", + "prepare": "husky install" }, "lint-staged": { "src/**/*.{js,jsx,ts,tsx,json,scss}": [ "eslint --fix", + "prettier --write", "stylelint", "git add" ] @@ -42,20 +39,22 @@ "dependencies": { "@date-io/core": "^1.3.8", "@date-io/moment": "^1.3.8", + "@emotion/react": "^11.10.4", "@fortawesome/fontawesome-svg-core": "^1.2.19", "@fortawesome/free-solid-svg-icons": "^5.9.0", "@fortawesome/react-fontawesome": "^0.1.4", "@loadable/component": "^5.12.0", - "@material-ui/core": "^4.2.0", - "@material-ui/icons": "^4.2.1", - "@material-ui/pickers": "^3.2.9", + "@material-ui/core": "^4.12.4", + "@material-ui/icons": "^4.11.3", + "@material-ui/pickers": "^3.3.10", + "@mui/lab": "^5.0.0-alpha.104", + "@mui/material": "^5.10.10", + "@mui/styles": "^5.10.10", "@sparcs-kaist/react-grid-layout": "^0.18.0", "@types/jest": "^25.1.4", "@types/jsonwebtoken": "^8.3.8", "@types/lodash": "^4.14.149", "@types/node": "^13.9.1", - "@types/react": "^16.9.23", - "@types/react-dom": "^16.9.5", "@types/react-helmet": "^5.0.15", "@types/react-redux": "^7.1.7", "@types/react-router-dom": "^5.1.3", @@ -63,7 +62,7 @@ "@types/styled-components": "^5.0.1", "animate.css": "^3.7.2", "awesome-debounce-promise": "^2.1.0", - "axios": "^0.19.0", + "axios": "^1.3.4", "babel-plugin-styled-components": "^1.10.7", "browserslist": "^4.6.4", "chart.js": "^2.9.3", @@ -72,14 +71,12 @@ "clsx": "^1.1.0", "cross-env": "^5.2.0", "devtools-detect": "^3.0.0", - "eslint-config-airbnb": "^18.0.1", - "eslint-config-react-app": "^5.1.0", "http-proxy-middleware": "^0.20.0", "i18next": "^15.1.3", "i18next-browser-languagedetector": "^3.0.1", "immer": "^5.1.0", "immutable": "^4.0.0-rc.12", - "jsonwebtoken": "^8.5.1", + "jwt-decode": "^3.1.2", "lodash": "^4.17.15", "lodash.debounce": "^4.0.8", "lodash.get": "^4.4.2", @@ -88,17 +85,16 @@ "lodash.throttle": "^4.1.1", "lodash.uniq": "^4.5.0", "lodash.uniqby": "^4.7.0", - "material-table": "^1.57.2", + "material-table": "^2.0.3", "moment": "^2.24.0", - "node-sass": "^4.11.0", "perfect-scrollbar": "^1.5.0", "prop-types": "^15.7.2", "query-string": "^6.8.1", - "react": "^16.8.6", + "react": "^18.2.0", "react-airbnb-carousel": "^0.0.12", "react-chartist": "^0.14.2", "react-chartjs-2": "^2.9.0", - "react-dom": "^16.8.6", + "react-dom": "^18.2.0", "react-dropzone": "^10.2.1", "react-helmet": "^5.2.1", "react-i18next": "^10.11.4", @@ -106,7 +102,7 @@ "react-quill": "^1.3.3", "react-redux": "^7.1.0", "react-router-dom": "^5.1.2", - "react-scripts": "3.3.0", + "react-scripts": "^5.0.1", "react-select": "^3.0.8", "react-slick": "^0.25.2", "react-spinners": "^0.8.0", @@ -120,6 +116,7 @@ "redux-pender": "^2.0.12", "remotedev-serialize": "^0.1.8", "reselect": "^4.0.0", + "sass": "^1.52.3", "slick-carousel": "^1.8.1", "styled-components": "^4.3.2", "styled-theming": "^2.2.0", @@ -127,7 +124,7 @@ "zabo-utils": "^0.0.6" }, "devDependencies": { - "@babel/core": "^7.4.3", + "@babel/core": "^7.19.6", "@storybook/addon-actions": "^5.0.10", "@storybook/addon-console": "^1.1.0", "@storybook/addon-info": "^5.1.9", @@ -139,22 +136,24 @@ "@storybook/addons": "^5.0.10", "@storybook/core": "^5.3.7", "@storybook/react": "^5.0.10", - "@typescript-eslint/eslint-plugin": "^2.16.0", - "@typescript-eslint/parser": "^2.16.0", + "@types/loadable__component": "^5.13.4", + "@types/lodash.get": "^4.4.7", + "@types/react": "^18.0.21", + "@types/react-dom": "^18.0.6", + "@typescript-eslint/eslint-plugin": "^5.39.0", + "@typescript-eslint/parser": "^5.39.0", "babel-eslint": "10.x", "babel-plugin-macros": "^2.8.0", - "eslint": "^6.8.0", - "eslint-plugin-flowtype": "3.x", - "eslint-plugin-import": "^2.20.0", - "eslint-plugin-jsx-a11y": "^6.2.3", - "eslint-plugin-react": "^7.17.0", - "eslint-plugin-react-hooks": "^1.7.0", - "eslint-plugin-simple-import-sort": "^5.0.1", + "eslint": "^8.2.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-react": "^7.28.0", + "eslint-plugin-react-hooks": "^4.3.0", "gzipper": "^3.5.0", - "husky": "^4.0.6", + "husky": "^8.0.1", "jest": "^24.9.0", - "lint-staged": "^9.5.0", - "prettier": "^1.19.1", + "lint-staged": "^13.0.3", + "prettier": "^2.7.1", "regenerator-runtime": "^0.13.3", "require-context.macro": "^1.0.4", "source-map-explorer": "^2.3.1", @@ -162,7 +161,7 @@ "stylelint-config-recommended": "^3.0.0", "stylelint-config-styled-components": "^0.1.1", "stylelint-processor-styled-components": "^1.9.0", - "typescript": "^3.8.3" + "typescript": "^4.8.4" }, "license": "MIT" } diff --git a/src/.prettierrc b/src/.prettierrc deleted file mode 100644 index a75b002d..00000000 --- a/src/.prettierrc +++ /dev/null @@ -1,14 +0,0 @@ -{ - "printWidth": 100, - "tabWidth": 4, - "useTabs": true, - "semi": false, - "trailingComma": "es5", - "jsxBracketSameLine": false, - "overrides": [ - { - "files": ".prettierrc", - "options": { "parser": "json" } - } - ] -} diff --git a/src/App.styled.js b/src/App.styled.js index 4730f983..d70e67f3 100644 --- a/src/App.styled.js +++ b/src/App.styled.js @@ -1,3 +1,3 @@ -import styled from 'styled-components'; +import styled from "styled-components"; export default styled.div``; diff --git a/src/App.test.js b/src/App.test.js index 695525ca..23c181f0 100644 --- a/src/App.test.js +++ b/src/App.test.js @@ -1,9 +1,9 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import App from './App'; +import React from "react"; +import ReactDOM from "react-dom"; +import App from "./App"; -it ('renders without crashing', () => { - const div = document.createElement ('div'); - ReactDOM.render (, div); - ReactDOM.unmountComponentAtNode (div); +it("renders without crashing", () => { + const div = document.createElement("div"); + ReactDOM.render(, div); + ReactDOM.unmountComponentAtNode(div); }); diff --git a/src/App.tsx b/src/App.tsx index f20ac14d..43034fa6 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,15 +1,13 @@ -import React from 'react'; -import { Route, Switch } from 'react-router-dom'; -import { Helmet } from 'react-helmet'; +import React from "react"; +import { Route, Switch } from "react-router-dom"; +import { Helmet } from "react-helmet"; -import ChannelTalk from 'containers/ChannelTalk'; -import ScrollToTop from 'containers/ScrollToTop'; -import WindowResizeListener from 'containers/WindowResizeListener'; -import ErrorBoundary from 'components/ErrorBoundary'; -import AuthCallback from 'organisms/AuthCallback'; -import PWAPrompt from 'templates/PWAPrompt'; +import ChannelTalk from "components/containers/ChannelTalk"; +import ScrollToTop from "components/containers/ScrollToTop"; +import WindowResizeListener from "components/containers/WindowResizeListener"; +import ErrorBoundary from "components/ErrorBoundary"; +import AuthCallback from "components/organisms/AuthCallback"; import { - AdminPage, ApiPage, AuthPage, HomePage, @@ -20,21 +18,29 @@ import { SettingsPage, ZaboPage, ZaboUploadPage, -} from 'pages'; +} from "components/pages"; -import { AdminRoute, PrivateRoute, PublicRoute } from 'hoc/AuthRoutes'; -import pToP from 'hoc/paramsToProps'; +import PWAPrompt from "components/templates/PWAPrompt"; -import AppWrapper from './App.styled'; +import { PrivateRoute, PublicRoute } from "hoc/AuthRoutes"; +import pToP from "hoc/paramsToProps"; + +import AppWrapper from "./App.styled"; const App = () => ( ZABO - 자보 - + - + @@ -45,9 +51,8 @@ const App = () => ( - + - diff --git a/src/boot.js b/src/boot.js index 93a71a08..bdf29f46 100644 --- a/src/boot.js +++ b/src/boot.js @@ -1,32 +1,32 @@ -import 'devtools-detect'; +import "devtools-detect"; -import moment from 'moment'; +import moment from "moment"; -import store from 'store'; -import { checkAuth } from 'store/reducers/auth'; -import { initialize } from 'store/reducers/upload'; -import axios from 'lib/axios'; -import storage from 'lib/storage'; +import store from "store"; +import { checkAuth } from "store/reducers/auth"; +import { initialize } from "store/reducers/upload"; +import axios from "lib/axios"; +import storage from "lib/storage"; -import { parseJSON } from './lib/utils'; +import { parseJSON } from "./lib/utils"; const pwaInstallPromptListener = () => { - window.addEventListener ('beforeinstallprompt', e => { + window.addEventListener("beforeinstallprompt", (e) => { // Prevent Chrome 67 and earlier from automatically showing the prompt - e.preventDefault (); + e.preventDefault(); // Stash the event so it can be triggered later. window.deferredPrompt = e; // Update UI notify the user they can add to home screen window.pwaPromptActive = true; - document.body.classList.add ('pwa-prompt-active'); + document.body.classList.add("pwa-prompt-active"); if (window.onPWAPromptActive) { - window.onPWAPromptActive (); + window.onPWAPromptActive(); } }); }; export default () => { - ((() => { + (() => { const throttle = (type, name, givenObj) => { const obj = givenObj || window; let running = false; @@ -35,43 +35,42 @@ export default () => { return; } running = true; - requestAnimationFrame (() => { - obj.dispatchEvent (new CustomEvent (name)); + requestAnimationFrame(() => { + obj.dispatchEvent(new CustomEvent(name)); running = false; }); }; - obj.addEventListener (type, func); + obj.addEventListener(type, func); }; /* init - you can init any event */ - throttle ('resize', 'optimizedResize'); - throttle ('scroll', 'optimizedScroll'); - }) ()); + throttle("resize", "optimizedResize"); + throttle("scroll", "optimizedScroll"); + })(); + pwaInstallPromptListener(); - pwaInstallPromptListener (); - - const uploadPersist = storage.getItem ('uploadPersist'); + const uploadPersist = storage.getItem("uploadPersist"); if (uploadPersist) { if (uploadPersist.date) { - store.dispatch (initialize (uploadPersist)); + store.dispatch(initialize(uploadPersist)); } else { - storage.removeItem ('uploadPersist'); + storage.removeItem("uploadPersist"); } } - const token = storage.getItem ('token'); - axios.updateToken (token); + const token = storage.getItem("token"); + axios.updateToken(token); if (token) { - store.dispatch (checkAuth (token)); + store.dispatch(checkAuth(token)); } }; -window.addEventListener ('devtoolschange', () => { - if (process.env.NODE_ENV !== 'production') return; - import ('static/images/recruitAscii').then (asciiArt => { +window.addEventListener("devtoolschange", () => { + if (process.env.NODE_ENV !== "production") return; + import("static/images/recruitAscii").then((asciiArt) => { // eslint-disable-next-line no-console - console.log (asciiArt.default); + console.log(asciiArt.default); }); }); diff --git a/src/components/ErrorBoundary.js b/src/components/ErrorBoundary.tsx similarity index 54% rename from src/components/ErrorBoundary.js rename to src/components/ErrorBoundary.tsx index d991f2be..5a0cbf15 100644 --- a/src/components/ErrorBoundary.js +++ b/src/components/ErrorBoundary.tsx @@ -1,19 +1,28 @@ -import React from 'react'; +import React, { ErrorInfo, ReactNode } from "react"; -class ErrorBoundary extends React.Component { +interface Props { + children?: ReactNode; +} + +interface State { + hasError: boolean; +} + +class ErrorBoundary extends React.Component { state = { hasError: false }; - static getDerivedStateFromError (error) { + static getDerivedStateFromError(error: Error) { // Update state so the next render will show the fallback UI. return { error, hasError: true }; } - componentDidCatch (error, errorInfo) { + componentDidCatch(error: Error, errorInfo: ErrorInfo) { + console.error("Uncaught error:", error, errorInfo); // You can also log the error to an error reporting service // logErrorToMyService(error, errorInfo); } - render () { + render() { if (this.state.hasError) { // You can render any custom fallback UI return

Something went wrong.

; diff --git a/src/components/atoms/Button/Button.js b/src/components/atoms/Button/Button.js index 5020a85c..321b76f0 100644 --- a/src/components/atoms/Button/Button.js +++ b/src/components/atoms/Button/Button.js @@ -1,17 +1,15 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { withRouter } from 'react-router-dom'; +import React from "react"; +import PropTypes from "prop-types"; +import { withRouter } from "react-router-dom"; -import StyledButton, { ButtonGroup } from './Button.styled'; +import StyledButton, { ButtonGroup } from "./Button.styled"; -const Button = ({ - history, to, onClick, ...props -}) => ( +const Button = ({ history, to, onClick, ...props }) => ( { - if (typeof onClick === 'function') onClick (event); - if (to) history.push (to); + onClick={(event) => { + if (typeof onClick === "function") onClick(event); + if (to) history.push(to); }} /> ); @@ -25,13 +23,13 @@ Button.propTypes = { Button.defaultProps = { ...StyledButton.defaultProps, - className: '', - to: '', - type: 'button', + className: "", + to: "", + type: "button", }; Button.defaultProps = {}; Button.Group = ButtonGroup; -export default withRouter (Button); +export default withRouter(Button); diff --git a/src/components/atoms/Button/Button.styled.js b/src/components/atoms/Button/Button.styled.js index 035e09dc..0d31476b 100644 --- a/src/components/atoms/Button/Button.styled.js +++ b/src/components/atoms/Button/Button.styled.js @@ -1,8 +1,8 @@ -import PropTypes from 'prop-types'; -import styled, { css } from 'styled-components'; +import PropTypes from "prop-types"; +import styled, { css } from "styled-components"; -import { colors } from 'lib/theme'; -import { getSize, media } from 'lib/utils/style'; +import { colors } from "lib/theme"; +import { getSize, media } from "lib/utils/style"; export const disabled = css` background-color: #f7f8f9; @@ -19,34 +19,44 @@ const StyledButton = styled.button` min-height: 30px; font-size: 12px; border-radius: 15px; - color: ${props => colors[props.color] || props.color || colors.textMain}; - background-color: ${props => colors[props.background] || props.background || colors.gray3}; - border: solid ${props => colors[props.border] || props.border || colors.gray60}; - border-width: ${props => (props.type === 'detail' ? '1.5px' : '1px')}; + color: ${(props) => colors[props.color] || props.color || colors.textMain}; + background-color: ${(props) => colors[props.background] || props.background || colors.gray3}; + border: solid ${(props) => colors[props.border] || props.border || colors.gray60}; + border-width: ${(props) => (props.type === "detail" ? "1.5px" : "1px")}; outline: none; padding: 3px 10px; - - width: ${props => ( - props.width ? getSize ('width') (props) - : props.xSmall ? '120px' - : props.small ? '180px' - : props.normal ? '240px' - : props.large ? '480px' - : 'auto')}; + + width: ${(props) => + props.width + ? getSize("width")(props) + : props.xSmall + ? "120px" + : props.small + ? "180px" + : props.normal + ? "240px" + : props.large + ? "480px" + : "auto"}; ${media.tablet` height: 30px; font-size: 12px; - width: ${props => ( - props.width ? getSize ('tWidth') (props) - : props.xSmall ? '120px' - : props.small ? '180px' - : props.normal ? '240px' - : props.large ? '480px' - : 'auto')}; + width: ${(props) => + props.width + ? getSize("tWidth")(props) + : props.xSmall + ? "120px" + : props.small + ? "180px" + : props.normal + ? "240px" + : props.large + ? "480px" + : "auto"}; `}; - ${props => props.disabled && disabled}; + ${(props) => props.disabled && disabled}; a { text-decoration: none; @@ -59,11 +69,11 @@ StyledButton.propTypes = { small: PropTypes.bool, normal: PropTypes.bool, large: PropTypes.bool, - width: PropTypes.oneOfType ([PropTypes.string, PropTypes.number]), + width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), disabled: PropTypes.bool, - color: PropTypes.oneOf (Object.keys (colors)), - background: PropTypes.oneOf (Object.keys (colors)), - border: PropTypes.oneOf (Object.keys (colors)), + color: PropTypes.oneOf(Object.keys(colors)), + background: PropTypes.oneOf(Object.keys(colors)), + border: PropTypes.oneOf(Object.keys(colors)), type: PropTypes.string, }; @@ -73,18 +83,16 @@ StyledButton.defaultProps = { normal: false, large: false, disabled: false, - color: 'textMain', - background: 'gray3', - border: 'gray50', - type: '', + color: "textMain", + background: "gray3", + border: "gray50", + type: "", }; export const ButtonGroup = styled.div` display: flex; button + button { - margin-left: ${props => ( - props.gutter ? getSize ('gutter') (props) - : '6px')}; + margin-left: ${(props) => (props.gutter ? getSize("gutter")(props) : "6px")}; } `; diff --git a/src/components/atoms/Button/index.js b/src/components/atoms/Button/index.js index efe8c800..c4719be7 100644 --- a/src/components/atoms/Button/index.js +++ b/src/components/atoms/Button/index.js @@ -1 +1 @@ -export { default } from './Button'; +export { default } from "./Button"; diff --git a/src/components/atoms/Category/Category.js b/src/components/atoms/Category/Category.js index 0d6213ff..595b78b4 100644 --- a/src/components/atoms/Category/Category.js +++ b/src/components/atoms/Category/Category.js @@ -1,19 +1,19 @@ -import styled, { css } from 'styled-components'; +import styled, { css } from "styled-components"; -import * as mixins from 'lib/mixins'; -import { media } from 'lib/utils/style'; +import * as mixins from "lib/mixins"; +import { media } from "lib/utils/style"; export const CategoryW = styled.div` ${mixins.flexCenter}; height: 19px; padding: 3px 6px; - background: ${props => props.theme.gray5}; + background: ${(props) => props.theme.gray5}; border-radius: 2px; font-size: 10px; line-height: 11px; - color: ${props => props.theme.gray60}; + color: ${(props) => props.theme.gray60}; cursor: default; - ${media.tablet (css` + ${media.tablet(css` font-size: 12px; line-height: 14px; height: 20px; diff --git a/src/components/atoms/Category/index.js b/src/components/atoms/Category/index.js index 5c451226..0d0bf611 100644 --- a/src/components/atoms/Category/index.js +++ b/src/components/atoms/Category/index.js @@ -1 +1 @@ -export * from './Category'; +export * from "./Category"; diff --git a/src/components/atoms/Container/Container.js b/src/components/atoms/Container/Container.js deleted file mode 100644 index 61cbe9ba..00000000 --- a/src/components/atoms/Container/Container.js +++ /dev/null @@ -1,38 +0,0 @@ -import PropTypes from 'prop-types'; -import styled, { css } from 'styled-components'; - -import { colors } from 'lib/theme'; - -import { media } from '../../../lib/utils/style'; - -const Container = styled.div` - width: 100%; - margin: 0 auto; - padding: 0 24px; - display: flex; - overflow: scroll; - &::-webkit-scrollbar { width: 0 !important } - -ms-overflow-style: none; - ${media.tablet (css` - padding: 0 18px; - `)}; - ${props => props.ownStyle || ''}; - background: ${props => (props.background ? props.theme[props.background] : 'transparent')}; -`; - -Container.Pad = styled.div` - padding-left: ${props => props.width}; -`; -Container.Pad.propTypes = { - width: PropTypes.number.isRequired, -}; -Container.Pad.defaultProps = { - width: '24px', -}; - -Container.propTypes = { - ownStyle: PropTypes.oneOfType ([PropTypes.string, PropTypes.array]), - background: PropTypes.oneOf (Object.keys (colors)), -}; - -export default Container; diff --git a/src/components/atoms/Container/Container.tsx b/src/components/atoms/Container/Container.tsx new file mode 100644 index 00000000..c13205b8 --- /dev/null +++ b/src/components/atoms/Container/Container.tsx @@ -0,0 +1,34 @@ +import styled, { css } from "styled-components"; + +import { colors } from "lib/theme"; +import { media } from "lib/utils/style"; + +const ContainerComponent = styled.div<{ + ownStyle?: ReturnType; + background?: keyof typeof colors; +}>` + width: 100%; + margin: 0 auto; + padding: 0 24px; + display: flex; + overflow: scroll; + + &::-webkit-scrollbar { + width: 0 !important; + } + + -ms-overflow-style: none; + ${media.tablet(css` + padding: 0 18px; + `)}; + ${(props) => props.ownStyle || ""}; + background: ${(props) => (props.background ? props.theme[props.background] : "transparent")}; +`; + +const PadComponent = styled.div<{ width?: number }>` + padding-left: ${({ width = "24px" }) => width}; +`; + +const Container = Object.assign(ContainerComponent, { Pad: PadComponent }); + +export default Container; diff --git a/src/components/atoms/Container/index.js b/src/components/atoms/Container/index.js index a147b67a..c81c92ae 100644 --- a/src/components/atoms/Container/index.js +++ b/src/components/atoms/Container/index.js @@ -1 +1 @@ -export { default } from './Container'; +export { default } from "./Container"; diff --git a/src/components/atoms/DueDate/index.js b/src/components/atoms/DueDate/DueDate.tsx similarity index 54% rename from src/components/atoms/DueDate/index.js rename to src/components/atoms/DueDate/DueDate.tsx index 1c737d37..090a8a11 100644 --- a/src/components/atoms/DueDate/index.js +++ b/src/components/atoms/DueDate/DueDate.tsx @@ -1,8 +1,8 @@ -import React from 'react'; -import styled from 'styled-components'; -import moment from 'moment'; +import React from "react"; +import styled from "styled-components"; +import moment from "moment"; -import { to2Digits } from 'lib/utils'; +import { to2Digits } from "lib/utils"; const DueDateW = styled.div` position: absolute; @@ -17,14 +17,14 @@ const DueDateW = styled.div` font-size: 11px; line-height: 18px; border-radius: 2px; - background: ${props => props.theme.main}; + background: ${(props) => props.theme.main}; font-style: normal; font-weight: bold; - color: ${props => props.theme.white}; + color: ${(props) => props.theme.white}; `; -const DDayW = styled (DueDateW)` - background: ${props => props.theme.red50}; +const DDayW = styled(DueDateW)` + background: ${(props) => props.theme.red50}; `; const DueDateLW = styled.div` @@ -47,17 +47,22 @@ const DueDateLW = styled.div` } `; -const DDayLW = styled (DueDateLW)` - background: ${props => props.theme.red50}; +const DDayLW = styled(DueDateLW)` + background: ${(props) => props.theme.red50}; `; -const DueDate = ({ schedule, large }) => { - const due = schedule ? moment (schedule).diff (moment (), 'days') : -1; +interface Props { + schedule: string; + large?: boolean; +} + +const DueDate: React.FC = ({ schedule, large }) => { + const due = schedule ? moment(schedule).diff(moment(), "days") : -1; if (large) { - if (due > 0) return D{to2Digits (-due, true)}; + if (due > 0) return D{to2Digits(-due, true)}; if (due === 0) return D-Day; } else { - if (due > 0) return D{to2Digits (-due, true)}; + if (due > 0) return D{to2Digits(-due, true)}; if (due === 0) return D-Day; } return null; diff --git a/src/components/atoms/DueDate/index.ts b/src/components/atoms/DueDate/index.ts new file mode 100644 index 00000000..79693720 --- /dev/null +++ b/src/components/atoms/DueDate/index.ts @@ -0,0 +1 @@ +export { default } from "./DueDate"; diff --git a/src/components/atoms/InputBase/InputBase.js b/src/components/atoms/InputBase/InputBase.js index 7601e577..519b825e 100644 --- a/src/components/atoms/InputBase/InputBase.js +++ b/src/components/atoms/InputBase/InputBase.js @@ -1,21 +1,21 @@ -import React from 'react'; -import MInputBase from '@material-ui/core/InputBase'; -import { makeStyles } from '@material-ui/core/styles'; +import React from "react"; +import MInputBase from "@material-ui/core/InputBase"; +import { makeStyles } from "@material-ui/core/styles"; -const useStyles = makeStyles ({ +const useStyles = makeStyles({ root: { - width: '100%', - minHeight: '48px', - margin: '8px 0 24px 0', - padding: '9px 10px', - borderRadius: '4px', - backgroundColor: '#f4f4f4', - fontFailiy: 'NanumSquare', + width: "100%", + minHeight: "48px", + margin: "8px 0 24px 0", + padding: "9px 10px", + borderRadius: "4px", + backgroundColor: "#f4f4f4", + fontFailiy: "NanumSquare", }, }); -const InputBase = props => { - const classes = useStyles (); +const InputBase = (props) => { + const classes = useStyles(); return ; }; diff --git a/src/components/atoms/InputBase/index.js b/src/components/atoms/InputBase/index.js index fc4c6ce9..aacba6ea 100644 --- a/src/components/atoms/InputBase/index.js +++ b/src/components/atoms/InputBase/index.js @@ -1 +1 @@ -export { default } from './InputBase'; +export { default } from "./InputBase"; diff --git a/src/components/atoms/Link/Link.container.js b/src/components/atoms/Link/Link.container.js index a2d71d18..cb1a65f3 100644 --- a/src/components/atoms/Link/Link.container.js +++ b/src/components/atoms/Link/Link.container.js @@ -1,16 +1,16 @@ -import React, { PureComponent } from 'react'; -import { connect } from 'react-redux'; +import React, { PureComponent } from "react"; +import { connect } from "react-redux"; -import Link from './Link'; +import Link from "./Link"; class LinkContainer extends PureComponent { - render () { + render() { return ; } } -const mapStateToProps = state => ({}); +const mapStateToProps = (state) => ({}); -const mapDispatchToProps = dispatch => ({}); +const mapDispatchToProps = (dispatch) => ({}); -export default connect (mapStateToProps, mapDispatchToProps) (LinkContainer); +export default connect(mapStateToProps, mapDispatchToProps)(LinkContainer); diff --git a/src/components/atoms/Link/Link.js b/src/components/atoms/Link/Link.js index 44a893aa..082e0e98 100644 --- a/src/components/atoms/Link/Link.js +++ b/src/components/atoms/Link/Link.js @@ -1,10 +1,10 @@ -import React, { PureComponent } from 'react'; -import PropTypes from 'prop-types'; +import React, { PureComponent } from "react"; +import PropTypes from "prop-types"; -import LinkWrapper from './Link.styled'; +import LinkWrapper from "./Link.styled"; class Link extends PureComponent { - render () { + render() { return ( {this.props.children} diff --git a/src/components/atoms/Link/Link.stories.js b/src/components/atoms/Link/Link.stories.js index 695b3d77..f64e01a1 100644 --- a/src/components/atoms/Link/Link.stories.js +++ b/src/components/atoms/Link/Link.stories.js @@ -1,8 +1,8 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; +import React from "react"; +import { storiesOf } from "@storybook/react"; -import Link from './index'; +import Link from "./index"; -storiesOf ('atoms/Link', module).add ('Default', () => , { - notes: '', +storiesOf("atoms/Link", module).add("Default", () => , { + notes: "", }); diff --git a/src/components/atoms/Link/Link.styled.js b/src/components/atoms/Link/Link.styled.js index 1d7c8fcc..436e2a7e 100644 --- a/src/components/atoms/Link/Link.styled.js +++ b/src/components/atoms/Link/Link.styled.js @@ -1,4 +1,4 @@ -import styled from 'styled-components'; +import styled from "styled-components"; const LinkWrapper = styled.div``; diff --git a/src/components/atoms/Link/index.js b/src/components/atoms/Link/index.js index c36d81aa..9147f700 100644 --- a/src/components/atoms/Link/index.js +++ b/src/components/atoms/Link/index.js @@ -1 +1 @@ -export { default } from './Link.container'; +export { default } from "./Link.container"; diff --git a/src/components/atoms/Modal/Modal.js b/src/components/atoms/Modal/Modal.js index 7b87ec47..fa24805b 100644 --- a/src/components/atoms/Modal/Modal.js +++ b/src/components/atoms/Modal/Modal.js @@ -1,33 +1,30 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import styled from 'styled-components'; +import React from "react"; +import ReactDOM from "react-dom"; +import styled from "styled-components"; -const modalRoot = document.getElementById ('modal-root'); +const modalRoot = document.getElementById("modal-root"); class Portal extends React.Component { - constructor (props) { - super (props); - this.el = document.createElement ('div'); + constructor(props) { + super(props); + this.el = document.createElement("div"); } - componentDidMount () { - modalRoot.appendChild (this.el); + componentDidMount() { + modalRoot.appendChild(this.el); } - componentWillUnmount () { - modalRoot.removeChild (this.el); + componentWillUnmount() { + modalRoot.removeChild(this.el); } - render () { - return ReactDOM.createPortal ( - this.props.children, - this.el, - ); + render() { + return ReactDOM.createPortal(this.props.children, this.el); } } const ModalWrapper = styled.div` - background-color: rgba(0,0,0,0.5); + background-color: rgba(0, 0, 0, 0.5); position: fixed; height: 100%; width: 100%; @@ -38,11 +35,9 @@ const ModalWrapper = styled.div` justify-content: center; `; -const Modal = props => ( +const Modal = (props) => ( - - {props.children} - + {props.children} ); diff --git a/src/components/atoms/Modal/index.js b/src/components/atoms/Modal/index.js index 0690fecf..09b91f72 100644 --- a/src/components/atoms/Modal/index.js +++ b/src/components/atoms/Modal/index.js @@ -1 +1 @@ -export { default } from './Modal'; +export { default } from "./Modal"; diff --git a/src/components/atoms/SVG/SVG.js b/src/components/atoms/SVG/SVG.js index ab4525bd..831670d6 100644 --- a/src/components/atoms/SVG/SVG.js +++ b/src/components/atoms/SVG/SVG.js @@ -1,12 +1,15 @@ -import React from 'react'; -import PropTypes from 'prop-types'; +import React from "react"; +import PropTypes from "prop-types"; import { - faArrowRight, faCoffee, faPlus, faQuestionCircle, + faArrowRight, + faCoffee, + faPlus, + faQuestionCircle, faUser, -} from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +} from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import arrow from 'static/icon/arrow.svg'; +import arrow from "static/icon/arrow.svg"; export const faIcons = { coffee: faCoffee, @@ -15,20 +18,21 @@ export const faIcons = { arrowRight: faArrowRight, questionCircle: faQuestionCircle, }; -const faIconList = Object.keys (faIcons); +const faIconList = Object.keys(faIcons); const icons = { arrow, }; const SVG = ({ icon, ...props }) => { - if (faIconList.some (faIcon => icon === faIcon)) return ; - return {icon}; + if (faIconList.some((faIcon) => icon === faIcon)) + return ; + return {icon}; }; SVG.propTypes = { ...FontAwesomeIcon.propTypes, - icon: PropTypes.oneOf (Object.keys (faIcons)).isRequired, + icon: PropTypes.oneOf(Object.keys(faIcons)).isRequired, }; SVG.defaultProps = {}; diff --git a/src/components/atoms/SVG/SVG.stories.js b/src/components/atoms/SVG/SVG.stories.js index 52e7f8ab..f802fd87 100644 --- a/src/components/atoms/SVG/SVG.stories.js +++ b/src/components/atoms/SVG/SVG.stories.js @@ -1,13 +1,11 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; +import React from "react"; +import { storiesOf } from "@storybook/react"; -import SVG from './index'; -import { faIcons } from './SVG'; +import SVG from "./index"; +import { faIcons } from "./SVG"; -Object.keys (faIcons) - .forEach (icon => { - storiesOf ('atoms/SVG', module) - .add (icon, () => , { - notes: '', - }); +Object.keys(faIcons).forEach((icon) => { + storiesOf("atoms/SVG", module).add(icon, () => , { + notes: "", }); +}); diff --git a/src/components/atoms/SVG/index.js b/src/components/atoms/SVG/index.js index 095a4677..48606c2a 100644 --- a/src/components/atoms/SVG/index.js +++ b/src/components/atoms/SVG/index.js @@ -1 +1 @@ -export { default } from './SVG'; +export { default } from "./SVG"; diff --git a/src/components/atoms/Span/index.js b/src/components/atoms/Span/index.js index 76e3615d..8d6d86ec 100644 --- a/src/components/atoms/Span/index.js +++ b/src/components/atoms/Span/index.js @@ -1,4 +1,4 @@ -import styled from 'styled-components'; +import styled from "styled-components"; export const Light = styled.span` font-weight: 300; diff --git a/src/components/atoms/SuperTooltip/SuperTooltip.js b/src/components/atoms/SuperTooltip/SuperTooltip.js index b80f8eff..a9985c79 100644 --- a/src/components/atoms/SuperTooltip/SuperTooltip.js +++ b/src/components/atoms/SuperTooltip/SuperTooltip.js @@ -1,16 +1,15 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import Tooltip from '@material-ui/core/Tooltip'; +import React from "react"; +import PropTypes from "prop-types"; +import Tooltip from "@material-ui/core/Tooltip"; -const SuperTooltip = ({ - title, hide, children, ...props -}) => ( - hide ? children : ( +const SuperTooltip = ({ title, hide, children, ...props }) => + hide ? ( + children + ) : ( {children} - ) -); + ); SuperTooltip.propTypes = { ...Tooltip.propTypes, diff --git a/src/components/atoms/SuperTooltip/index.js b/src/components/atoms/SuperTooltip/index.js index 6edf0eae..0feb676f 100644 --- a/src/components/atoms/SuperTooltip/index.js +++ b/src/components/atoms/SuperTooltip/index.js @@ -1 +1 @@ -export { default } from './SuperTooltip'; +export { default } from "./SuperTooltip"; diff --git a/src/components/atoms/TagList/TagList.js b/src/components/atoms/TagList/TagList.js index 7e907294..f3929c89 100644 --- a/src/components/atoms/TagList/TagList.js +++ b/src/components/atoms/TagList/TagList.js @@ -1,8 +1,8 @@ -import React, { useEffect, useMemo, useState } from 'react'; -import PropTypes from 'prop-types'; -import styled, { css } from 'styled-components'; +import React, { useEffect, useMemo, useState } from "react"; +import PropTypes from "prop-types"; +import styled, { css } from "styled-components"; -import { ZABO_CATEGORIES } from 'lib/variables'; +import { ZABO_CATEGORIES } from "lib/variables"; export const TagListWrapper = styled.div` margin-top: 20px; @@ -16,7 +16,9 @@ export const TagListWrapper = styled.div` margin: 0 12px 10px 0; border: 1px solid #143441; border-radius: 4px; - &:hover, &:focus, &.clicked { + &:hover, + &:focus, + &.clicked { color: white; background-color: #143441; } @@ -25,66 +27,65 @@ export const TagListWrapper = styled.div` background-color: white; } } - ${props => (props.type === 'search' ? css` - width: 100%; - scroll-behavior: smooth; - overflow-x: scroll; - white-space: nowrap; - /* hide scroll bar */ - /* -webkit- (Chrome, Safari, newer versions of Opera) */ - &::-webkit-scrollbar { width: 0 !important } - /* Firefox */ - scrollbar-width: none; - /* -ms- (Internet Explorer +10) */ - -ms-overflow-style: none; + ${(props) => + props.type === "search" + ? css` + width: 100%; + scroll-behavior: smooth; + overflow-x: scroll; + white-space: nowrap; + /* hide scroll bar */ + /* -webkit- (Chrome, Safari, newer versions of Opera) */ + &::-webkit-scrollbar { + width: 0 !important; + } + /* Firefox */ + scrollbar-width: none; + /* -ms- (Internet Explorer +10) */ + -ms-overflow-style: none; - button { - font-size: 14px; - padding: 8px 10px; - margin-right: 8px; - &:last-child { margin-right: 0 } - } - ` : css` - `)} + button { + font-size: 14px; + padding: 8px 10px; + margin-right: 8px; + &:last-child { + margin-right: 0; + } + } + ` + : css``} `; const TagList = ({ type, onTagClick, clickedTags }) => { - const handleClick = e => { + const handleClick = (e) => { const { value: category } = e.target; - onTagClick (category); + onTagClick(category); }; - const tagList = useMemo (() => ( - ZABO_CATEGORIES.map ((tag, idx) => { - const cName = clickedTags.includes (tag) ? 'clicked' : 'unclicked'; - return ( - - ); - }) - ), [clickedTags, onTagClick]); - - return ( - - {tagList} - + const tagList = useMemo( + () => + ZABO_CATEGORIES.map((tag, idx) => { + const cName = clickedTags.includes(tag) ? "clicked" : "unclicked"; + return ( + + ); + }), + [clickedTags, onTagClick], ); + + return {tagList}; }; TagList.propTypes = { type: PropTypes.string, onTagClick: PropTypes.func.isRequired, - clickedTags: PropTypes.arrayOf (PropTypes.string), + clickedTags: PropTypes.arrayOf(PropTypes.string), }; TagList.defaultProps = { - type: '', + type: "", clickedTags: [], }; diff --git a/src/components/atoms/TagList/index.js b/src/components/atoms/TagList/index.js index 6abe6b35..084eb401 100644 --- a/src/components/atoms/TagList/index.js +++ b/src/components/atoms/TagList/index.js @@ -1 +1 @@ -export { default } from './TagList'; +export { default } from "./TagList"; diff --git a/src/components/atoms/Todo/Todo.js b/src/components/atoms/Todo/Todo.js index 56a17236..a2bd90c1 100644 --- a/src/components/atoms/Todo/Todo.js +++ b/src/components/atoms/Todo/Todo.js @@ -1,13 +1,13 @@ -import React, { PureComponent } from 'react'; -import PropTypes from 'prop-types'; +import React, { PureComponent } from "react"; +import PropTypes from "prop-types"; -import TodoWrapper from './Todo.styled'; +import TodoWrapper from "./Todo.styled"; const Todo = ({ onClick, completed, text }) => ( {text} diff --git a/src/components/atoms/Todo/Todo.stories.js b/src/components/atoms/Todo/Todo.stories.js index 2bf9654b..940b6101 100644 --- a/src/components/atoms/Todo/Todo.stories.js +++ b/src/components/atoms/Todo/Todo.stories.js @@ -1,8 +1,8 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; +import React from "react"; +import { storiesOf } from "@storybook/react"; -import Todo from './index'; +import Todo from "./index"; -storiesOf ('atoms/Todo', module).add ('Default', () => , { - notes: '', +storiesOf("atoms/Todo", module).add("Default", () => , { + notes: "", }); diff --git a/src/components/atoms/Todo/Todo.styled.js b/src/components/atoms/Todo/Todo.styled.js index eef2162d..58678796 100644 --- a/src/components/atoms/Todo/Todo.styled.js +++ b/src/components/atoms/Todo/Todo.styled.js @@ -1,4 +1,4 @@ -import styled from 'styled-components'; +import styled from "styled-components"; const TodoWrapper = styled.li``; diff --git a/src/components/atoms/Todo/index.js b/src/components/atoms/Todo/index.js index 78428c7b..012972be 100644 --- a/src/components/atoms/Todo/index.js +++ b/src/components/atoms/Todo/index.js @@ -1 +1 @@ -export { default } from './Todo'; +export { default } from "./Todo"; diff --git a/src/components/atoms/ToggleButton/ToggleButton.js b/src/components/atoms/ToggleButton/ToggleButton.js index f576b5fa..e27d81a4 100644 --- a/src/components/atoms/ToggleButton/ToggleButton.js +++ b/src/components/atoms/ToggleButton/ToggleButton.js @@ -1,6 +1,6 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import styled from 'styled-components'; +import React from "react"; +import PropTypes from "prop-types"; +import styled from "styled-components"; const ToggleButtonWrapper = styled.div` display: inline-block; @@ -27,8 +27,8 @@ const ToggleButtonWrapper = styled.div` left: 0; right: 0; bottom: 0; - background-color: #BCBCBC; - transition: .4s; + background-color: #bcbcbc; + transition: 0.4s; } .slider:before { @@ -39,7 +39,7 @@ const ToggleButtonWrapper = styled.div` left: 4px; bottom: 4px; background-color: white; - transition: .4s; + transition: 0.4s; } input:checked + .slider { diff --git a/src/components/atoms/ToggleButton/index.js b/src/components/atoms/ToggleButton/index.js index 5061a176..f6d953a7 100644 --- a/src/components/atoms/ToggleButton/index.js +++ b/src/components/atoms/ToggleButton/index.js @@ -1 +1 @@ -export { default } from './ToggleButton'; +export { default } from "./ToggleButton"; diff --git a/src/components/atoms/TwoCol/TwoCol.js b/src/components/atoms/TwoCol/TwoCol.js index 04d15118..0d166160 100644 --- a/src/components/atoms/TwoCol/TwoCol.js +++ b/src/components/atoms/TwoCol/TwoCol.js @@ -1,17 +1,17 @@ -import PropTypes from 'prop-types'; -import styled, { css } from 'styled-components'; +import PropTypes from "prop-types"; +import styled, { css } from "styled-components"; -import { media } from 'lib/utils/style'; +import { media } from "lib/utils/style"; const colMixin = css` display: flex; flex-direction: column; - flex: ${props => props.flex} 0 0; + flex: ${(props) => props.flex} 0 0; flex-shrink: 0; flex-basis: auto; min-width: 0; - ${media.tablet (css` - flex: ${props => props.flex}; + ${media.tablet(css` + flex: ${(props) => props.flex}; `)}; `; @@ -25,7 +25,6 @@ Left.defaultProps = { flex: 1, }; - const Right = styled.section` ${colMixin}; `; @@ -36,29 +35,34 @@ Right.defaultProps = { flex: 1, }; - const TwoCol = styled.section` display: flex; width: 100%; flex-wrap: wrap; flex-shrink: 0; flex-basis: auto; - ${props => (props.mobileWrap ? css` - flex-direction: column; - ` : '')}; - - ${media.tablet (css` + ${(props) => + props.mobileWrap + ? css` + flex-direction: column; + ` + : ""}; + + ${media.tablet(css` flex-direction: row; flex-wrap: nowrap; - ${props => (props.divider ? css` - ${Left} { - padding-right: 24px; - border-right: 1px solid ${props => props.theme.gray10}; - } - ${Right} { - padding-left: 24px; - } - ` : '')}; + ${(props) => + props.divider + ? css` + ${Left} { + padding-right: 24px; + border-right: 1px solid ${(props) => props.theme.gray10}; + } + ${Right} { + padding-left: 24px; + } + ` + : ""}; `)}; `; diff --git a/src/components/atoms/TwoCol/index.js b/src/components/atoms/TwoCol/index.js index 49b5c44e..4fc12b6f 100644 --- a/src/components/atoms/TwoCol/index.js +++ b/src/components/atoms/TwoCol/index.js @@ -1 +1 @@ -export { default } from './TwoCol'; +export { default } from "./TwoCol"; diff --git a/src/components/containers/ChannelTalk.tsx b/src/components/containers/ChannelTalk.tsx index f4fda391..8da26628 100644 --- a/src/components/containers/ChannelTalk.tsx +++ b/src/components/containers/ChannelTalk.tsx @@ -1,58 +1,50 @@ -import { useEffect } from 'react'; -import { RouteComponentProps, useLocation } from 'react-router-dom'; -import { useSelector } from 'react-redux'; -import { get } from 'lodash'; -import queryString from 'query-string'; -import { IState } from 'types/store.d'; +import { useEffect } from "react"; +import { RouteComponentProps, useLocation } from "react-router-dom"; +import { useSelector } from "react-redux"; +import { get } from "lodash"; +import queryString from "query-string"; +import { IState } from "types/store.d"; -import ChannelService from 'lib/channel_io'; -import { isAuthedSelector } from 'lib/utils'; +import ChannelService from "lib/channel_io"; +import { isAuthedSelector } from "lib/utils"; -const ChannelTalk = ({ match } : RouteComponentProps<{top : string}>) => { - const { search, pathname } = useLocation (); +const ChannelTalk = ({ match }: RouteComponentProps<{ top: string }>) => { + const { search, pathname } = useLocation(); const { top } = match.params; - const isAuthenticated = useSelector (isAuthedSelector); - const info = useSelector ((state : IState) => get (state, ['auth', 'info'])); + const isAuthenticated = useSelector(isAuthedSelector); + const info = useSelector((state: IState) => get(state, ["auth", "info"])); - useEffect (() => { - if (process.env.NODE_ENV !== 'production') return; - if (top === 'settings') { - ChannelService.shutdown (); + useEffect(() => { + if (process.env.NODE_ENV !== "production") return; + if (top === "settings") { + ChannelService.shutdown(); return; } - if (pathname === '/zabo/upload') { - ChannelService.shutdown (); + if (pathname === "/zabo/upload") { + ChannelService.shutdown(); return; } - const { code, state } = queryString.parse (search); + const { code, state } = queryString.parse(search); if (code && state) return; const settings = { - pluginKey: '5fe8c634-bcbd-4499-ba99-967191a2ef77', + pluginKey: "5fe8c634-bcbd-4499-ba99-967191a2ef77", }; if (isAuthenticated) { if (!info) return; - const { - _id, - username, - koreanName, - groups, - flags, - email, - profilePhoto, - } = info; - Object.assign (settings, { + const { _id, username, koreanName, groups, flags, email, profilePhoto } = info; + Object.assign(settings, { userId: _id, profile: { name: username, koreanName, avatarUrl: profilePhoto, - groups: groups.map (group => group.name).join (', '), - flags: flags.join (', '), + groups: groups.map((group) => group.name).join(", "), + flags: flags.join(", "), email, }, }); } - ChannelService.boot (settings); + ChannelService.boot(settings); }, [search, isAuthenticated, info, top, pathname]); return null; }; diff --git a/src/components/containers/ScrollToTop.tsx b/src/components/containers/ScrollToTop.tsx index 62dda51d..93dcce2d 100644 --- a/src/components/containers/ScrollToTop.tsx +++ b/src/components/containers/ScrollToTop.tsx @@ -1,15 +1,19 @@ -import { useEffect } from 'react'; -import PropTypes from 'prop-types'; -import { useLocation, useParams } from 'react-router-dom'; +import React, { useEffect } from "react"; +import PropTypes from "prop-types"; +import { useLocation, useParams } from "react-router-dom"; -const ScrollToTop = ({ updateWithPath } : { updateWithPath : boolean }) => { - const { route } = useParams (); - const { pathname } = useLocation (); - useEffect (() => { - window.scrollTo (0, 0); - }, [route]); - useEffect (() => { - if (updateWithPath) window.scrollTo (0, 0); +interface ScrollToTopProps { + updateWithPath?: boolean; +} + +const ScrollToTop: React.FC = ({ updateWithPath }) => { + // const { route } = useParams(); + const { pathname } = useLocation(); + // useEffect(() => { + // window.scrollTo(0, 0); + // }, [route]); + useEffect(() => { + if (updateWithPath) window.scrollTo(0, 0); }, [updateWithPath, pathname]); return null; }; diff --git a/src/components/containers/WindowResizeListener.tsx b/src/components/containers/WindowResizeListener.tsx index 464cc2cb..91ec2c69 100644 --- a/src/components/containers/WindowResizeListener.tsx +++ b/src/components/containers/WindowResizeListener.tsx @@ -1,23 +1,23 @@ -import { useCallback, useEffect } from 'react'; -import { useDispatch } from 'react-redux'; +import { useCallback, useEffect } from "react"; +import { useDispatch } from "react-redux"; -import { setWindowSize } from 'store/reducers/app'; +import { setWindowSize } from "store/reducers/app"; -function getDimensions () { +function getDimensions() { const width = window.innerWidth; const height = window.innerHeight; return { width, height }; } const WindowResizeListener = () => { - const dispatch = useDispatch (); - const handleResize = useCallback (() => { - dispatch (setWindowSize (getDimensions ())); + const dispatch = useDispatch(); + const handleResize = useCallback(() => { + dispatch(setWindowSize(getDimensions())); }, []); - useEffect (() => { - window.addEventListener ('optimizedResize', handleResize); + useEffect(() => { + window.addEventListener("optimizedResize", handleResize); return () => { - window.removeEventListener ('optimizedResize', handleResize); + window.removeEventListener("optimizedResize", handleResize); }; }, []); return null; diff --git a/src/components/molecules/OwnerInfo/OwnerInfo.js b/src/components/molecules/OwnerInfo/OwnerInfo.js index 52645f41..247481d2 100644 --- a/src/components/molecules/OwnerInfo/OwnerInfo.js +++ b/src/components/molecules/OwnerInfo/OwnerInfo.js @@ -1,11 +1,11 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import styled, { css } from 'styled-components'; +import React from "react"; +import PropTypes from "prop-types"; +import styled, { css } from "styled-components"; -import { ZaboType } from 'lib/propTypes'; -import { media } from 'lib/utils/style'; +import { ZaboType } from "lib/propTypes"; +import { media } from "lib/utils/style"; -import defaultProfile from 'static/images/defaultProfile.png'; +import defaultProfile from "static/images/defaultProfile.png"; export const OwnerInfoW = styled.div` display: flex; @@ -16,12 +16,12 @@ const ProfileW = styled.img` `; const WritingsW = styled.div` - color: ${props => props.theme.gray100}; + color: ${(props) => props.theme.gray100}; `; WritingsW.Name = styled.div` font-size: 14px; line-height: 16px; - ${media.tablet (css` + ${media.tablet(css` font-size: 14px; line-height: 16px; `)}; @@ -31,24 +31,15 @@ WritingsW.Sub = styled.div` line-height: 14px; `; -const OwnerInfo = ({ - info, showProfile, showSub, styles, style, -}) => { +const OwnerInfo = ({ info, showProfile, showSub, styles, style }) => { const { name, profilePhoto, subtitle } = info; const safeUrl = profilePhoto || defaultProfile; return ( {showProfile && } - - {name || ''} - - {showSub - && ( - - {subtitle || ''} - - )} + {name || ""} + {showSub && {subtitle || ""}} ); @@ -56,11 +47,11 @@ const OwnerInfo = ({ OwnerInfo.propTypes = { info: ZaboType.owner, - style: PropTypes.shape ({}), - styles: PropTypes.shape ({ - writings: PropTypes.shape (), - name: PropTypes.shape (), - subtitle: PropTypes.shape (), + style: PropTypes.shape({}), + styles: PropTypes.shape({ + writings: PropTypes.shape(), + name: PropTypes.shape(), + subtitle: PropTypes.shape(), }), showProfile: PropTypes.bool, showSub: PropTypes.bool, diff --git a/src/components/molecules/OwnerInfo/index.js b/src/components/molecules/OwnerInfo/index.js index 1bf76392..43928287 100644 --- a/src/components/molecules/OwnerInfo/index.js +++ b/src/components/molecules/OwnerInfo/index.js @@ -1 +1 @@ -export { default, OwnerInfoW } from './OwnerInfo'; +export { default, OwnerInfoW } from "./OwnerInfo"; diff --git a/src/components/molecules/ScrollBtn/ScrollBtn.js b/src/components/molecules/ScrollBtn/ScrollBtn.js deleted file mode 100644 index ee7f5ce8..00000000 --- a/src/components/molecules/ScrollBtn/ScrollBtn.js +++ /dev/null @@ -1,45 +0,0 @@ -import React, { useCallback } from 'react'; -import styled, { css } from 'styled-components'; - -import leftScroll from 'static/images/leftScroll.png'; -import rightScroll from 'static/images/rightScroll.png'; - -const ScrollBtnW = styled.div` - ${props => (props.show ? css`` : css` - display: none; - `)}; - @media (max-width: 640px) { - display: none; - } - float: right; - img { - width: 30px; - height: 30px; - margin-left: 3px; - border-radius: 50%; - cursor: pointer; - &:hover { - box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.2); - } - } - margin: 0 auto; -`; - -const ScrollBtn = ({ - elemId, show, scrollSize = 622, left = true, right = true, -}) => { - const leftScrollClick = useCallback (() => { - document.getElementById (elemId).scrollLeft -= scrollSize; - }, []); - const rightScrollClick = useCallback (() => { - document.getElementById (elemId).scrollLeft += scrollSize; - }, []); - return ( - - {left && left scroll button} - {right && right scroll button} - - ); -}; - -export default ScrollBtn; diff --git a/src/components/molecules/ScrollBtn/ScrollBtn.tsx b/src/components/molecules/ScrollBtn/ScrollBtn.tsx new file mode 100644 index 00000000..77e10233 --- /dev/null +++ b/src/components/molecules/ScrollBtn/ScrollBtn.tsx @@ -0,0 +1,67 @@ +import React, { useCallback } from "react"; +import styled, { css } from "styled-components"; + +import leftScroll from "static/images/leftScroll.png"; +import rightScroll from "static/images/rightScroll.png"; + +const ScrollBtnW = styled.div<{ show?: boolean }>` + ${(props) => + props.show + ? css`` + : css` + display: none; + `}; + @media (max-width: 640px) { + display: none; + } + float: right; + + img { + width: 30px; + height: 30px; + margin-left: 3px; + border-radius: 50%; + cursor: pointer; + + &:hover { + box-shadow: 0 0 8px rgba(0, 0, 0, 0.2); + } + } + + margin: 0 auto; +`; + +interface Props { + elemId: string; + show?: boolean; + scrollSize?: number; + left?: boolean; + right?: boolean; +} + +const ScrollBtn: React.FC = ({ + elemId, + show, + scrollSize = 622, + left = true, + right = true, +}) => { + const scroll = useCallback( + (offset: number) => { + const elem = document.getElementById(elemId); + if (elem) elem.scrollLeft += offset; + }, + [elemId], + ); + + const leftScrollClick = useCallback(() => scroll(-scrollSize), [scroll, scrollSize]); + const rightScrollClick = useCallback(() => scroll(scrollSize), [scroll, scrollSize]); + return ( + + {left && left scroll button} + {right && right scroll button} + + ); +}; + +export default ScrollBtn; diff --git a/src/components/molecules/ScrollBtn/index.js b/src/components/molecules/ScrollBtn/index.js deleted file mode 100644 index f8cb0ebb..00000000 --- a/src/components/molecules/ScrollBtn/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './ScrollBtn'; diff --git a/src/components/molecules/ScrollBtn/index.ts b/src/components/molecules/ScrollBtn/index.ts new file mode 100644 index 00000000..02586e23 --- /dev/null +++ b/src/components/molecules/ScrollBtn/index.ts @@ -0,0 +1 @@ +export { default } from "./ScrollBtn"; diff --git a/src/components/molecules/Select/Select.js b/src/components/molecules/Select/Select.js index a62f3bfc..73f3c6e2 100644 --- a/src/components/molecules/Select/Select.js +++ b/src/components/molecules/Select/Select.js @@ -1,14 +1,12 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import ReactSelect from 'react-select'; -import ReactAsyncSelect from 'react-select/async'; +import React from "react"; +import PropTypes from "prop-types"; +import ReactSelect from "react-select"; +import ReactAsyncSelect from "react-select/async"; const Select = ({ async, ...props }) => { let Component = ReactSelect; if (async) Component = ReactAsyncSelect; - return ( - - ); + return ; }; Select.propTypes = { diff --git a/src/components/molecules/Select/index.js b/src/components/molecules/Select/index.js index 22ae8193..cd39325e 100644 --- a/src/components/molecules/Select/index.js +++ b/src/components/molecules/Select/index.js @@ -1 +1 @@ -export { default } from './Select'; +export { default } from "./Select"; diff --git a/src/components/molecules/SimpleSelect/SimpleSelect.js b/src/components/molecules/SimpleSelect/SimpleSelect.js index 6dbb9351..117b3fee 100644 --- a/src/components/molecules/SimpleSelect/SimpleSelect.js +++ b/src/components/molecules/SimpleSelect/SimpleSelect.js @@ -1,12 +1,12 @@ -import React from 'react'; -import PropTypes from 'prop-types'; +import React from "react"; +import PropTypes from "prop-types"; -import Select from 'molecules/Select'; +import Select from "components/molecules/Select"; const sizes = { small: { fontSize: 12, - lineHeight: '14px', + lineHeight: "14px", height: 30, borderRadius: 15, indicatorSize: 16, @@ -16,7 +16,7 @@ const sizes = { }, regular: { fontSize: 16, - lineHeight: '18px', + lineHeight: "18px", height: 38, borderRadius: 4, indicatorSize: 20, @@ -33,15 +33,15 @@ const customStyles = { }), option: (provided, state) => ({ ...provided, - backgroundColor: state.isSelected ? '#F4F4F4' : '#FFFFFF', + backgroundColor: state.isSelected ? "#F4F4F4" : "#FFFFFF", fontSize: sizes[state.selectProps.size].fontSize, lineHeight: sizes[state.selectProps.size].lineHeight, - color: '#143441', - padding: '12px 16px', - display: 'flex', - alignItems: 'center', - '&:hover': { - backgroundColor: '#F4F4F4', + color: "#143441", + padding: "12px 16px", + display: "flex", + alignItems: "center", + "&:hover": { + backgroundColor: "#F4F4F4", }, }), control: (provided, state) => ({ @@ -50,17 +50,17 @@ const customStyles = { height: sizes[state.selectProps.size].height, minHeight: sizes[state.selectProps.size].height, borderRadius: sizes[state.selectProps.size].borderRadius, - background: '#F4F4F4', - border: 'none', - '&:hover': {}, - boxShadow: 'none', + background: "#F4F4F4", + border: "none", + "&:hover": {}, + boxShadow: "none", }), placeholder: (provided, state) => ({ ...provided, fontSize: sizes[state.selectProps.size].fontSize, lineHeight: sizes[state.selectProps.size].lineHeight, - padding: '2px 11px', - color: '#8F8F8F', + padding: "2px 11px", + color: "#8F8F8F", }), menu: (provided, state) => ({ ...provided, @@ -68,7 +68,7 @@ const customStyles = { paddingTop: state.options.length ? 6 : 0, width: state.selectProps.width, borderRadius: 4, - boxShadow: '0px 1px 4px rgba(0, 0, 0, 0.3)', + boxShadow: "0px 1px 4px rgba(0, 0, 0, 0.3)", }), valueContainer: (provided, state) => ({ ...provided, @@ -78,8 +78,8 @@ const customStyles = { }), singleValue: (provided, state) => ({ ...provided, - color: '#143441', - fontWeight: 'bold', + color: "#143441", + fontWeight: "bold", fontSize: sizes[state.selectProps.size].fontSize, lineHeight: sizes[state.selectProps.size].lineHeight, }), @@ -108,11 +108,11 @@ const SimpleSelect = ({ ...props }) => ( SimpleSelect.propTypes = { ...Select.propTypes, - size: PropTypes.oneOf (['small', 'regular']), + size: PropTypes.oneOf(["small", "regular"]), }; SimpleSelect.defaultProps = { - size: 'regular', + size: "regular", }; export default SimpleSelect; diff --git a/src/components/molecules/SimpleSelect/index.js b/src/components/molecules/SimpleSelect/index.js index e8e9a5ee..1c2172dd 100644 --- a/src/components/molecules/SimpleSelect/index.js +++ b/src/components/molecules/SimpleSelect/index.js @@ -1 +1 @@ -export { default } from './SimpleSelect'; +export { default } from "./SimpleSelect"; diff --git a/src/components/molecules/StatBox/StatBox.js b/src/components/molecules/StatBox/StatBox.js index d51f1781..9258de58 100644 --- a/src/components/molecules/StatBox/StatBox.js +++ b/src/components/molecules/StatBox/StatBox.js @@ -1,23 +1,23 @@ -import React, { useMemo } from 'react'; -import PropTypes from 'prop-types'; -import { useHistory } from 'react-router-dom'; -import { useDispatch, useSelector } from 'react-redux'; -import styled from 'styled-components'; -import throttle from 'lodash.throttle'; +import React, { useMemo } from "react"; +import PropTypes from "prop-types"; +import { useHistory } from "react-router-dom"; +import { useDispatch, useSelector } from "react-redux"; +import styled from "styled-components"; +import throttle from "lodash.throttle"; -import { toggleZaboLike, toggleZaboPin } from 'store/reducers/zabo'; -import { isAuthedSelector } from 'lib/utils'; +import { toggleZaboLike, toggleZaboPin } from "store/reducers/zabo"; +import { isAuthedSelector } from "lib/utils"; -import bookmarkImg from 'static/images/bookmark.svg'; -import emptyBookmarkImg from 'static/images/bookmarkEmpty.svg'; -import likeImg from 'static/images/like.svg'; -import emptyLikeImg from 'static/images/likeEmpty.svg'; -import whiteEmptyBookmarkImg from 'static/images/whiteBookmakrEmpty.svg'; -import whiteBookmarkImg from 'static/images/whiteBookmark.svg'; -import whiteLikeImg from 'static/images/whiteLike.svg'; -import whiteEmptyLikeImg from 'static/images/whiteLikeEmpty.svg'; +import bookmarkImg from "static/images/bookmark.svg"; +import emptyBookmarkImg from "static/images/bookmarkEmpty.svg"; +import likeImg from "static/images/like.svg"; +import emptyLikeImg from "static/images/likeEmpty.svg"; +import whiteEmptyBookmarkImg from "static/images/whiteBookmakrEmpty.svg"; +import whiteBookmarkImg from "static/images/whiteBookmark.svg"; +import whiteLikeImg from "static/images/whiteLike.svg"; +import whiteEmptyLikeImg from "static/images/whiteLikeEmpty.svg"; -import { alerts } from '../../../lib/variables'; +import { alerts } from "../../../lib/variables"; const icons = { colored: { @@ -106,32 +106,34 @@ const Text = styled.div` font-weight: 800; font-size: 14px; line-height: 16px; - color: #FFFFFF; + color: #ffffff; } `; const StatBox = ({ stat, type, ...props }) => { - const { - type: statType, count, zaboId, active, - } = stat; - const dispatch = useDispatch (); - const isAuthed = useSelector (isAuthedSelector); - const history = useHistory (); - const colored = (type === 'button'); - const src = icons[colored ? 'colored' : 'white'][statType][active ? 'filled' : 'empty']; - const throttledAction = useMemo (() => throttle (() => { - dispatch (toggleActions[statType] (zaboId)); - }, 200), [zaboId]); + const { type: statType, count, zaboId, active } = stat; + const dispatch = useDispatch(); + const isAuthed = useSelector(isAuthedSelector); + const history = useHistory(); + const colored = type === "button"; + const src = icons[colored ? "colored" : "white"][statType][active ? "filled" : "empty"]; + const throttledAction = useMemo( + () => + throttle(() => { + dispatch(toggleActions[statType](zaboId)); + }, 200), + [zaboId], + ); - const onClick = e => { - e.preventDefault (); - if (isAuthed) throttledAction (); - else if (window.confirm (alerts.login)) { - history.replace ({ pathname: '/auth/login', state: { referrer: history.location.pathname } }); + const onClick = (e) => { + e.preventDefault(); + if (isAuthed) throttledAction(); + else if (window.confirm(alerts.login)) { + history.replace({ pathname: "/auth/login", state: { referrer: history.location.pathname } }); } }; - if (type === 'text') { + if (type === "text") { return ( @@ -148,17 +150,17 @@ const StatBox = ({ stat, type, ...props }) => { }; StatBox.propTypes = { - stat: PropTypes.shape ({ - type: PropTypes.oneOf (['pin', 'like']).isRequired, + stat: PropTypes.shape({ + type: PropTypes.oneOf(["pin", "like"]).isRequired, count: PropTypes.number, zaboId: PropTypes.string.isRequired, active: PropTypes.bool, }).isRequired, - type: PropTypes.oneOf (['button', 'text']), + type: PropTypes.oneOf(["button", "text"]), }; StatBox.defaultProps = { - type: 'button', + type: "button", }; export default StatBox; diff --git a/src/components/molecules/StatBox/index.js b/src/components/molecules/StatBox/index.js index 77f2e615..5429de0d 100644 --- a/src/components/molecules/StatBox/index.js +++ b/src/components/molecules/StatBox/index.js @@ -1 +1 @@ -export { default } from './StatBox'; +export { default } from "./StatBox"; diff --git a/src/components/organisms/AuthCallback/AuthCallback.js b/src/components/organisms/AuthCallback/AuthCallback.js deleted file mode 100644 index c119340b..00000000 --- a/src/components/organisms/AuthCallback/AuthCallback.js +++ /dev/null @@ -1,32 +0,0 @@ -import { useEffect } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; -import queryString from 'query-string'; - -import { loginCallback } from 'store/reducers/auth'; -import storage from 'lib/storage'; - -const AuthCallback = ({ location, history }) => { - const dispatch = useDispatch (); - useEffect (() => { - const { code, state } = queryString.parse (location.search); - if (code && state) { - dispatch (loginCallback (code, state)) - .then (res => { - const referrer = storage.getItem ('referrer'); - if (referrer) { - storage.removeItem ('referrer'); - history.replace (referrer); - return; - } - history.replace (`/${res.user.username}`); - }) - .catch (error => { - alert (error.message); - history.replace ('/'); - }); - } - }, []); - return null; -}; - -export default AuthCallback; diff --git a/src/components/organisms/AuthCallback/AuthCallback.tsx b/src/components/organisms/AuthCallback/AuthCallback.tsx new file mode 100644 index 00000000..d36673db --- /dev/null +++ b/src/components/organisms/AuthCallback/AuthCallback.tsx @@ -0,0 +1,41 @@ +import React, { useEffect } from "react"; +import { useDispatch } from "react-redux"; +import queryString from "query-string"; +import type { RouteComponentProps } from "react-router-dom"; + +import { loginCallback } from "store/reducers/auth"; +import storage from "lib/storage"; +import type { Action } from "redux-actions"; + +// TODO +// This is a temporary fix to avoid type errors +// We should find a way to infer types from redux middlewares +interface Dispatch { +

(action: Action

): P; +} + +const AuthCallback: React.FC = ({ location, history }) => { + const dispatch = useDispatch(); + useEffect(() => { + const { code, state } = queryString.parse(location.search); + if (typeof code === "string" && typeof state === "string") { + dispatch(loginCallback(code, state)) + .then((res) => { + const referrer = storage.getItem("referrer"); + if (referrer) { + storage.removeItem("referrer"); + history.replace(referrer); + return; + } + history.replace(`/${res.user.username}`); + }) + .catch((error) => { + alert(error.message); + history.replace("/"); + }); + } + }, [dispatch, history, location.search]); + return null; +}; + +export default AuthCallback; diff --git a/src/components/organisms/AuthCallback/index.js b/src/components/organisms/AuthCallback/index.js deleted file mode 100644 index f48a0308..00000000 --- a/src/components/organisms/AuthCallback/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './AuthCallback'; diff --git a/src/components/organisms/AuthCallback/index.ts b/src/components/organisms/AuthCallback/index.ts new file mode 100644 index 00000000..54aa5430 --- /dev/null +++ b/src/components/organisms/AuthCallback/index.ts @@ -0,0 +1 @@ +export { default } from "./AuthCallback"; diff --git a/src/components/organisms/GroupBox/GroupBox.js b/src/components/organisms/GroupBox/GroupBox.js deleted file mode 100644 index 1cc5468f..00000000 --- a/src/components/organisms/GroupBox/GroupBox.js +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import { GroupType } from 'lib/propTypes'; - -import GroupBoxA from './GroupBoxA'; -import GroupBoxP from './GroupBoxP'; -import GroupBoxS from './GroupBoxS'; - -const GroupBox = ({ type, ...props }) => { - switch (type) { - case 'profile': - return ; - case 'simple': - return ; - case 'apply': - return ; - default: - return null; - } -}; - -GroupBox.propTypes = { - group: GroupType.isRequired, - type: PropTypes.oneOf (['profile', 'simple', 'apply']), -}; - -GroupBox.defaultProps = { - type: 'profile', -}; - -export default GroupBox; diff --git a/src/components/organisms/GroupBox/GroupBox.styled.js b/src/components/organisms/GroupBox/GroupBox.styled.tsx similarity index 62% rename from src/components/organisms/GroupBox/GroupBox.styled.js rename to src/components/organisms/GroupBox/GroupBox.styled.tsx index 98c1e6c6..786d3182 100644 --- a/src/components/organisms/GroupBox/GroupBox.styled.js +++ b/src/components/organisms/GroupBox/GroupBox.styled.tsx @@ -1,12 +1,12 @@ -import { Link } from 'react-router-dom'; -import styled, { css } from 'styled-components'; +import { Link } from "react-router-dom"; +import styled, { css } from "styled-components"; -import ProfileStats from 'organisms/ProfileStats'; +import ProfileStats from "components/organisms/ProfileStats"; -import * as mixins from 'lib/mixins'; -import { media } from 'lib/utils/style'; +import * as mixins from "lib/mixins"; +import { media } from "lib/utils/style"; -export const GroupW = styled (Link)` +export const GroupW = styled(Link)<{ isPending?: boolean }>` display: flex; align-items: center; min-width: 275px; @@ -14,17 +14,17 @@ export const GroupW = styled (Link)` border-radius: 6px; margin-right: 14px; padding: 24px 12px; - box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.3); - + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3); + img { width: 70px; height: 70px; margin-right: 12px; border-radius: 50%; - border: 1px solid ${props => props.theme.gray10}; + border: 1px solid ${(props) => props.theme.gray10}; } - ${media.tablet (css` + ${media.tablet(css` min-width: 299px; height: 126px; padding: 28px 14px; @@ -34,15 +34,18 @@ export const GroupW = styled (Link)` margin-right: 14px; } `)}; - ${props => (props.isPending ? css` - background: ${props => props.theme.gray10}; - &:hover { - cursor: not-allowed; - } - ` : '')}; + ${(props) => + props.isPending + ? css` + background: ${(props) => props.theme.gray10}; + &:hover { + cursor: not-allowed; + } + ` + : ""}; `; -export const GroupAW = styled (Link)` +export const GroupAW = styled(Link)` ${mixins.flexCenter}; flex-direction: column; border-radius: 6px; @@ -50,7 +53,7 @@ export const GroupAW = styled (Link)` height: 108px; padding: 24px 12px; margin-right: 14px; - background: ${props => props.theme.gray3}; + background: ${(props) => props.theme.gray3}; img { width: 24px; @@ -60,13 +63,13 @@ export const GroupAW = styled (Link)` font-size: 12px; padding: 0; margin: 8px 0 0 0; - color: ${props => props.theme.gray50}; + color: ${(props) => props.theme.gray50}; } - ${media.tablet (css` + ${media.tablet(css` min-width: 297px; height: 126px; - + img { width: 20px; height: 20px; @@ -77,11 +80,11 @@ export const GroupAW = styled (Link)` `)} `; -export const GroupSW = styled (GroupW)` +export const GroupSW = styled(GroupW)` width: 100%; height: 72px; padding: 12px 16px; - ${media.tablet (css` + ${media.tablet(css` height: 92px; padding: 16px 24px; `)}; @@ -91,7 +94,7 @@ export const GroupSW = styled (GroupW)` border-radius: 50%; margin-right: 12px; } - ${media.tablet (css` + ${media.tablet(css` width: 100%; img { width: 60px; @@ -108,9 +111,9 @@ export const WritingsW = styled.section` overflow: hidden; `; -export const ProfileStatsW = styled (ProfileStats)` +export const ProfileStatsW = styled(ProfileStats)` margin-top: 14px; - ${media.tablet (css` + ${media.tablet(css` margin-top: 12px; `)}; `; @@ -124,7 +127,7 @@ export const NameW = styled.div` white-space: nowrap; display: inline-block; font-weight: 800; - ${media.tablet (css` + ${media.tablet(css` font-size: 16px; `)}; `; @@ -132,9 +135,9 @@ export const NameW = styled.div` export const SubtitleW = styled.div` font-size: 10px; line-height: 11px; - color: ${props => props.theme.gray100}; + color: ${(props) => props.theme.gray100}; margin-top: 4px; - ${media.tablet (css` + ${media.tablet(css` font-size: 12px; line-height: 14px; `)}; diff --git a/src/components/organisms/GroupBox/GroupBox.tsx b/src/components/organisms/GroupBox/GroupBox.tsx new file mode 100644 index 00000000..da17036e --- /dev/null +++ b/src/components/organisms/GroupBox/GroupBox.tsx @@ -0,0 +1,26 @@ +import React from "react"; + +import GroupBoxA from "./GroupBoxA"; +import GroupBoxP from "./GroupBoxP"; +import GroupBoxS from "./GroupBoxS"; +import type { Group } from "lib/interface"; + +interface Props { + type?: "profile" | "simple" | "apply"; + group?: Group; +} + +const GroupBox: React.FC = ({ type = "profile", group = null, ...props }) => { + switch (type) { + case "profile": + return group && ; + case "simple": + return group && ; + case "apply": + return ; + default: + return null; + } +}; + +export default GroupBox; diff --git a/src/components/organisms/GroupBox/GroupBoxA.js b/src/components/organisms/GroupBox/GroupBoxA.js deleted file mode 100644 index cfd6f33e..00000000 --- a/src/components/organisms/GroupBox/GroupBoxA.js +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react'; - -import addGray from 'static/images/add_gray.svg'; - -import { GroupAW } from './GroupBox.styled'; - -const GroupBox = () => ( - - add icon -

새로운 그룹 신청하기

- -); - -GroupBox.propTypes = {}; - -export default GroupBox; diff --git a/src/components/organisms/GroupBox/GroupBoxA.tsx b/src/components/organisms/GroupBox/GroupBoxA.tsx new file mode 100644 index 00000000..ec9b599f --- /dev/null +++ b/src/components/organisms/GroupBox/GroupBoxA.tsx @@ -0,0 +1,14 @@ +import React from "react"; + +import addGray from "static/images/add_gray.svg"; + +import { GroupAW } from "./GroupBox.styled"; + +const GroupBox: React.FC = () => ( + + add icon +

새로운 그룹 신청하기

+
+); + +export default GroupBox; diff --git a/src/components/organisms/GroupBox/GroupBoxP.js b/src/components/organisms/GroupBox/GroupBoxP.js deleted file mode 100644 index f9646162..00000000 --- a/src/components/organisms/GroupBox/GroupBoxP.js +++ /dev/null @@ -1,56 +0,0 @@ -import React from 'react'; -import Tooltip from '@material-ui/core/Tooltip'; - -import { GroupType } from 'lib/propTypes'; -import { getLabeledTimeDiff } from 'lib/utils'; - -import groupDefaultProfile from 'static/images/groupDefaultProfile.png'; - -import { - GroupW, NameW, ProfileStatsW, WritingsW, -} from './GroupBox.styled'; - -const GroupBox = ({ group, ...props }) => { - const { - name, profilePhoto, zabosCount, followersCount, recentUpload, isPending, - } = group; - const timePast = recentUpload ? getLabeledTimeDiff (recentUpload, 60, 60, 24, 7, 5, 12) : '없음'; - const stats = [{ - name: '올린 자보', - value: zabosCount, - }, { - name: '팔로워', - value: followersCount, - }, { - name: '최근 업로드', - value: timePast, - }]; - - return ( - { if (isPending) e.preventDefault (); }} - {...props} - > - { - profilePhoto - ? group profile photo - : default group profile photo - } - - - {name} - - - - - ); -}; - -GroupBox.propTypes = { - group: GroupType.isRequired, -}; - -export default GroupBox; diff --git a/src/components/organisms/GroupBox/GroupBoxP.tsx b/src/components/organisms/GroupBox/GroupBoxP.tsx new file mode 100644 index 00000000..f766d78c --- /dev/null +++ b/src/components/organisms/GroupBox/GroupBoxP.tsx @@ -0,0 +1,59 @@ +import React from "react"; +import Tooltip from "@material-ui/core/Tooltip"; + +import { getLabeledTimeDiff } from "lib/utils"; + +import groupDefaultProfile from "static/images/groupDefaultProfile.png"; + +import { GroupW, NameW, ProfileStatsW, WritingsW } from "./GroupBox.styled"; +import type { Group } from "lib/interface"; + +interface Props { + group: Group; +} + +const GroupBox: React.FC = ({ group, ...props }) => { + const timePast = group.recentUpload + ? getLabeledTimeDiff(group.recentUpload, 60, 60, 24, 7, 5, 12) + : "없음"; + const stats = [ + { + name: "올린 자보", + value: group.zabosCount, + }, + { + name: "팔로워", + value: group.followersCount, + }, + { + name: "최근 업로드", + value: timePast, + }, + ]; + + return ( + { + if (group.isPending) e.preventDefault(); + }} + {...props} + > + {group.profilePhoto ? ( + group profile photo + ) : ( + default group profile photo + )} + + + {group.name} + + + + + ); +}; + +export default GroupBox; diff --git a/src/components/organisms/GroupBox/GroupBoxS.js b/src/components/organisms/GroupBox/GroupBoxS.js deleted file mode 100644 index 52d9a867..00000000 --- a/src/components/organisms/GroupBox/GroupBoxS.js +++ /dev/null @@ -1,48 +0,0 @@ -import React, { useEffect, useRef, useState } from 'react'; -import { useSelector } from 'react-redux'; -import get from 'lodash.get'; - -import SuperTooltip from 'atoms/SuperTooltip'; - -import { GroupType } from 'lib/propTypes'; -import { isElemWidthOverflown } from 'lib/utils'; - -import groupDefaultProfile from 'static/images/groupDefaultProfile.png'; - -import { - GroupSW, NameW, SubtitleW, WritingsW, -} from './GroupBox.styled'; - -const GroupBoxS = ({ group, ...props }) => { - const { - name, profilePhoto, subtitle, - } = group; - const width = useSelector (state => get (state, ['app', 'windowSize', 'width'])); - const nameRef = useRef (null); - const [showTooltip, setShowTooltip] = useState (false); - useEffect (() => { setShowTooltip (isElemWidthOverflown (nameRef.current)); }, [nameRef, width]); - - return ( - -
- { - profilePhoto - ? group profile - : default group profile - } -
- - - {name} - - {subtitle || '한 줄 소개 없음'} - -
- ); -}; - -GroupBoxS.propTypes = { - group: GroupType.isRequired, -}; - -export default GroupBoxS; diff --git a/src/components/organisms/GroupBox/GroupBoxS.tsx b/src/components/organisms/GroupBox/GroupBoxS.tsx new file mode 100644 index 00000000..b8016a3a --- /dev/null +++ b/src/components/organisms/GroupBox/GroupBoxS.tsx @@ -0,0 +1,45 @@ +import React, { useEffect, useRef, useState } from "react"; +import { useSelector } from "react-redux"; +import get from "lodash.get"; + +import SuperTooltip from "components/atoms/SuperTooltip"; + +import { isElemWidthOverflown } from "lib/utils"; + +import groupDefaultProfile from "static/images/groupDefaultProfile.png"; + +import { GroupSW, NameW, SubtitleW, WritingsW } from "./GroupBox.styled"; +import { Group } from "lib/interface"; + +interface Props { + group: Group; +} + +const GroupBoxS: React.FC = ({ group, ...props }) => { + const width = useSelector((state) => get(state, ["app", "windowSize", "width"])); + const nameRef = useRef(null); + const [showTooltip, setShowTooltip] = useState(false); + useEffect(() => { + nameRef.current && setShowTooltip(isElemWidthOverflown(nameRef.current)); + }, [nameRef, width]); + + return ( + +
+ {group.profilePhoto ? ( + group profile + ) : ( + default group profile + )} +
+ + + {group.name} + + {group.subtitle || "한 줄 소개 없음"} + +
+ ); +}; + +export default GroupBoxS; diff --git a/src/components/organisms/GroupBox/index.js b/src/components/organisms/GroupBox/index.js deleted file mode 100644 index cb0f05b3..00000000 --- a/src/components/organisms/GroupBox/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './GroupBox'; diff --git a/src/components/organisms/GroupBox/index.ts b/src/components/organisms/GroupBox/index.ts new file mode 100644 index 00000000..e13c587a --- /dev/null +++ b/src/components/organisms/GroupBox/index.ts @@ -0,0 +1 @@ +export { default } from "./GroupBox"; diff --git a/src/components/organisms/GroupList/GroupList.js b/src/components/organisms/GroupList/GroupList.tsx similarity index 54% rename from src/components/organisms/GroupList/GroupList.js rename to src/components/organisms/GroupList/GroupList.tsx index e83cec80..12405e3c 100644 --- a/src/components/organisms/GroupList/GroupList.js +++ b/src/components/organisms/GroupList/GroupList.tsx @@ -1,14 +1,13 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import styled, { css } from 'styled-components'; +import React from "react"; +import styled from "styled-components"; -import { GroupType } from 'lib/propTypes'; +import ScrollBtn from "../../molecules/ScrollBtn"; +import GroupBox from "../GroupBox"; +import type { Group } from "lib/interface/schemas"; -import ScrollBtn from '../../molecules/ScrollBtn'; -import GroupBox from '../GroupBox'; - -export const Groups = styled.section` +const GroupsComponent = styled.section` width: 1032px; + h1 { display: inline-block; font-size: 22px; @@ -28,7 +27,7 @@ export const Groups = styled.section` } `; -Groups.List = styled.div` +const GroupsListComponent = styled.div` display: flex; scroll-behavior: smooth; width: 100%; @@ -37,10 +36,14 @@ Groups.List = styled.div` overflow-x: scroll; /* overflow-y: visible; */ white-space: nowrap; - + /* hide scroll bar */ /* -webkit- (Chrome, Safari, newer versions of Opera) */ - &::-webkit-scrollbar { width: 0 !important } + + &::-webkit-scrollbar { + width: 0 !important; + } + /* Firefox */ scrollbar-width: none; /* -ms- (Internet Explorer +10) */ @@ -51,33 +54,32 @@ Groups.List = styled.div` } `; +export const Groups = Object.assign(GroupsComponent, { List: GroupsListComponent }); + const text = { - profile: '소속 그룹', - search: '그룹 검색 결과', -}; + profile: "소속 그룹", + search: "그룹 검색 결과", +} as const; + +interface Props { + type: keyof typeof text; + groups: Group[]; + hasApplyBox?: boolean; + isMyProfile?: boolean; +} -const GroupList = ({ - type, groups, hasApplyBox, isMyProfile, -}) => ( +const GroupList: React.FC = ({ type, groups, isMyProfile }) => (

{text[type]}

3} /> - {groups.map (group => )} - {isMyProfile && } + {groups.map((group) => ( + + ))} + {isMyProfile && } <> 
); -GroupList.propTypes = { - type: PropTypes.string.isRequired, - groups: PropTypes.arrayOf (GroupType).isRequired, - hasApplyBox: PropTypes.bool, -}; - -GroupList.defaultProps = { - hasApplyBox: false, -}; - export default GroupList; diff --git a/src/components/organisms/GroupList/index.js b/src/components/organisms/GroupList/index.js deleted file mode 100644 index 8bdc0511..00000000 --- a/src/components/organisms/GroupList/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './GroupList'; diff --git a/src/components/organisms/GroupList/index.ts b/src/components/organisms/GroupList/index.ts new file mode 100644 index 00000000..e4cbd0d0 --- /dev/null +++ b/src/components/organisms/GroupList/index.ts @@ -0,0 +1 @@ +export { default } from "./GroupList"; diff --git a/src/components/organisms/List/List.js b/src/components/organisms/List/List.js index 01ce139c..47af63c4 100644 --- a/src/components/organisms/List/List.js +++ b/src/components/organisms/List/List.js @@ -1,26 +1,20 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import styled from 'styled-components'; +import React from "react"; +import PropTypes from "prop-types"; +import styled from "styled-components"; const StyledList = styled.div` width: 100%; `; -const List = ({ dataSource, renderItem }) => ( - - {dataSource.map (renderItem)} - -); +const List = ({ dataSource, renderItem }) => {dataSource.map(renderItem)}; List.propTypes = { - dataSource: PropTypes.arrayOf (PropTypes.shape ({ - - })).isRequired, + dataSource: PropTypes.arrayOf(PropTypes.shape({})).isRequired, renderItem: PropTypes.func, }; List.defaultProps = { - renderItem: item =>
{item}
, + renderItem: (item) =>
{item}
, }; export default List; diff --git a/src/components/organisms/List/index.js b/src/components/organisms/List/index.js index f4550745..8e34bd39 100644 --- a/src/components/organisms/List/index.js +++ b/src/components/organisms/List/index.js @@ -1 +1 @@ -export { default } from './List'; +export { default } from "./List"; diff --git a/src/components/organisms/MemberItem/MemberItem.js b/src/components/organisms/MemberItem/MemberItem.js index 40657aaa..fca70b9a 100644 --- a/src/components/organisms/MemberItem/MemberItem.js +++ b/src/components/organisms/MemberItem/MemberItem.js @@ -1,20 +1,20 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import styled, { css } from 'styled-components'; +import React from "react"; +import PropTypes from "prop-types"; +import styled, { css } from "styled-components"; -import SimpleSelect from 'molecules/SimpleSelect'; +import SimpleSelect from "components/molecules/SimpleSelect"; -import useSetState from 'hooks/useSetState'; -import { colors } from 'lib/theme'; +import useSetState from "hooks/useSetState"; +import { colors } from "lib/theme"; -import cross from 'static/images/cross.svg'; -import groupDefaultProfile from 'static/images/groupDefaultProfile.png'; +import cross from "static/images/cross.svg"; +import groupDefaultProfile from "static/images/groupDefaultProfile.png"; const GroupMember = styled.div` display: flex; align-items: center; justify-content: space-between; - border-bottom: 1px solid #E9E9E9; + border-bottom: 1px solid #e9e9e9; &:last-child { border-bottom: none; } @@ -62,7 +62,7 @@ GroupMember.Name = styled.div` GroupMember.Role = styled.div` height: 16px; - font-size: 14px; + font-size: 14px; color: #202020; @media (max-width: 640px) { font-size: 14px; @@ -71,12 +71,11 @@ GroupMember.Role = styled.div` GroupMember.Edit = styled.div` display: flex; - >* { + > * { margin-right: 8px; } `; - const gray3 = css` background-color: ${colors.gray3}; color: ${colors.gray50}; @@ -100,24 +99,20 @@ const themes = { gray3, main, gray3Border }; GroupMember.Button = styled.button` border-radius: 15px; height: 30px; - ${props => themes[props.colorTheme]}; + ${(props) => themes[props.colorTheme]}; &:last-child { margin-right: 0; } `; const roleOptions = [ - { value: 'editor', label: '편집자' }, - { value: 'admin', label: '관리자' }, + { value: "editor", label: "편집자" }, + { value: "admin", label: "관리자" }, ]; -const MemberItem = ({ - member, updateMember, removeMember, ...props -}) => { - const { - _id, username, name, koreanName, profilePhoto, role, - } = member; - const [state, setState] = useSetState ({ +const MemberItem = ({ member, updateMember, removeMember, ...props }) => { + const { _id, username, name, koreanName, profilePhoto, role } = member; + const [state, setState] = useSetState({ edit: false, roleOption: roleOptions[0], }); @@ -128,7 +123,7 @@ const MemberItem = ({ {username} @@ -136,48 +131,49 @@ const MemberItem = ({ - { - !edit - ? setState ({ edit: true })}>수정하기 - : ( - <> - setState ({ roleOption: newOption })} - isClearable={false} - width={73} - size="small" - /> - removeMember (_id)} - > - delete user - - { - updateMember (_id, roleOption.value); - setState ({ edit: false }); - }} - >완료 - - - ) - } + {!edit ? ( + setState({ edit: true })}> + 수정하기 + + ) : ( + <> + setState({ roleOption: newOption })} + isClearable={false} + width={73} + size="small" + /> + removeMember(_id)} + > + delete user + + { + updateMember(_id, roleOption.value); + setState({ edit: false }); + }} + > + 완료 + + + )} ); }; MemberItem.propTypes = { - member: PropTypes.shape ({ + member: PropTypes.shape({ _id: PropTypes.string, username: PropTypes.string, name: PropTypes.string, diff --git a/src/components/organisms/MemberItem/index.js b/src/components/organisms/MemberItem/index.js index 8998b01d..8cb79278 100644 --- a/src/components/organisms/MemberItem/index.js +++ b/src/components/organisms/MemberItem/index.js @@ -1 +1 @@ -export { default } from './MemberItem'; +export { default } from "./MemberItem"; diff --git a/src/components/organisms/ProfileStats/ProfileStats.js b/src/components/organisms/ProfileStats/ProfileStats.js index 5c8061ad..d3c16164 100644 --- a/src/components/organisms/ProfileStats/ProfileStats.js +++ b/src/components/organisms/ProfileStats/ProfileStats.js @@ -1,26 +1,26 @@ -import React from 'react'; -import PropTypes from 'prop-types'; +import React from "react"; +import PropTypes from "prop-types"; -import { Stats } from './ProfileStats.styled'; +import { Stats } from "./ProfileStats.styled"; const ProfileStats = ({ stats, smallV, ...props }) => ( - { - stats.map (({ name, value }) => ( - -

{value || 0}

-
{name}
-
- )) - } + {stats.map(({ name, value }) => ( + +

{value || 0}

+
{name}
+
+ ))}
); ProfileStats.propTypes = { - stats: PropTypes.arrayOf (PropTypes.shape ({ - name: PropTypes.string.isRequired, - value: PropTypes.oneOfType ([PropTypes.number, PropTypes.string]).isRequired, - })).isRequired, + stats: PropTypes.arrayOf( + PropTypes.shape({ + name: PropTypes.string.isRequired, + value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, + }), + ).isRequired, smallV: PropTypes.bool, }; diff --git a/src/components/organisms/ProfileStats/ProfileStats.styled.js b/src/components/organisms/ProfileStats/ProfileStats.styled.js index 0641169c..adc006cd 100644 --- a/src/components/organisms/ProfileStats/ProfileStats.styled.js +++ b/src/components/organisms/ProfileStats/ProfileStats.styled.js @@ -1,4 +1,4 @@ -import styled, { css } from 'styled-components'; +import styled, { css } from "styled-components"; export const Stats = styled.section` display: inline-block; @@ -6,7 +6,7 @@ export const Stats = styled.section` Stats.elem = styled.div` display: inline-block; - border-right: 1px solid #E9E9E9; + border-right: 1px solid #e9e9e9; padding: 0 18px; h3 { @@ -18,28 +18,35 @@ Stats.elem = styled.div` } div { font-size: 14px; - color: #8F8F8F; + color: #8f8f8f; text-align: center; } - ${props => (props.small ? css` - padding: 0 14px; - h3 { - font-size: 16px; - margin-bottom: 4px; - font-weight: bold; - } - div { font-size: 12px } - @media (max-width: 640px) { - padding: 0 11px; - h3 { - font-size: 14px; - margin-bottom: 3px; - } - div { font-size: 10px } - } - ` : css``)}; - + ${(props) => + props.small + ? css` + padding: 0 14px; + h3 { + font-size: 16px; + margin-bottom: 4px; + font-weight: bold; + } + div { + font-size: 12px; + } + @media (max-width: 640px) { + padding: 0 11px; + h3 { + font-size: 14px; + margin-bottom: 3px; + } + div { + font-size: 10px; + } + } + ` + : css``}; + &:nth-child(1) { padding-left: 0; } diff --git a/src/components/organisms/ProfileStats/index.js b/src/components/organisms/ProfileStats/index.js index 0292c338..c02642b8 100644 --- a/src/components/organisms/ProfileStats/index.js +++ b/src/components/organisms/ProfileStats/index.js @@ -1 +1 @@ -export { default } from './ProfileStats'; +export { default } from "./ProfileStats"; diff --git a/src/components/organisms/SearchSelect/SearchSelect.js b/src/components/organisms/SearchSelect/SearchSelect.js index 279893e1..1dc49ba4 100644 --- a/src/components/organisms/SearchSelect/SearchSelect.js +++ b/src/components/organisms/SearchSelect/SearchSelect.js @@ -1,110 +1,108 @@ -import React from 'react'; -import { components } from 'react-select'; +import React from "react"; +import { components } from "react-select"; -import Select from 'molecules/Select'; +import Select from "components/molecules/Select"; -import { media } from 'lib/utils/style'; +import { media } from "lib/utils/style"; -import defaultProfile from 'static/images/defaultProfile.png'; -import searchIcon from 'static/images/search-icon-navy.png'; +import defaultProfile from "static/images/defaultProfile.png"; +import searchIcon from "static/images/search-icon-navy.png"; const customStyles = { container: (provided, state) => { - const focusStyle = state.isFocused ? { - boxShadow: '0px 2px 8px rgba(0, 0, 0, 0.3)', - borderRadius: 4, - } : {}; + const focusStyle = state.isFocused + ? { + boxShadow: "0px 2px 8px rgba(0, 0, 0, 0.3)", + borderRadius: 4, + } + : {}; return { ...provided, maxWidth: 388, - width: '100%', + width: "100%", ...focusStyle, }; }, option: (provided, state) => ({ ...provided, - backgroundColor: state.isSelected ? '#F4F4F4' : '#FFFFFF', - padding: '12px 16px', - display: 'flex', - alignItems: 'center', + backgroundColor: state.isSelected ? "#F4F4F4" : "#FFFFFF", + padding: "12px 16px", + display: "flex", + alignItems: "center", img: { width: 32, height: 32, marginRight: 10, - borderRadius: '50%', + borderRadius: "50%", }, - '&:hover': { - backgroundColor: '#F4F4F4', + "&:hover": { + backgroundColor: "#F4F4F4", }, }), control: (provided, state) => { - const focusStyle = state.isFocused ? { - background: '#FFFFFF', - borderRadius: '4px 4px 0 0', - boxShadow: 'none', - borderBottom: '1px solid #E9E9E9', - } : {}; - return ({ + const focusStyle = state.isFocused + ? { + background: "#FFFFFF", + borderRadius: "4px 4px 0 0", + boxShadow: "none", + borderBottom: "1px solid #E9E9E9", + } + : {}; + return { ...provided, maxWidth: 388, - width: '100%', + width: "100%", height: 38, borderRadius: 4, - background: '#F4F4F4', - border: 'none', + background: "#F4F4F4", + border: "none", img: { width: 18, height: 18, marginLeft: 19, }, - '&:hover': {}, + "&:hover": {}, ...focusStyle, - }); + }; }, placeholder: (provided, state) => ({ ...provided, - width: '100%', + width: "100%", fontSize: 16, - overflow: 'hidden', - textOverflow: 'ellipsis', - whiteSpace: 'nowrap', - padding: '2px 11px', - lineHeight: '18px', - color: '#8F8F8F', + overflow: "hidden", + textOverflow: "ellipsis", + whiteSpace: "nowrap", + padding: "2px 11px", + lineHeight: "18px", + color: "#8F8F8F", }), input: (provided, state) => ({ ...provided, - padding: '2px 11px', + padding: "2px 11px", }), menu: (provided, state) => ({ - label: 'menu', - background: '#FFFFFF', - top: '100%', - position: 'absolute', + label: "menu", + background: "#FFFFFF", + top: "100%", + position: "absolute", zIndex: 1, paddingTop: state.options.length ? 12 : 0, maxWidth: 388, - width: '100%', - boxShadow: '0px 2px 8px rgba(0, 0, 0, 0.3)', + width: "100%", + boxShadow: "0px 2px 8px rgba(0, 0, 0, 0.3)", }), }; const CustomControl = ({ children, ...props }) => ( - search icon + search icon {children} ); const CustomOption = ({ children, ...props }) => { const { - data: { - username, koreanName, name, profilePhoto, - }, + data: { username, koreanName, name, profilePhoto }, } = props; return ( @@ -134,8 +132,6 @@ SearchSelect.propTypes = { ...Select.propTypes, }; -SearchSelect.defaultProps = { - -}; +SearchSelect.defaultProps = {}; export default SearchSelect; diff --git a/src/components/organisms/SearchSelect/index.js b/src/components/organisms/SearchSelect/index.js index ec092652..eafb36ee 100644 --- a/src/components/organisms/SearchSelect/index.js +++ b/src/components/organisms/SearchSelect/index.js @@ -1 +1 @@ -export { default } from './SearchSelect'; +export { default } from "./SearchSelect"; diff --git a/src/components/organisms/StyledQuill.js b/src/components/organisms/StyledQuill.js index 607e946e..66c6f43e 100644 --- a/src/components/organisms/StyledQuill.js +++ b/src/components/organisms/StyledQuill.js @@ -1,84 +1,93 @@ -import 'react-quill/dist/quill.bubble.css'; +import "react-quill/dist/quill.bubble.css"; -import ReactQuill from 'react-quill'; -import styled, { css } from 'styled-components'; +import ReactQuill from "react-quill"; +import styled, { css } from "styled-components"; +let OSName = "Unknown OS"; +if (navigator.appVersion.indexOf("Win") !== -1) OSName = "Windows"; +if (navigator.appVersion.indexOf("Mac") !== -1) OSName = "MacOS"; +if (navigator.appVersion.indexOf("X11") !== -1) OSName = "UNIX"; +if (navigator.appVersion.indexOf("Linux") !== -1) OSName = "Linux"; -let OSName = 'Unknown OS'; -if (navigator.appVersion.indexOf ('Win') !== -1) OSName = 'Windows'; -if (navigator.appVersion.indexOf ('Mac') !== -1) OSName = 'MacOS'; -if (navigator.appVersion.indexOf ('X11') !== -1) OSName = 'UNIX'; -if (navigator.appVersion.indexOf ('Linux') !== -1) OSName = 'Linux'; - -const StyledQuill = styled (ReactQuill)` +const StyledQuill = styled(ReactQuill)` @import url(//fonts.googleapis.com/css?family=Noto+Sans+KR:400,700&display=swap&subset=korean); .ql-container { .ql-editor { font-size: 16px; font-family: NanumSquare, Arial, sans-serif; - ${OSName === 'Windows' ? css` - p { - transform: skewX(0.3deg); - } - ` : ''}; - ol { padding-left: 0; } - ul { padding-left: 0; } + ${OSName === "Windows" + ? css` + p { + transform: skewX(0.3deg); + } + ` + : ""}; + ol { + padding-left: 0; + } + ul { + padding-left: 0; + } li { - padding-left: 1em; - &::before { - font-family: NotoSans, Arial, sans-serif; - } - } - ${(() => { - let result = ''; - for (let i = 1; i <= 8; i += 1) { - result += `.ql-indent-${i} { padding-left: calc(1em + ${3 * i}px); }\n`; - result += `p.ql-indent-${i} { padding-left: ${3 * i}px; }\n`; - } - return result; - }) ()}; - } - } - - ${props => (!props.readOnly ? css` - .ql-container { - border: 0; - margin: 8px 0 18px 0; - .ql-editor { - border-radius: 4px; - min-height: 142px; - padding: 11px 16px; - background-color: #F4F4F4; - font-size: 14px; - color: #202020; - &::placeholder { - color: #8F8F8F; + padding-left: 1em; + &::before { + font-family: NotoSans, Arial, sans-serif; } } + ${(() => { + let result = ""; + for (let i = 1; i <= 8; i += 1) { + result += `.ql-indent-${i} { padding-left: calc(1em + ${3 * i}px); }\n`; + result += `p.ql-indent-${i} { padding-left: ${3 * i}px; }\n`; + } + return result; + })()}; } - ` - : css` - .ql-container { - .ql-editor { - font-size: 14px; - line-height: 18px; - color: #202020; - padding: 0; - } - } - `)}; + } - ${props => (props.groupSetting ? css` - .ql-container .ql-editor p { - font-weight: 500; - color: #363636; - font-size: 16px; - @media (max-width: 640px) { - font-size: 14px; - } - } - ` : css` - `)}; + ${(props) => + !props.readOnly + ? css` + .ql-container { + border: 0; + margin: 8px 0 18px 0; + .ql-editor { + border-radius: 4px; + min-height: 142px; + padding: 11px 16px; + background-color: #f4f4f4; + font-size: 14px; + color: #202020; + &::placeholder { + color: #8f8f8f; + } + } + } + ` + : css` + .ql-container { + .ql-editor { + font-size: 14px; + line-height: 18px; + color: #202020; + padding: 0; + } + } + `}; + + ${(props) => + props.groupSetting + ? css` + .ql-container .ql-editor p { + font-weight: 500; + color: #363636; + font-size: 16px; + @media (max-width: 640px) { + font-size: 14px; + } + } + ` + : css``}; `; export default StyledQuill; diff --git a/src/components/organisms/ZaboCard/ZaboCard.js b/src/components/organisms/ZaboCard/ZaboCard.js index 9e64654c..9b734333 100644 --- a/src/components/organisms/ZaboCard/ZaboCard.js +++ b/src/components/organisms/ZaboCard/ZaboCard.js @@ -1,24 +1,24 @@ -import React from 'react'; -import PropTypes from 'prop-types'; +import React from "react"; +import PropTypes from "prop-types"; -import withZabo from 'hoc/withZabo'; -import { ZaboType } from 'lib/propTypes'; +import withZabo from "hoc/withZabo"; +import { ZaboType } from "lib/propTypes"; -import ZaboCardL from './ZaboCardL'; -import ZaboCardM from './ZaboCardM'; +import ZaboCardL from "./ZaboCardL"; +import ZaboCardM from "./ZaboCardM"; const ZaboCard = ({ zabo, size }) => { - if (size === 'large') return ; + if (size === "large") return ; return ; }; ZaboCard.propTypes = { zabo: ZaboType.isRequired, - size: PropTypes.oneOf (['medium', 'large']), + size: PropTypes.oneOf(["medium", "large"]), }; ZaboCard.defaultProps = { - size: 'medium', + size: "medium", }; -export default withZabo (ZaboCard, false, false); +export default withZabo(ZaboCard, false, false); diff --git a/src/components/organisms/ZaboCard/ZaboCard.stories.js b/src/components/organisms/ZaboCard/ZaboCard.stories.js index c8320940..516330bf 100644 --- a/src/components/organisms/ZaboCard/ZaboCard.stories.js +++ b/src/components/organisms/ZaboCard/ZaboCard.stories.js @@ -1,11 +1,8 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; +import React from "react"; +import { storiesOf } from "@storybook/react"; -import ZaboCard from './index'; +import ZaboCard from "./index"; -storiesOf ('organisms/ZaboCard', module).add ( - 'Default', - () => , { - notes: '', - }, -); +storiesOf("organisms/ZaboCard", module).add("Default", () => , { + notes: "", +}); diff --git a/src/components/organisms/ZaboCard/ZaboCard.styled.js b/src/components/organisms/ZaboCard/ZaboCard.styled.js index 20a98192..a66c2d77 100644 --- a/src/components/organisms/ZaboCard/ZaboCard.styled.js +++ b/src/components/organisms/ZaboCard/ZaboCard.styled.js @@ -1,7 +1,7 @@ -import styled, { css } from 'styled-components'; +import styled, { css } from "styled-components"; -import * as mixins from 'lib/mixins'; -import { media } from 'lib/utils/style'; +import * as mixins from "lib/mixins"; +import { media } from "lib/utils/style"; /* ============ Zabo ============ */ const ZaboCardW = styled.div` @@ -21,13 +21,14 @@ export const PosterW = styled.div` cursor: pointer; overflow: hidden; border-radius: 4px; - ${props => (props.anchor === 'width' - ? css` - width: 240px; - ` - : css` - height: 100%; - `)}; + ${(props) => + props.anchor === "width" + ? css` + width: 240px; + ` + : css` + height: 100%; + `}; &:hover { .hover-show { visibility: visible; @@ -35,7 +36,10 @@ export const PosterW = styled.div` } @media (max-width: 640px) { &:hover { - .dimmer, .hover-show { display: none } + .dimmer, + .hover-show { + display: none; + } } } `; @@ -48,14 +52,20 @@ PosterW.Image = styled.img` PosterW.Dimmer = styled.div` position: absolute; - top: 0; left: 0; width: 100%; height: 100%; - background-color: rgba(0, 0, 0, .03); + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.03); `; export const OverlayW = styled.div` visibility: hidden; position: absolute; - top: 0; left: 0; width: 100%; height: 100%; + top: 0; + left: 0; + width: 100%; + height: 100%; background: linear-gradient(0deg, rgba(0, 0, 0, 0.35), rgba(0, 0, 0, 0.35)); `; @@ -82,7 +92,7 @@ export const WritingsW = styled.div` font-size: 14px; line-height: 16px; color: #143441; - overflow : hidden; + overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } @@ -90,7 +100,7 @@ export const WritingsW = styled.div` margin-top: 2px; font-size: 12px; line-height: 14px; - color: #8F8F8F; + color: #8f8f8f; } .author { margin-top: 8px; @@ -119,7 +129,7 @@ export const PosterLW = styled.div` height: 100%; border-radius: 4px 0 0 4px; width: 114px; - ${media.tablet (css` + ${media.tablet(css` width: 140px; `)}; `; @@ -134,23 +144,26 @@ PosterLW.Image = styled.img` PosterLW.Dimmer = styled.div` position: absolute; - top: 0; left: 0; width: 100%; height: 100%; - background-color: rgba(0, 0, 0, .03); + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.03); `; export const ZaboCardLW = styled.section` display: flex; width: 100%; height: 145px; - border: 1px solid #E9E9E9; + border: 1px solid #e9e9e9; border-radius: 4px; overflow: hidden; - color: ${props => props.theme.white}; + color: ${(props) => props.theme.white}; margin-bottom: 8px; ${PosterLW} { height: 145px; } - ${media.tablet (css` + ${media.tablet(css` height: 178px; margin-bottom: 16px; ${PosterLW} { @@ -178,12 +191,12 @@ export const Title = styled.div` margin-top: 9px; margin-bottom: 11px; margin-right: 24px; - color: ${props => props.theme.main}; + color: ${(props) => props.theme.main}; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; min-height: 16px; - ${media.tablet (css` + ${media.tablet(css` font-size: 18px; line-height: 20px; min-height: 20px; @@ -205,9 +218,9 @@ OwnerW.Name = styled.div` ${mixins.flexCenter}; font-size: 14px; line-height: 16px; - color: ${props => props.theme.gray100}; + color: ${(props) => props.theme.gray100}; margin-left: 6px; - ${media.tablet (css` + ${media.tablet(css` font-size: 14px; line-height: 16px; margin-left: 8px; @@ -221,7 +234,7 @@ export const MetaInfo = styled.div` line-height: 11px; color: #666666; margin-top: 24px; - ${media.tablet (css` + ${media.tablet(css` font-size: 12px; line-height: 14px; margin-top: 44px; @@ -233,11 +246,10 @@ export const MetaInfo = styled.div` // } MetaInfo.Dot = styled.div` display: inline-block; - color: #8F8F8F; + color: #8f8f8f; vertical-align: middle; text-align: center; width: 14px; `; - export default ZaboCardW; diff --git a/src/components/organisms/ZaboCard/ZaboCardL.js b/src/components/organisms/ZaboCard/ZaboCardL.js index 9b3272d5..ad9949b6 100644 --- a/src/components/organisms/ZaboCard/ZaboCardL.js +++ b/src/components/organisms/ZaboCard/ZaboCardL.js @@ -1,34 +1,34 @@ -import React, { useEffect, useRef, useState } from 'react'; -import { Link } from 'react-router-dom'; -import { useSelector } from 'react-redux'; -import Tooltip from '@material-ui/core/Tooltip'; -import get from 'lodash.get'; -import moment from 'moment'; +import React, { useEffect, useRef, useState } from "react"; +import { Link } from "react-router-dom"; +import { useSelector } from "react-redux"; +import Tooltip from "@material-ui/core/Tooltip"; +import get from "lodash.get"; +import moment from "moment"; -import { CategoryListW, CategoryW } from 'atoms/Category'; -import SuperTooltip from 'atoms/SuperTooltip'; +import { CategoryListW, CategoryW } from "components/atoms/Category"; +import SuperTooltip from "components/atoms/SuperTooltip"; -import { ZaboType } from 'lib/propTypes'; -import { isElemWidthOverflown } from 'lib/utils'; +import { ZaboType } from "lib/propTypes"; +import { isElemWidthOverflown } from "lib/utils"; -import groupDefaultProfile from 'static/images/groupDefaultProfile.png'; +import groupDefaultProfile from "static/images/groupDefaultProfile.png"; -import { - MetaInfo, OwnerW, - PosterLW, Title, - WritingsLW, ZaboCardLW, -} from './ZaboCard.styled'; +import { MetaInfo, OwnerW, PosterLW, Title, WritingsLW, ZaboCardLW } from "./ZaboCard.styled"; const PosterL = ({ zabo }) => { - const [height, setHeight] = useState (174); + const [height, setHeight] = useState(174); const { photos } = zabo; return ( { if (ref) setHeight (ref.clientHeight); }} - style={{ - // paddingLeft: (photos[0].width / photos[0].height) * height, + ref={(ref) => { + if (ref) setHeight(ref.clientHeight); }} + style={ + { + // paddingLeft: (photos[0].width / photos[0].height) * height, + } + } > @@ -41,38 +41,41 @@ PosterL.propTypes = { }; const ZaboCardL = ({ zabo }) => { - const { - _id, category, title, owner, createdAt, views, effectiveViews, - } = zabo; - const width = useSelector (state => get (state, ['app', 'windowSize', 'width'])); - const titleRef = useRef (null); - const [showTooltip, setShowTooltip] = useState (false); - useEffect (() => { setShowTooltip (isElemWidthOverflown (titleRef.current)); }, [width, titleRef]); - const createdAtLabel = moment (createdAt).format ('YYYY-MM-DD'); + const { _id, category, title, owner, createdAt, views, effectiveViews } = zabo; + const width = useSelector((state) => get(state, ["app", "windowSize", "width"])); + const titleRef = useRef(null); + const [showTooltip, setShowTooltip] = useState(false); + useEffect(() => { + setShowTooltip(isElemWidthOverflown(titleRef.current)); + }, [width, titleRef]); + const createdAtLabel = moment(createdAt).format("YYYY-MM-DD"); return (
- +
- {category.slice (0, 3).map (cat => # {cat})} - {category.length > 3 - && ( - - {category.slice (3).map (cat => # {cat})} - - )} - placement="top" - enterTouchDelay={0} - > - ··· - - )} + {category.slice(0, 3).map((cat) => ( + # {cat} + ))} + {category.length > 3 && ( + + {category.slice(3).map((cat) => ( + # {cat} + ))} + + } + placement="top" + enterTouchDelay={0} + > + ··· + + )} {title} @@ -85,11 +88,9 @@ const ZaboCardL = ({ zabo }) => { {createdAtLabel} - - · - + · -
조회수 {views.toLocaleString ()}
+
조회수 {views.toLocaleString()}
diff --git a/src/components/organisms/ZaboCard/ZaboCardM.js b/src/components/organisms/ZaboCard/ZaboCardM.js index b93b354a..e1376caf 100644 --- a/src/components/organisms/ZaboCard/ZaboCardM.js +++ b/src/components/organisms/ZaboCard/ZaboCardM.js @@ -1,34 +1,44 @@ -import React from 'react'; -import { Link } from 'react-router-dom'; +import React from "react"; +import { Link } from "react-router-dom"; -import DueDate from 'atoms/DueDate'; -import StatBox from 'molecules/StatBox'; +import DueDate from "components/atoms/DueDate"; +import StatBox from "components/molecules/StatBox"; -import { ZaboType } from 'lib/propTypes'; -import { getLabeledTimeDiff, to2Digits } from 'lib/utils'; +import { ZaboType } from "lib/propTypes"; +import { getLabeledTimeDiff, to2Digits } from "lib/utils"; -import ZaboCardW, { - OverlayW, PosterW, WritingsW, -} from './ZaboCard.styled'; +import ZaboCardW, { OverlayW, PosterW, WritingsW } from "./ZaboCard.styled"; const Poster = ({ zabo }) => { const { - _id, photos, title, owner, createdAt, schedules, views, - likesCount, isLiked, pinsCount, isPinned, + _id, + photos, + title, + owner, + createdAt, + schedules, + views, + likesCount, + isLiked, + pinsCount, + isPinned, } = zabo; const schedule = schedules[0]; - const stats = [{ - type: 'like', - count: likesCount, - zaboId: _id, - active: isLiked, - }, { - type: 'pin', - count: pinsCount, - zaboId: _id, - active: isPinned, - }]; + const stats = [ + { + type: "like", + count: likesCount, + zaboId: _id, + active: isLiked, + }, + { + type: "pin", + count: pinsCount, + zaboId: _id, + active: isPinned, + }, + ]; return ( { - {stats.map (stat => ( + {stats.map((stat) => ( ))} @@ -56,11 +66,20 @@ Poster.propTypes = { const Writing = ({ zabo }) => { const { - _id, photos, title, owner, createdAt, schedules, views, - likesCount, isLiked, pinsCount, isPinned, + _id, + photos, + title, + owner, + createdAt, + schedules, + views, + likesCount, + isLiked, + pinsCount, + isPinned, } = zabo; - const timePast = getLabeledTimeDiff (createdAt, 60, 60, 24, 7, 5, 0); + const timePast = getLabeledTimeDiff(createdAt, 60, 60, 24, 7, 5, 0); return ( @@ -70,10 +89,12 @@ const Writing = ({ zabo }) => {
- {timePast} · {`조회수 ${(views || 0).toLocaleString ()}`} + {timePast} · {`조회수 ${(views || 0).toLocaleString()}`}
- {owner ? owner.name : 'anonymous'} + + {owner ? owner.name : "anonymous"} +
); diff --git a/src/components/organisms/ZaboCard/index.js b/src/components/organisms/ZaboCard/index.js index a9e24739..78ac7450 100644 --- a/src/components/organisms/ZaboCard/index.js +++ b/src/components/organisms/ZaboCard/index.js @@ -1 +1 @@ -export { default } from './ZaboCard'; +export { default } from "./ZaboCard"; diff --git a/src/components/pages/AdminPage/Admin.js b/src/components/pages/AdminPage/Admin.js deleted file mode 100755 index 6322da52..00000000 --- a/src/components/pages/AdminPage/Admin.js +++ /dev/null @@ -1,172 +0,0 @@ -import 'perfect-scrollbar/css/perfect-scrollbar.css'; - -import React, { useEffect } from 'react'; -import { Redirect, Route, Switch } from 'react-router-dom'; -import { useDispatch } from 'react-redux'; -// @material-ui/core components -import { makeStyles } from '@material-ui/core/styles'; -// core components -import DashboardIcon from '@material-ui/icons/Dashboard'; -import GroupIcon from '@material-ui/icons/Group'; -import UserIcon from '@material-ui/icons/Person'; -// creates a beautiful scrollbar -import PerfectScrollbar from 'perfect-scrollbar'; - -import { getGroupApplyList, getGroupList, getUserList } from 'store/reducers/admin'; - -// import routes from 'routes'; -import logo from 'static/logo/logo.svg'; - -import AdminWrapper from './Admin.styled'; -import bgImage from './assets/img/sidebar-2.jpg'; -import styles from './assets/jss/material-dashboard-react/layouts/adminStyle'; -// import FixedPlugin from './components/FixedPlugin/FixedPlugin'; -import Footer from './components/Footer/Footer'; -import Navbar from './components/Navbars/Navbar'; -import Sidebar from './components/Sidebar/Sidebar'; -import Dashboard from './Dashboard'; -import GroupAdminPage from './GroupAdminPage'; -import GroupDetailPage from './GroupDetailPage'; -import UserAdminPage from './UserAdminPage'; -import UserDetailPage from './UserDetailPage'; - -const routes = [ - { - path: '/dashboard', - name: 'Dashboard', - icon: DashboardIcon, - component: Dashboard, - layout: '/admin', - }, - { - path: '/group', - name: 'Group', - icon: GroupIcon, - component: GroupAdminPage, - layout: '/admin', - }, - { - path: '/user', - name: 'User', - icon: UserIcon, - component: UserAdminPage, - layout: '/admin', - }, -]; - -let ps; - -const switchRoutes = ( - - - - {routes.map ((prop, key) => ( - - ))} - - -); - -const useStyles = makeStyles (styles); - -export default function Admin ({ ...rest }) { - // styles - const classes = useStyles (); - // ref to help us initialize PerfectScrollbar on windows devices - const mainPanel = React.createRef (); - // states and functions - const [image, setImage] = React.useState (bgImage); - const [color, setColor] = React.useState ('blue'); - const [fixedClasses, setFixedClasses] = React.useState ('dropdown show'); - const [mobileOpen, setMobileOpen] = React.useState (false); - const handleImageClick = image => { - setImage (image); - }; - const handleColorClick = color => { - setColor (color); - }; - const handleFixedClick = () => { - if (fixedClasses === 'dropdown') { - setFixedClasses ('dropdown show'); - } else { - setFixedClasses ('dropdown'); - } - }; - const handleDrawerToggle = () => { - setMobileOpen (!mobileOpen); - }; - const getRoute = () => window.location.pathname !== '/admin/maps'; - const resizeFunction = () => { - if (window.innerWidth >= 960) { - setMobileOpen (false); - } - }; - // initialize and destroy the PerfectScrollbar plugin - React.useEffect (() => { - if (navigator.platform.indexOf ('Win') > -1) { - ps = new PerfectScrollbar (mainPanel.current, { - suppressScrollX: true, - suppressScrollY: false, - }); - document.body.style.overflow = 'hidden'; - } - window.addEventListener ('resize', resizeFunction); - // Specify how to clean up after this effect: - return function cleanup () { - if (navigator.platform.indexOf ('Win') > -1) { - ps.destroy (); - } - window.removeEventListener ('resize', resizeFunction); - }; - }, [mainPanel]); - - const dispatch = useDispatch (); - useEffect (() => { - dispatch (getGroupApplyList ()); - dispatch (getGroupList ()); - dispatch (getUserList ()); - }, []); - - return ( - - -
- - {/* On the /maps route we want the map to be on full screen - this is not possible if the content and conatiner classes are present because they have some paddings which would make the map smaller */} - {getRoute () ? ( -
-
{switchRoutes}
-
- ) : ( -
{switchRoutes}
- )} - {getRoute () ?
: null} - {/* */} -
-
- ); -} diff --git a/src/components/pages/AdminPage/Admin.styled.js b/src/components/pages/AdminPage/Admin.styled.js deleted file mode 100644 index cb614d69..00000000 --- a/src/components/pages/AdminPage/Admin.styled.js +++ /dev/null @@ -1,510 +0,0 @@ -import styled from 'styled-components'; -/* eslint-disable */ -export default styled.div` - /*! - ========================================================= - * Material Dashboard React - v1.8.0 based on Material Dashboard - v1.2.0 - ========================================================= - - * Product Page: http://www.creative-tim.com/product/material-dashboard-react - * Copyright 2019 Creative Tim (http://www.creative-tim.com) - * Licensed under MIT (https://github.com/creativetimofficial/material-dashboard-react/blob/master/LICENSE.md) - - ========================================================= - - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - - */ - .ct-grid { - stroke: rgba(255, 255, 255, 0.2); - stroke-width: 1px; - stroke-dasharray: 2px; - } - - .ct-series-a .ct-point, - .ct-series-a .ct-line, - .ct-series-a .ct-bar, - .ct-series-a .ct-slice-donut { - stroke: rgba(255, 255, 255, 0.8); - } - - .ct-label.ct-horizontal.ct-end { - align-items: flex-start; - justify-content: flex-start; - text-align: left; - text-anchor: start; - } - - .ct-label { - color: rgba(255, 255, 255, 0.7); - } - - .ct-chart-line .ct-label, - .ct-chart-bar .ct-label { - display: block; - display: -webkit-box; - display: -moz-box; - display: -ms-flexbox; - display: -webkit-flex; - display: flex; - } - - .ct-label { - fill: rgba(0, 0, 0, 0.4); - line-height: 1; - } - html * { - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - } - body { - background-color: #eeeeee; - color: #3c4858; - margin: 0; - font-family: Roboto, Helvetica, Arial, sans-serif; - font-weight: 300; - line-height: 1.5em; - } - - blockquote footer:before, - blockquote small:before { - content: "\\2014 \\00A0"; - } - - small { - font-size: 80%; - } - - h1 { - font-size: 3em; - line-height: 1.15em; - } - - h2 { - font-size: 2.4em; - } - - h3 { - font-size: 1.825em; - line-height: 1.4em; - margin: 20px 0 10px; - } - - h4 { - font-size: 1.3em; - line-height: 1.4em; - } - - h5 { - font-size: 1.25em; - line-height: 1.4em; - margin-bottom: 15px; - } - - h6 { - font-size: 1em; - text-transform: uppercase; - font-weight: 500; - } - - body { - background-color: #eeeeee; - color: #3c4858; - } - - blockquote p { - font-style: italic; - } - - body, - h1, - h2, - h3, - h4, - h5, - h6 { - font-family: "Roboto", "Helvetica", "Arial", sans-serif; - font-weight: 300; - line-height: 1.5em; - } - - a { - color: #9c27b0; - text-decoration: none; - } - - a:hover, - a:focus { - color: #89229b; - text-decoration: none; - } - - legend { - border-bottom: 0; - } - - * { - -webkit-tap-highlight-color: rgba(255, 255, 255, 0); - -webkit-tap-highlight-color: transparent; - } - - *:focus { - outline: 0; - } - - a:focus, - a:active, - button:active, - button:focus, - button:hover, - button::-moz-focus-inner, - input[type="reset"]::-moz-focus-inner, - input[type="button"]::-moz-focus-inner, - input[type="submit"]::-moz-focus-inner, - select::-moz-focus-inner, - input[type="file"] > input[type="button"]::-moz-focus-inner { - outline: 0 !important; - } - - legend { - margin-bottom: 20px; - font-size: 21px; - } - - output { - padding-top: 8px; - font-size: 14px; - line-height: 1.42857; - } - - label { - font-size: 14px; - line-height: 1.42857; - color: #aaaaaa; - font-weight: 400; - } - - footer { - padding: 15px 0; - } - - footer ul { - margin-bottom: 0; - padding: 0; - list-style: none; - } - - footer ul li { - display: inline-block; - } - - footer ul li a { - color: inherit; - padding: 15px; - font-weight: 500; - font-size: 12px; - text-transform: uppercase; - border-radius: 3px; - text-decoration: none; - position: relative; - display: block; - } - - footer ul li a:hover { - text-decoration: none; - } - - @media (max-width: 991px) { - body, - html { - position: relative; - overflow-x: hidden; - } - - #bodyClick { - height: 100%; - width: 100%; - position: fixed; - opacity: 0; - top: 0; - left: auto; - right: 260px; - content: ""; - z-index: 9999; - overflow-x: hidden; - } - } - - .fixed-plugin { - font-family: "Roboto", "Helvetica", "Arial", sans-serif; - font-weight: 300; - line-height: 1.5em; - position: fixed; - top: 180px; - right: 0; - width: 64px; - background: rgba(0, 0, 0, 0.3); - z-index: 1031; - border-radius: 8px 0 0 8px; - text-align: center; - top: 120px; - .badge-primary-background-color: #9c27b0; - } - - .fixed-plugin .SocialMediaShareButton, - .fixed-plugin .github-btn { - display: inline-block; - } - - .fixed-plugin li > a, - .fixed-plugin .badge { - transition: all 0.34s; - -webkit-transition: all 0.34s; - -moz-transition: all 0.34s; - text-decoration: none; - } - - .fixed-plugin .fa-cog { - color: #ffffff; - padding: 10px; - border-radius: 0 0 6px 6px; - width: auto; - } - - .fixed-plugin .dropdown-menu { - right: 80px; - left: auto; - width: 290px; - border-radius: 0.1875rem; - padding: 0 10px; - position: absolute; - color: rgba(0, 0, 0, 0.87); - display: inline-block; - box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.14); - background: #fff; - border-radius: 3px; - } - - .fixed-plugin .fa-circle-thin { - color: #ffffff; - } - - .fixed-plugin .active .fa-circle-thin { - color: #00bbff; - } - - .fixed-plugin .dropdown-menu > .active > a, - .fixed-plugin .dropdown-menu > .active > a:hover, - .fixed-plugin .dropdown-menu > .active > a:focus { - color: #777777; - text-align: center; - } - - .fixed-plugin img { - border-radius: 0; - width: 100%; - height: 100px; - margin: 0 auto; - } - - .fixed-plugin .dropdown-menu li > a:hover, - .fixed-plugin .dropdown-menu li > a:focus { - box-shadow: none; - } - .fixed-plugin .badge { - border: 3px solid #ffffff; - border-radius: 50%; - cursor: pointer; - display: inline-block; - height: 23px; - margin-right: 5px; - position: relative; - width: 23px; - background-color: rgba(30, 30, 30, 0.97); - } - - .fixed-plugin .badge.active, - .fixed-plugin .badge:hover { - border-color: #00bbff; - } - - .fixed-plugin .badge-purple { - background-color: #9c27b0; - } - - .fixed-plugin .badge-blue { - background-color: #00bcd4; - } - - .fixed-plugin .badge-green { - background-color: #4caf50; - } - - .fixed-plugin .badge-orange { - background-color: #ff9800; - } - - .fixed-plugin .badge-red { - background-color: #f44336; - } - - .fixed-plugin h5 { - font-size: 14px; - margin: 10px; - } - .fixed-plugin .dropdown-menu li { - display: block; - padding: 4px 0px; - width: 25%; - float: left; - } - - .fixed-plugin li.adjustments-line, - .fixed-plugin li.header-title, - .fixed-plugin li.button-container { - width: 100%; - height: 50px; - min-height: inherit; - padding: 0px; - text-align: center; - } - - .fixed-plugin li.adjustments-line p { - margin: 0; - } - - .fixed-plugin li.adjustments-line div, - .fixed-plugin li.header-title div, - .fixed-plugin li.button-container div { - margin-bottom: 5px; - } - .fixed-plugin li.header-title { - height: 30px; - line-height: 25px; - font-size: 12px; - font-weight: 600; - text-align: center; - text-transform: uppercase; - } - - .fixed-plugin .adjustments-line p { - float: left; - display: inline-block; - margin-bottom: 0; - font-size: 1em; - color: #3c4858; - } - - .fixed-plugin .adjustments-line a { - color: transparent; - } - - .fixed-plugin .adjustments-line a .badge-colors { - position: relative; - top: -2px; - } - - .fixed-plugin .adjustments-line a a:hover, - .fixed-plugin .adjustments-line a a:focus { - color: transparent; - } - .fixed-plugin .adjustments-line .dropdown-menu > li.adjustments-line > a { - padding-right: 0; - padding-left: 0; - border-bottom: 1px solid #ddd; - border-radius: 0; - margin: 0; - } - - .fixed-plugin .dropdown-menu > li > a.img-holder { - font-size: 16px; - text-align: center; - border-radius: 10px; - background-color: #fff; - border: 3px solid #fff; - padding-left: 0; - padding-right: 0; - opacity: 1; - cursor: pointer; - display: block; - max-height: 100px; - overflow: hidden; - padding: 0; - } - - .fixed-plugin .dropdown-menu > li > a.img-holder img { - margin-top: auto; - } - .fixed-plugin .dropdown-menu > li:hover > a.img-holder, - .fixed-plugin .dropdown-menu > li:focus > a.img-holder { - border-color: rgba(0, 187, 255, 0.53); - } - - .fixed-plugin .dropdown-menu > .active > a.img-holder, - .fixed-plugin .dropdown-menu > .active > a.img-holder { - border-color: #00bbff; - background-color: #ffffff; - } - .fixed-plugin .dropdown .dropdown-menu { - -webkit-transform: translateY(-15%); - -moz-transform: translateY(-15%); - -o-transform: translateY(-15%); - -ms-transform: translateY(-15%); - transform: translateY(-15%); - top: 27px; - opacity: 0; - transform-origin: 0 0; - display: none; - } - - .fixed-plugin .dropdown .dropdown-menu:before { - border-bottom: 0.4em solid transparent; - border-left: 0.4em solid rgba(0, 0, 0, 0.2); - border-top: 0.4em solid transparent; - right: -16px; - top: 46px; - } - .fixed-plugin .dropdown .dropdown-menu:after { - border-bottom: 0.4em solid transparent; - border-left: 0.4em solid #ffffff; - border-top: 0.4em solid transparent; - right: -16px; - } - - .fixed-plugin .dropdown .dropdown-menu:before, - .fixed-plugin .dropdown .dropdown-menu:after { - content: ""; - display: inline-block; - position: absolute; - top: 46px; - width: 16px; - transform: translateY(-50%); - -webkit-transform: translateY(-50%); - -moz-transform: translateY(-50%); - } - - .fixed-plugin .dropdown.show .dropdown-menu { - display: block; - visibility: visible; - opacity: 1; - -webkit-transform: translateY(-13%); - -moz-transform: translateY(-13%); - -o-transform: translateY(-13%); - -ms-transform: translateY(-13%); - transform: translateY(-13%); - transform-origin: 0 0; - } - .fixed-plugin.rtl-fixed-plugin { - right: auto; - left: 0px; - border-radius: 0 8px 8px 0; - } - .fixed-plugin.rtl-fixed-plugin .dropdown-menu { - right: auto; - left: 80px; - } - * { - letter-spacing: normal !important; - } - -`; diff --git a/src/components/pages/AdminPage/Dashboard.js b/src/components/pages/AdminPage/Dashboard.js deleted file mode 100755 index 10223345..00000000 --- a/src/components/pages/AdminPage/Dashboard.js +++ /dev/null @@ -1,641 +0,0 @@ -import './chartist.min.css'; - -import React, { useCallback, useEffect } from 'react'; -// react plugin for creating charts -import ChartistGraph from 'react-chartist'; -import { Bar, Line } from 'react-chartjs-2'; -import { Divider } from '@material-ui/core'; -// @material-ui/core -import { makeStyles } from '@material-ui/core/styles'; -import { - ArrowDownward, ArrowForward, ArrowUpward, OpenInNew, -} from '@material-ui/icons'; -import Accessibility from '@material-ui/icons/Accessibility'; -import AccessTime from '@material-ui/icons/AccessTime'; -import BugReport from '@material-ui/icons/BugReport'; -import Cloud from '@material-ui/icons/Cloud'; -import Code from '@material-ui/icons/Code'; -import DateRange from '@material-ui/icons/DateRange'; -import FileCopy from '@material-ui/icons/FileCopy'; -import Info from '@material-ui/icons/Info'; -import LocalOffer from '@material-ui/icons/LocalOffer'; -// @material-ui/icons -import Store from '@material-ui/icons/Store'; -import Update from '@material-ui/icons/Update'; -import Warning from '@material-ui/icons/Warning'; - -import useSetState from 'hooks/useSetState'; -import axios from 'lib/axios'; - -import styles from './assets/jss/material-dashboard-react/views/dashboardStyle'; -import Card from './components/Card/Card'; -import CardBody from './components/Card/CardBody'; -import CardFooter from './components/Card/CardFooter'; -import CardHeader from './components/Card/CardHeader'; -import CardIcon from './components/Card/CardIcon'; -import CustomTabs from './components/CustomTabs/CustomTabs'; -import GridContainer from './components/Grid/GridContainer'; -// core components -import GridItem from './components/Grid/GridItem'; -import Table from './components/Table/Table'; -import Tasks from './components/Tasks/Tasks'; -import Danger from './components/Typography/Danger'; -import { - completedTasksChart, - dailySalesChart, - emailsSubscriptionChart, -} from './variables/charts'; -import { bugs, server, website } from './variables/general'; - -const useStyles = makeStyles (styles); - -const today = new Date (); -const days = []; -for (let i = 0; i < 7; i++) { - if (i === 6 || today.getDate () === 1) { - days[6 - i] = `${today.getMonth () + 1}/${today.getDate ()}`; - } else { - days[6 - i] = today.getDate (); - } - today.setDate (today.getDate () - 1); -} - -const parseData = data => { - const cnt = [0, 0, 0, 0, 0, 0, 0]; - data.forEach (({ _id, createdAt }) => { - const pos = new Date (); - const temp = new Date (createdAt); - - for (let i = 0; i < 6; i++) { - if (temp.getDate () === pos.getDate () && temp.getMonth () === pos.getMonth () && temp.getFullYear () === pos.getFullYear ()) { - cnt[6 - i] += 1; - break; - } else { - pos.setDate (pos.getDate () - 1); - } - } - }); - return cnt; -}; - -export default function Dashboard () { - const [state, setState] = useSetState ({ - totalZaboCounts: 0, - todayZaboCounts: 0, - totalUserCounts: 0, - todayUserCounts: 0, - zaboChartData: { - data: [], - }, - userChartData: { - data: [], - }, - }); - const { - totalZaboCounts, todayZaboCounts, totalUserCounts, todayUserCounts, zaboChartData, userChartData, - } = state; - - const fetchChartData = useCallback (() => { - Promise.all ([ - axios.get ('/admin/analytics/zabo/date/created'), - axios.get ('/admin/analytics/user/date/created'), - ]) - .then (([zaboList, userList]) => { - const zaboCounts = parseData (zaboList); - const userCounts = parseData (userList); - setState ({ - totalZaboCounts: zaboList.length, - todayZaboCounts: zaboCounts[6], - totalUserCounts: userList.length, - todayUserCounts: userCounts[6], - zaboChartData: { - labels: days, - data: zaboCounts, - }, - userChartData: { - labels: days, - data: userCounts, - }, - }); - }, error => { - console.error (error); - setState ({ - totalZaboCounts: 'NaN', - todayZaboCounts: 'NaN', - totalUserCounts: 'NaN', - todayUserCounts: 'NaN', - zaboChartData: { - labels: [''], - data: [0], - }, - userChartData: { - labels: [''], - data: [0], - }, - }); - }); - }, [state, setState]); - - useEffect (() => { - fetchChartData (); - }, []); - - const classes = useStyles (); - return ( -
-

모아보기

- - - - - - - -

등록된 자보 수

-

- 오늘은 - <> - { - zaboChartData.data[6] > zaboChartData.data[5] - ? ( - - - { todayZaboCounts } - - ) - : zaboChartData.data[6] < zaboChartData.data[5] - ? ( - - - { todayZaboCounts } - - ) - : ( - - - { todayZaboCounts } - - ) - } - - 개, 총 - { - zaboChartData.data[6] > zaboChartData.data[5] - ? ( - - { totalZaboCounts } - - ) - : zaboChartData.data[6] < zaboChartData.data[5] - ? ( - - { totalZaboCounts } - - ) - : ( - - { totalZaboCounts } - - ) - } - 개의 자보가 등록되었습니다. -

-
- -
- 자세히 보기 -
-
-
-
- - - - - - -

회원 수

-

- 오늘은 - <> - { - userChartData.data[6] > userChartData.data[5] - ? ( - - - { todayUserCounts } - - ) - : userChartData.data[6] < userChartData.data[5] - ? ( - - - { todayUserCounts } - - ) - : ( - - - { todayUserCounts } - - ) - } - - 명, 총 - { - userChartData.data[6] > userChartData.data[5] - ? ( - - { totalUserCounts } - - ) - : userChartData.data[6] < userChartData.data[5] - ? ( - - { totalUserCounts } - - ) - : ( - - { totalUserCounts } - - ) - } - 명의 회원이 가입했습니다. -

-
- -
- 자세히 보기 -
-
-
-
- - - - - - -

사용자 수

-

현재 총 - - {totalUserCounts} - - (비회원 - - xx - )명이 자보를 이용중입니다. -

-
- -
- 자세히 보기 -
-
-
-
-
- - - - - - - content_copy - -

Used Space

-

- 49/50 GB -

-
- - - -
-
- - - - - - -

Revenue

-

$34,245

-
- -
- - Last 24 Hours -
-
-
-
- - - - - info_outline - -

Fixed Issues

-

75

-
- -
- - Tracked from Github -
-
-
-
- - - - - - -

Followers

-

+245

-
- -
- - Just Updated -
-
-
-
-
- - - - - - - -

Daily Sales

-

- - 55% - {' '} - increase in today sales. -

-
- -
- updated 4 minutes ago -
-
-
-
- - - - - - -

Email Subscriptions

-

Last Campaign Performance

-
- -
- campaign sent 2 days ago -
-
-
-
- - - - - - -

Completed Tasks

-

Last Campaign Performance

-
- -
- campaign sent 2 days ago -
-
-
-
-
- - - - ), - }, - { - tabName: 'Website', - tabIcon: Code, - tabContent: ( - - ), - }, - { - tabName: 'Server', - tabIcon: Cloud, - tabContent: ( - - ), - }, - ]} - /> - - - - -

Employees Stats

-

- New employees on 15th September, 2016 -

-
- - - - - - - - ); -} diff --git a/src/components/pages/AdminPage/GroupAdminPage.js b/src/components/pages/AdminPage/GroupAdminPage.js deleted file mode 100644 index 7cec0a66..00000000 --- a/src/components/pages/AdminPage/GroupAdminPage.js +++ /dev/null @@ -1,169 +0,0 @@ -import React, { - useCallback, useMemo, useState, -} from 'react'; -import { Link } from 'react-router-dom'; -import { useDispatch, useSelector } from 'react-redux'; -import { makeStyles } from '@material-ui/core'; -import Avatar from '@material-ui/core/Avatar'; -import Card from '@material-ui/core/Card'; -import CardActions from '@material-ui/core/CardActions'; -import CardContent from '@material-ui/core/CardContent'; -import CardHeader from '@material-ui/core/CardHeader'; -import CardMedia from '@material-ui/core/CardMedia'; -import Collapse from '@material-ui/core/Collapse'; -import { red } from '@material-ui/core/colors'; -import IconButton from '@material-ui/core/IconButton'; -import Typography from '@material-ui/core/Typography'; -import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; -import MoreVertIcon from '@material-ui/icons/MoreVert'; -import clsx from 'clsx'; -import get from 'lodash.get'; -import moment from 'moment'; - -import StyledQuill from 'organisms/StyledQuill'; - -import { acceptApplyGroup } from 'store/reducers/admin'; - -import defaultProfile from 'static/images/defaultProfile.png'; -import groupDefaultProfile from 'static/images/groupDefaultProfile.png'; - -import GridContainer from './components/Grid/GridContainer'; -import GridItem from './components/Grid/GridItem'; - -const useStyles = makeStyles (theme => ({ - root: { - maxWidth: 600, - margin: theme.spacing (2), - }, - media: { - height: 0, - // paddingTop: '56.25%', // 16:9 - paddingTop: '100%', // 16:9 - }, - expand: { - transform: 'rotate(0deg)', - marginLeft: 'auto', - transition: theme.transitions.create ('transform', { - duration: theme.transitions.duration.shortest, - }), - }, - expandOpen: { - transform: 'rotate(180deg)', - }, - avatar: { - backgroundColor: red[500], - }, -})); - -const GroupItem = ({ group, isPending }) => { - const classes = useStyles (); - const [expanded, setExpanded] = useState (false); - const handleExpandClick = () => { - setExpanded (!expanded); - }; - - const { - name, profilePhoto, createdAt, purpose, subtitle, description, members, category, - } = group; - const owner = (members[0] || {}).user || {}; - const { username, profilePhoto: userProfilePhoto, ...others } = owner; - - const dispatch = useDispatch (); - const accept = useCallback (() => { - dispatch (acceptApplyGroup ({ name })); - }, [name]); - - return ( - - - - } - action={( - - - - )} - title={username} - subheader={moment (createdAt).format ('YYYY-MM-DD HH:mm:ss')} - /> - - - - - - {name} - - - {subtitle} - - - - {isPending && ( -
- 승인하기 -
- )} - - - -
- - - - {JSON.stringify (category)} - - - - - {isPending && ( -
-

Purpose: {purpose}

-
- )} -
-
-
-
- ); -}; - -const GroupAdminPage = () => { - const pendingGroups = useSelector (state => get (state, ['admin', 'pendingGroups'], [])); - const groups = useSelector (state => get (state, ['admin', 'groups'], [])); - - return ( -
-

Pending Groups

- - {pendingGroups.map (group => ( - - ))} - -

Groups

- - {groups.map (group => ( - - ))} - -
- ); -}; - -export default GroupAdminPage; diff --git a/src/components/pages/AdminPage/GroupDetailPage.js b/src/components/pages/AdminPage/GroupDetailPage.js deleted file mode 100644 index 2ff56d31..00000000 --- a/src/components/pages/AdminPage/GroupDetailPage.js +++ /dev/null @@ -1,60 +0,0 @@ -import React, { useMemo } from 'react'; -import { useSelector } from 'react-redux'; -import get from 'lodash.get'; - -import SuperTooltip from 'atoms/SuperTooltip'; -import StyledQuill from 'organisms/StyledQuill'; -import { Page } from 'pages/ProfilePage/Profile.styled'; - -import groupDefaultProfile from 'static/images/groupDefaultProfile.png'; - -import GridContainer from './components/Grid/GridContainer'; -import UserCard from './UserCard'; - -const GroupDetailPage = ({ match }) => { - const { name } = match.params; - const group = useSelector (state => get (state, ['admin', 'groupsMap', name])); - if (!group) return null; - const { - profilePhoto, members, recentUpload, description, subtitle, - } = group; - - return ( -
- - - - { - profilePhoto - ? profile photo - : default profile img - } - - -

{name}

- -

{subtitle || '아직 소개가 없습니다.'}

-
-
-
-
- - - - -

Members

- - {members.map (member => ( - - ))} - -
-
- ); -}; - -export default GroupDetailPage; diff --git a/src/components/pages/AdminPage/UserAdminPage.js b/src/components/pages/AdminPage/UserAdminPage.js deleted file mode 100644 index f4fd78eb..00000000 --- a/src/components/pages/AdminPage/UserAdminPage.js +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react'; -import { useSelector } from 'react-redux'; -import get from 'lodash.get'; - -import GridContainer from './components/Grid/GridContainer'; -import UserList from './UsersTable'; - -const UserAdminPage = () => { - const users = useSelector (state => get (state, ['admin', 'users'], [])); - return ( -
- - {!!users.length && } - -
- ); -}; - -export default UserAdminPage; diff --git a/src/components/pages/AdminPage/UserCard.js b/src/components/pages/AdminPage/UserCard.js deleted file mode 100644 index 41dac131..00000000 --- a/src/components/pages/AdminPage/UserCard.js +++ /dev/null @@ -1,110 +0,0 @@ -import React, { useState } from 'react'; -import { Link } from 'react-router-dom'; -import { makeStyles } from '@material-ui/core'; -import Button from '@material-ui/core/Button'; -import Card from '@material-ui/core/Card'; -import CardActionArea from '@material-ui/core/CardActionArea'; -import CardActions from '@material-ui/core/CardActions'; -import CardContent from '@material-ui/core/CardContent'; -import CardMedia from '@material-ui/core/CardMedia'; -import Collapse from '@material-ui/core/Collapse'; -import IconButton from '@material-ui/core/IconButton'; -import Typography from '@material-ui/core/Typography'; -import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; -import clsx from 'clsx'; - -import StyledQuill from 'organisms/StyledQuill'; - -import defaultProfile from 'static/images/defaultProfile.png'; - -import { UserType } from '../../../lib/propTypes'; -import GridItem from './components/Grid/GridItem'; -import UserInfo from './UserInfo'; - -const useStyles = makeStyles (theme => ({ - root: { - maxWidth: 600, - margin: theme.spacing (2), - }, - media: { - paddingTop: '100%', - // minHeight: 300, - }, - expand: { - transform: 'rotate(0deg)', - marginLeft: 'auto', - transition: theme.transitions.create ('transform', { - duration: theme.transitions.duration.shortest, - }), - }, - expandOpen: { - transform: 'rotate(180deg)', - }, -})); - -const UserCard = ({ user }) => { - const classes = useStyles (); - const [expanded, setExpanded] = useState (false); - const handleExpandClick = () => { - setExpanded (!expanded); - }; - - const { - _id, profilePhoto, username, createdAt, - birthday, email, name, kaistEmail, kaistPersonType, kaistStatus, koreanName, - flags, description, kaistId, facebookId, tweeterId, - } = user; - - return ( - - - - - - - - - {username} - {name || ''} - - - - - - - - - - - - - - - - - - - ); -}; - -UserCard.propTypes = { - user: UserType.isRequired, -}; - -export default UserCard; diff --git a/src/components/pages/AdminPage/UserDetailPage.js b/src/components/pages/AdminPage/UserDetailPage.js deleted file mode 100644 index 6d95863a..00000000 --- a/src/components/pages/AdminPage/UserDetailPage.js +++ /dev/null @@ -1,52 +0,0 @@ -import React, { useMemo } from 'react'; -import { useSelector } from 'react-redux'; -import get from 'lodash.get'; - -import SuperTooltip from 'atoms/SuperTooltip'; -import Header from 'templates/Header'; -import { Page } from 'pages/ProfilePage/Profile.styled'; - -import defaultProfile from 'static/images/defaultProfile.png'; - -import UserInfo from './UserInfo'; - -const UserDetailPage = ({ match }) => { - const { username } = match.params; - const user = useSelector (state => get (state, ['admin', 'usersMap', username])); - if (!user) return null; - const { - _id, profilePhoto, createdAt, groups, - birthday, email, name, kaistEmail, kaistPersonType, kaistStatus, koreanName, - flags, description, - } = user; - - return ( -
-
- - - - { - profilePhoto - ? profile photo - : default profile img - } - - -

{username}

- -

{description || '아직 소개가 없습니다.'}

-
-
-
-
- - - - - -
- ); -}; - -export default UserDetailPage; diff --git a/src/components/pages/AdminPage/UserInfo.js b/src/components/pages/AdminPage/UserInfo.js deleted file mode 100644 index 73c163fb..00000000 --- a/src/components/pages/AdminPage/UserInfo.js +++ /dev/null @@ -1,282 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { Link } from 'react-router-dom'; -import { Doughnut } from 'react-chartjs-2'; -import { makeStyles } from '@material-ui/core'; -import Button from '@material-ui/core/Button'; -import Card from '@material-ui/core/Card'; -import CardActionArea from '@material-ui/core/CardActionArea'; -import CardActions from '@material-ui/core/CardActions'; -import CardContent from '@material-ui/core/CardContent'; -import CardMedia from '@material-ui/core/CardMedia'; -import Chip from '@material-ui/core/Chip'; -import Typography from '@material-ui/core/Typography'; - -import { UserType } from 'lib/propTypes'; - -import defaultProfile from '../../../static/images/defaultProfile.png'; -import StyledQuill from '../../organisms/StyledQuill'; - -const useProfileStyles = makeStyles (theme => ({ - root: { - maxWidth: 600, - margin: theme.spacing (2), - }, - media: { - paddingTop: '100%', - }, -})); - -export const UserProfileCard = ({ user }) => { - const classes = useProfileStyles (); - const { - _id, profilePhoto, username, createdAt, - birthday, email, name, kaistEmail, kaistPersonType, kaistStatus, koreanName, - flags, description, kaistId, facebookId, tweeterId, - } = user; - return ( - - - - - - - - {username} - {name || ''} - - - - - - - - ); -}; - -UserProfileCard.propTypes = { - user: UserType.isRequired, -}; - -const STATUS_LIST = ['재학', '졸업예장', '입학전']; -const PERSON_TYPE_LIST = ['Student']; -const FLAG_LIST = ['TEST', 'SPARCS']; -const SSO_LIST = ['KAIST', 'Facebook', 'Tweeter', 'Email']; - -const useChipStyle = makeStyles (theme => ({ - root: { - margin: theme.spacing (2), - }, - chip: { - margin: theme.spacing (0.5), - }, -})); - -const Chips = ({ label, status, list }) => { - const classes = useChipStyle (); - return ( -
- - {label} - -
- { - list.map (type => ( - x === type) ? 'primary' : ''} - /> - )) - } - { - list.some (type => status.some (x => x === type)) - || status.map (stat => ) - } -
-
- ); -}; - -Chips.propTypes = { - label: PropTypes.string, - /* eslint react/forbid-prop-types:0 */ - status: PropTypes.array, - list: PropTypes.array, -}; - -export const UserChips = ({ user }) => { - const { - email, kaistPersonType, kaistStatus, - flags, kaistId, facebookId, tweeterId, - } = user; - - const ssoList = []; - if (kaistId) ssoList.push ('KAIST'); - if (facebookId) ssoList.push ('Facebook'); - if (tweeterId) ssoList.push ('Twitter'); - if (email.split ('@')[1] !== 'sso.sparcs.org') ssoList.push ('Email'); - - return ( - <> - - - - - - ); -}; - -UserChips.propTypes = { - user: UserType.isRequired, -}; - -const UserOtherInfo = ({ user }) => { - const { - _id, createdAt, birthday, email, kaistEmail, - gender, facebookId, firstName, lastName, studentId, - currentGroup, kaistInfoTime, kaistId, groups, followings, - } = user; - // TODO: recommends - - const others = [{ - label: 'ID', - value: _id, - }, { - label: 'Facebook ID', - value: facebookId, - }, { - label: 'KAIST ID', - value: kaistId, - }, { - label: 'KAIST Email', - value: kaistEmail, - }, { - label: 'Email', - value: email, - }, { - label: 'Student ID', - value: studentId, - }, { - label: 'Gender', - value: gender, - }, { - label: 'English Name', - value: `${firstName} ${lastName}`, - }, { - label: 'Current Group', - value: currentGroup ? currentGroup.name : null, - }, { - label: 'KAIST Info Time', - value: kaistInfoTime, - }, { - label: 'Groups', - value: groups.map (group => {group.name}), - }, { - label: 'Followings', - value: followings.map (({ followee, onModel }) => ( - onModel === 'Group' - ? {followee.name} - : {followee.username} - )), - }, { - label: 'Birthday', - value: birthday, - }, { - label: 'createdAt', - value: createdAt, - }]; - - return ( - <> - { - others.map (({ label, value }) => ( - - - {label} - -
- { - Array.isArray (value) - ? value.map (val => ( - - )) - : ( - value ? ( - - ) :
none
- ) - } -
-
- )) - } - - ); -}; - -UserOtherInfo.propTypes = { - user: UserType.isRequired, -}; - -const interestColors = { - 과학생회: '#FF6384', - 자치단체: '#36A2EB', - 총학생회: '#FFCE56', - 생활문화: '#00A5E3', - 예술: '#8DD7BF', - 음악: '#FF96C5', - 종교사회: '#FF5768', - 체육: '#FFBF65', - 학술: '#FC6238', - 창업: '#FFD872', - 관리자: '#E7C582', -}; - -const UserInterests = ({ user }) => { - const { interests } = user; - const cats = Object.keys (interests); - const data = { - labels: cats, - datasets: [{ - data: cats.map (cat => interests[cat]), - backgroundColor: cats.map (cat => interestColors[cat]), - hoverBackgroundColor: cats.map (cat => interestColors[cat]), - }], - }; - - return ( - - ); -}; - -UserInterests.propTypes = { - user: UserType.isRequired, -}; - -const UserInfo = ({ user }) => ( - <> - - - - - -); - -UserInfo.propTypes = { - user: UserType.isRequired, -}; - -export default UserInfo; diff --git a/src/components/pages/AdminPage/UsersTable.js b/src/components/pages/AdminPage/UsersTable.js deleted file mode 100644 index d478f25b..00000000 --- a/src/components/pages/AdminPage/UsersTable.js +++ /dev/null @@ -1,81 +0,0 @@ -import React, { useState } from 'react'; -import { Link } from 'react-router-dom'; -import Divider from '@material-ui/core/Divider'; -import List from '@material-ui/core/List'; -import ListItem from '@material-ui/core/ListItem'; -import ListItemText from '@material-ui/core/ListItemText'; -import MaterialTable from 'material-table'; -import moment from 'moment'; - -import defaultProfile from 'static/images/defaultProfile.png'; - -import tableIcons from './tableIcons'; -import UserInfo from './UserInfo'; - -export default function UserList ({ users }) { - const [state, setState] = useState ({ - columns: [ - { title: 'Name', field: 'name' }, - { - field: 'profilePhoto', - title: 'Photo', - render: rowData => , - }, - { - title: 'Username', - field: 'username', - render: ({ username }) => {username}, - }, - { title: 'Birthday', field: 'birthday', type: 'date' }, - { title: 'Email', field: 'kaistEmail' }, - { - title: 'Type', - field: 'kaistPersonType', - render: rowData => ( - - - - - - {rowData.kaistPersonType === 'Student' - && ( - - - - )} - - ), - }, - { - title: '등록일', - field: 'createdAt', - render: rowData => ( - moment (rowData.createdAt).format ('YYYY-MM-DD HH:mm:ss') - ), - }, - ], - data: users, - }); - return ( - ( -
- -
- )} - icons={tableIcons} - /> - ); -} diff --git a/src/components/pages/AdminPage/assets/css/material-dashboard-react.css b/src/components/pages/AdminPage/assets/css/material-dashboard-react.css deleted file mode 100755 index c5e7500f..00000000 --- a/src/components/pages/AdminPage/assets/css/material-dashboard-react.css +++ /dev/null @@ -1,512 +0,0 @@ -/*! - - ========================================================= - * Material Dashboard React - v1.8.0 based on Material Dashboard - v1.2.0 - ========================================================= - - * Product Page: http://www.creative-tim.com/product/material-dashboard-react - * Copyright 2019 Creative Tim (http://www.creative-tim.com) - * Licensed under MIT (https://github.com/creativetimofficial/material-dashboard-react/blob/master/LICENSE.md) - - ========================================================= - - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - - */ -.ct-grid { - stroke: rgba(255, 255, 255, 0.2); - stroke-width: 1px; - stroke-dasharray: 2px; -} - -.ct-series-a .ct-point, -.ct-series-a .ct-line, -.ct-series-a .ct-bar, -.ct-series-a .ct-slice-donut { - stroke: rgba(255, 255, 255, 0.8); -} - -.ct-label.ct-horizontal.ct-end { - -webkit-box-align: flex-start; - -webkit-align-items: flex-start; - -ms-flex-align: flex-start; - align-items: flex-start; - -webkit-box-pack: flex-start; - -webkit-justify-content: flex-start; - -ms-flex-pack: flex-start; - justify-content: flex-start; - text-align: left; - text-anchor: start; -} - -.ct-label { - color: rgba(255, 255, 255, 0.7); -} - -.ct-chart-line .ct-label, -.ct-chart-bar .ct-label { - display: block; - display: -webkit-box; - display: -moz-box; - display: -ms-flexbox; - display: -webkit-flex; - display: flex; -} - -.ct-label { - fill: rgba(0, 0, 0, 0.4); - line-height: 1; -} -html * { - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} -body { - background-color: #eeeeee; - color: #3c4858; - margin: 0; - font-family: Roboto, Helvetica, Arial, sans-serif; - font-weight: 300; - line-height: 1.5em; -} - -blockquote footer:before, -blockquote small:before { - content: "\2014 \00A0"; -} - -small { - font-size: 80%; -} - -h1 { - font-size: 3em; - line-height: 1.15em; -} - -h2 { - font-size: 2.4em; -} - -h3 { - font-size: 1.825em; - line-height: 1.4em; - margin: 20px 0 10px; -} - -h4 { - font-size: 1.3em; - line-height: 1.4em; -} - -h5 { - font-size: 1.25em; - line-height: 1.4em; - margin-bottom: 15px; -} - -h6 { - font-size: 1em; - text-transform: uppercase; - font-weight: 500; -} - -body { - background-color: #eeeeee; - color: #3c4858; -} - -blockquote p { - font-style: italic; -} - -body, -h1, -h2, -h3, -h4, -h5, -h6 { - font-family: "Roboto", "Helvetica", "Arial", sans-serif; - font-weight: 300; - line-height: 1.5em; -} - -a { - color: #9c27b0; - text-decoration: none; -} - -a:hover, -a:focus { - color: #89229b; - text-decoration: none; -} - -legend { - border-bottom: 0; -} - -* { - -webkit-tap-highlight-color: rgba(255, 255, 255, 0); - -webkit-tap-highlight-color: transparent; -} - -*:focus { - outline: 0; -} - -a:focus, -a:active, -button:active, -button:focus, -button:hover, -button::-moz-focus-inner, -input[type="reset"]::-moz-focus-inner, -input[type="button"]::-moz-focus-inner, -input[type="submit"]::-moz-focus-inner, -select::-moz-focus-inner, -input[type="file"] > input[type="button"]::-moz-focus-inner { - outline: 0 !important; -} - -legend { - margin-bottom: 20px; - font-size: 21px; -} - -output { - padding-top: 8px; - font-size: 14px; - line-height: 1.42857; -} - -label { - font-size: 14px; - line-height: 1.42857; - color: #aaaaaa; - font-weight: 400; -} - -footer { - padding: 15px 0; -} - -footer ul { - margin-bottom: 0; - padding: 0; - list-style: none; -} - -footer ul li { - display: inline-block; -} - -footer ul li a { - color: inherit; - padding: 15px; - font-weight: 500; - font-size: 12px; - text-transform: uppercase; - border-radius: 3px; - text-decoration: none; - position: relative; - display: block; -} - -footer ul li a:hover { - text-decoration: none; -} - -@media (max-width: 991px) { - body, - html { - position: relative; - overflow-x: hidden; - } - - #bodyClick { - height: 100%; - width: 100%; - position: fixed; - opacity: 0; - top: 0; - left: auto; - right: 260px; - content: ""; - z-index: 9999; - overflow-x: hidden; - } -} - -.fixed-plugin { - font-family: "Roboto", "Helvetica", "Arial", sans-serif; - font-weight: 300; - line-height: 1.5em; - position: fixed; - top: 180px; - right: 0; - width: 64px; - background: rgba(0, 0, 0, 0.3); - z-index: 1031; - border-radius: 8px 0 0 8px; - text-align: center; - top: 120px; -.badge-primary-background-color: #9c27b0; -} - -.fixed-plugin .SocialMediaShareButton, -.fixed-plugin .github-btn { - display: inline-block; -} - -.fixed-plugin li > a, -.fixed-plugin .badge { - transition: all 0.34s; - -webkit-transition: all 0.34s; - -moz-transition: all 0.34s; - text-decoration: none; -} - -.fixed-plugin .fa-cog { - color: #ffffff; - padding: 10px; - border-radius: 0 0 6px 6px; - width: auto; -} - -.fixed-plugin .dropdown-menu { - right: 80px; - left: auto; - width: 290px; - border-radius: 0.1875rem; - padding: 0 10px; - position: absolute; - color: rgba(0, 0, 0, 0.87); - display: inline-block; - box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.14); - background: #fff; - border-radius: 3px; -} - -.fixed-plugin .fa-circle-thin { - color: #ffffff; -} - -.fixed-plugin .active .fa-circle-thin { - color: #00bbff; -} - -.fixed-plugin .dropdown-menu > .active > a, -.fixed-plugin .dropdown-menu > .active > a:hover, -.fixed-plugin .dropdown-menu > .active > a:focus { - color: #777777; - text-align: center; -} - -.fixed-plugin img { - border-radius: 0; - width: 100%; - height: 100px; - margin: 0 auto; -} - -.fixed-plugin .dropdown-menu li > a:hover, -.fixed-plugin .dropdown-menu li > a:focus { - box-shadow: none; -} -.fixed-plugin .badge { - border: 3px solid #ffffff; - border-radius: 50%; - cursor: pointer; - display: inline-block; - height: 23px; - margin-right: 5px; - position: relative; - width: 23px; - background-color: rgba(30, 30, 30, 0.97); -} - -.fixed-plugin .badge.active, -.fixed-plugin .badge:hover { - border-color: #00bbff; -} - -.fixed-plugin .badge-purple { - background-color: #9c27b0; -} - -.fixed-plugin .badge-blue { - background-color: #00bcd4; -} - -.fixed-plugin .badge-green { - background-color: #4caf50; -} - -.fixed-plugin .badge-orange { - background-color: #ff9800; -} - -.fixed-plugin .badge-red { - background-color: #f44336; -} - -.fixed-plugin h5 { - font-size: 14px; - margin: 10px; -} -.fixed-plugin .dropdown-menu li { - display: block; - padding: 4px 0px; - width: 25%; - float: left; -} - -.fixed-plugin li.adjustments-line, -.fixed-plugin li.header-title, -.fixed-plugin li.button-container { - width: 100%; - height: 50px; - min-height: inherit; - padding: 0px; - text-align: center; -} - -.fixed-plugin li.adjustments-line p { - margin: 0; -} - -.fixed-plugin li.adjustments-line div, -.fixed-plugin li.header-title div, -.fixed-plugin li.button-container div { - margin-bottom: 5px; -} -.fixed-plugin li.header-title { - height: 30px; - line-height: 25px; - font-size: 12px; - font-weight: 600; - text-align: center; - text-transform: uppercase; -} - -.fixed-plugin .adjustments-line p { - float: left; - display: inline-block; - margin-bottom: 0; - font-size: 1em; - color: #3c4858; -} - -.fixed-plugin .adjustments-line a { - color: transparent; -} - -.fixed-plugin .adjustments-line a .badge-colors { - position: relative; - top: -2px; -} - -.fixed-plugin .adjustments-line a a:hover, -.fixed-plugin .adjustments-line a a:focus { - color: transparent; -} -.fixed-plugin .adjustments-line .dropdown-menu > li.adjustments-line > a { - padding-right: 0; - padding-left: 0; - border-bottom: 1px solid #ddd; - border-radius: 0; - margin: 0; -} - -.fixed-plugin .dropdown-menu > li > a.img-holder { - font-size: 16px; - text-align: center; - border-radius: 10px; - background-color: #fff; - border: 3px solid #fff; - padding-left: 0; - padding-right: 0; - opacity: 1; - cursor: pointer; - display: block; - max-height: 100px; - overflow: hidden; - padding: 0; -} - -.fixed-plugin .dropdown-menu > li > a.img-holder img { - margin-top: auto; -} -.fixed-plugin .dropdown-menu > li:hover > a.img-holder, -.fixed-plugin .dropdown-menu > li:focus > a.img-holder { - border-color: rgba(0, 187, 255, 0.53); -} - -.fixed-plugin .dropdown-menu > .active > a.img-holder, -.fixed-plugin .dropdown-menu > .active > a.img-holder { - border-color: #00bbff; - background-color: #ffffff; -} -.fixed-plugin .dropdown .dropdown-menu { - -webkit-transform: translateY(-15%); - -moz-transform: translateY(-15%); - -o-transform: translateY(-15%); - -ms-transform: translateY(-15%); - transform: translateY(-15%); - top: 27px; - opacity: 0; - transform-origin: 0 0; - display: none; -} - -.fixed-plugin .dropdown .dropdown-menu:before { - border-bottom: 0.4em solid transparent; - border-left: 0.4em solid rgba(0, 0, 0, 0.2); - border-top: 0.4em solid transparent; - right: -16px; - top: 46px; -} -.fixed-plugin .dropdown .dropdown-menu:after { - border-bottom: 0.4em solid transparent; - border-left: 0.4em solid #ffffff; - border-top: 0.4em solid transparent; - right: -16px; -} - -.fixed-plugin .dropdown .dropdown-menu:before, -.fixed-plugin .dropdown .dropdown-menu:after { - content: ""; - display: inline-block; - position: absolute; - top: 46px; - width: 16px; - transform: translateY(-50%); - -webkit-transform: translateY(-50%); - -moz-transform: translateY(-50%); -} - -.fixed-plugin .dropdown.show .dropdown-menu { - display: block; - visibility: visible; - opacity: 1; - -webkit-transform: translateY(-13%); - -moz-transform: translateY(-13%); - -o-transform: translateY(-13%); - -ms-transform: translateY(-13%); - transform: translateY(-13%); - transform-origin: 0 0; -} -.fixed-plugin.rtl-fixed-plugin { - right: auto; - left: 0px; - border-radius: 0 8px 8px 0; -} -.fixed-plugin.rtl-fixed-plugin .dropdown-menu { - right: auto; - left: 80px; -} -* { - letter-spacing: normal !important; -} diff --git a/src/components/pages/AdminPage/assets/img/Projects-SSO.svg b/src/components/pages/AdminPage/assets/img/Projects-SSO.svg deleted file mode 100644 index 5850a01d..00000000 --- a/src/components/pages/AdminPage/assets/img/Projects-SSO.svg +++ /dev/null @@ -1,13 +0,0 @@ - - Projects-SSO - - - - - - - - diff --git a/src/components/pages/AdminPage/assets/img/Services-Zabo.svg b/src/components/pages/AdminPage/assets/img/Services-Zabo.svg deleted file mode 100644 index 7a6702e4..00000000 --- a/src/components/pages/AdminPage/assets/img/Services-Zabo.svg +++ /dev/null @@ -1,14 +0,0 @@ - - Services-Zabo - - - - - - - - - diff --git a/src/components/pages/AdminPage/assets/img/apple-icon.png b/src/components/pages/AdminPage/assets/img/apple-icon.png deleted file mode 100755 index d5c10d67..00000000 Binary files a/src/components/pages/AdminPage/assets/img/apple-icon.png and /dev/null differ diff --git a/src/components/pages/AdminPage/assets/img/cover.jpeg b/src/components/pages/AdminPage/assets/img/cover.jpeg deleted file mode 100755 index c70fee79..00000000 Binary files a/src/components/pages/AdminPage/assets/img/cover.jpeg and /dev/null differ diff --git a/src/components/pages/AdminPage/assets/img/faces/member_1.png b/src/components/pages/AdminPage/assets/img/faces/member_1.png deleted file mode 100644 index 50fe0bf4..00000000 Binary files a/src/components/pages/AdminPage/assets/img/faces/member_1.png and /dev/null differ diff --git a/src/components/pages/AdminPage/assets/img/faces/member_2.png b/src/components/pages/AdminPage/assets/img/faces/member_2.png deleted file mode 100644 index baaf8872..00000000 Binary files a/src/components/pages/AdminPage/assets/img/faces/member_2.png and /dev/null differ diff --git a/src/components/pages/AdminPage/assets/img/favicon.png b/src/components/pages/AdminPage/assets/img/favicon.png deleted file mode 100755 index a95e8c30..00000000 Binary files a/src/components/pages/AdminPage/assets/img/favicon.png and /dev/null differ diff --git a/src/components/pages/AdminPage/assets/img/mask.png b/src/components/pages/AdminPage/assets/img/mask.png deleted file mode 100755 index dc695721..00000000 Binary files a/src/components/pages/AdminPage/assets/img/mask.png and /dev/null differ diff --git a/src/components/pages/AdminPage/assets/img/new_logo.png b/src/components/pages/AdminPage/assets/img/new_logo.png deleted file mode 100755 index 4b248c1b..00000000 Binary files a/src/components/pages/AdminPage/assets/img/new_logo.png and /dev/null differ diff --git a/src/components/pages/AdminPage/assets/img/reactlogo.png b/src/components/pages/AdminPage/assets/img/reactlogo.png deleted file mode 100755 index 40672ae8..00000000 Binary files a/src/components/pages/AdminPage/assets/img/reactlogo.png and /dev/null differ diff --git a/src/components/pages/AdminPage/assets/img/sidebar-1.jpg b/src/components/pages/AdminPage/assets/img/sidebar-1.jpg deleted file mode 100755 index d60429be..00000000 Binary files a/src/components/pages/AdminPage/assets/img/sidebar-1.jpg and /dev/null differ diff --git a/src/components/pages/AdminPage/assets/img/sidebar-2.jpg b/src/components/pages/AdminPage/assets/img/sidebar-2.jpg deleted file mode 100755 index 14e29f3a..00000000 Binary files a/src/components/pages/AdminPage/assets/img/sidebar-2.jpg and /dev/null differ diff --git a/src/components/pages/AdminPage/assets/img/sidebar-3.jpg b/src/components/pages/AdminPage/assets/img/sidebar-3.jpg deleted file mode 100755 index c9dfa637..00000000 Binary files a/src/components/pages/AdminPage/assets/img/sidebar-3.jpg and /dev/null differ diff --git a/src/components/pages/AdminPage/assets/img/sidebar-4.jpg b/src/components/pages/AdminPage/assets/img/sidebar-4.jpg deleted file mode 100755 index 06c46ed9..00000000 Binary files a/src/components/pages/AdminPage/assets/img/sidebar-4.jpg and /dev/null differ diff --git a/src/components/pages/AdminPage/assets/img/tim_80x80.png b/src/components/pages/AdminPage/assets/img/tim_80x80.png deleted file mode 100755 index 5f2bb549..00000000 Binary files a/src/components/pages/AdminPage/assets/img/tim_80x80.png and /dev/null differ diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react.js deleted file mode 100755 index 05d0c8e7..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react.js +++ /dev/null @@ -1,303 +0,0 @@ -/*! - - ========================================================= - * Material Dashboard React - v1.8.0 based on Material Dashboard - v1.2.0 - ========================================================= - - * Product Page: http://www.creative-tim.com/product/material-dashboard-react - * Copyright 2019 Creative Tim (http://www.creative-tim.com) - * Licensed under MIT (https://github.com/creativetimofficial/material-dashboard-react/blob/master/LICENSE.md) - - ========================================================= - - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - - */ - -// ############################## -// // // Function that converts from hex color to rgb color -// // // Example: input = #9c27b0 => output = 156, 39, 176 -// // // Example: input = 9c27b0 => output = 156, 39, 176 -// // // Example: input = #999 => output = 153, 153, 153 -// // // Example: input = 999 => output = 153, 153, 153 -// ############################# -const hexToRgb = input => { - let clone = input; - clone += ''; - clone = clone.replace ('#', ''); - const hexRegex = /[0-9A-Fa-f]/g; - if (!hexRegex.test (clone) || (clone.length !== 3 && clone.length !== 6)) { - throw new Error ('input is not a valid hex color.'); - } - if (clone.length === 3) { - const first = clone[0]; - const second = clone[1]; - const last = clone[2]; - clone = first + first + second + second + last + last; - } - clone = clone.toUpperCase (clone); - const first = clone[0] + clone[1]; - const second = clone[2] + clone[3]; - const last = clone[4] + clone[5]; - return ( - `${parseInt (first, 16) - }, ${ - parseInt (second, 16) - }, ${ - parseInt (last, 16)}` - ); -}; - -// ############################## -// // // Variables - Styles that are used on more than one component -// ############################# - -const drawerWidth = 260; - -const transition = { - transition: 'all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1)', -}; - -const container = { - paddingRight: '15px', - paddingLeft: '15px', - marginRight: 'auto', - marginLeft: 'auto', -}; - -const defaultFont = { - fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif', - fontWeight: '300', - lineHeight: '1.5em', -}; - -const primaryColor = ['#9c27b0', '#ab47bc', '#8e24aa', '#af2cc5']; -const warningColor = ['#ff9800', '#ffa726', '#fb8c00', '#ffa21a']; -const dangerColor = ['#f44336', '#ef5350', '#e53935', '#f55a4e']; -const successColor = ['#4caf50', '#66bb6a', '#43a047', '#5cb860']; -const infoColor = ['#00acc1', '#26c6da', '#00acc1', '#00d3ee']; -const roseColor = ['#e91e63', '#ec407a', '#d81b60', '#eb3573']; -const grayColor = [ - '#999', - '#777', - '#3C4858', - '#AAAAAA', - '#D2D2D2', - '#DDD', - '#b4b4b4', - '#555555', - '#333', - '#a9afbb', - '#eee', - '#e7e7e7', -]; -const blackColor = '#000'; -const whiteColor = '#FFF'; - -const boxShadow = { - boxShadow: - `0 10px 30px -12px rgba(${ - hexToRgb (blackColor) - }, 0.42), 0 4px 25px 0px rgba(${ - hexToRgb (blackColor) - }, 0.12), 0 8px 10px -5px rgba(${ - hexToRgb (blackColor) - }, 0.2)`, -}; - -const primaryBoxShadow = { - boxShadow: - `0 4px 20px 0 rgba(${ - hexToRgb (blackColor) - },.14), 0 7px 10px -5px rgba(${ - hexToRgb (primaryColor[0]) - },.4)`, -}; -const infoBoxShadow = { - boxShadow: - `0 4px 20px 0 rgba(${ - hexToRgb (blackColor) - },.14), 0 7px 10px -5px rgba(${ - hexToRgb (infoColor[0]) - },.4)`, -}; -const successBoxShadow = { - boxShadow: - `0 4px 20px 0 rgba(${ - hexToRgb (blackColor) - },.14), 0 7px 10px -5px rgba(${ - hexToRgb (successColor[0]) - },.4)`, -}; -const warningBoxShadow = { - boxShadow: - `0 4px 20px 0 rgba(${ - hexToRgb (blackColor) - },.14), 0 7px 10px -5px rgba(${ - hexToRgb (warningColor[0]) - },.4)`, -}; -const dangerBoxShadow = { - boxShadow: - `0 4px 20px 0 rgba(${ - hexToRgb (blackColor) - },.14), 0 7px 10px -5px rgba(${ - hexToRgb (dangerColor[0]) - },.4)`, -}; -const roseBoxShadow = { - boxShadow: - `0 4px 20px 0 rgba(${ - hexToRgb (blackColor) - },.14), 0 7px 10px -5px rgba(${ - hexToRgb (roseColor[0]) - },.4)`, -}; - -const warningCardHeader = { - background: - `linear-gradient(60deg, ${warningColor[1]}, ${warningColor[2]})`, - ...warningBoxShadow, -}; -const successCardHeader = { - background: - `linear-gradient(60deg, ${successColor[1]}, ${successColor[2]})`, - ...successBoxShadow, -}; -const dangerCardHeader = { - background: - `linear-gradient(60deg, ${dangerColor[1]}, ${dangerColor[2]})`, - ...dangerBoxShadow, -}; -const infoCardHeader = { - background: - `linear-gradient(60deg, ${infoColor[1]}, ${infoColor[2]})`, - ...infoBoxShadow, -}; -const primaryCardHeader = { - background: - `linear-gradient(60deg, ${primaryColor[1]}, ${primaryColor[2]})`, - ...primaryBoxShadow, -}; -const roseCardHeader = { - background: - `linear-gradient(60deg, ${roseColor[1]}, ${roseColor[2]})`, - ...roseBoxShadow, -}; - -const cardActions = { - margin: '0 20px 10px', - paddingTop: '10px', - borderTop: `1px solid ${grayColor[10]}`, - height: 'auto', - ...defaultFont, -}; - -const cardHeader = { - margin: '-20px 15px 0', - borderRadius: '3px', - padding: '15px', -}; - -const card = { - display: 'inline-block', - position: 'relative', - width: '100%', - margin: '25px 0', - boxShadow: `0 1px 4px 0 rgba(${hexToRgb (blackColor)}, 0.14)`, - borderRadius: '3px', - color: `rgba(${hexToRgb (blackColor)}, 0.87)`, - background: whiteColor, -}; - -const defaultBoxShadow = { - border: '0', - borderRadius: '3px', - boxShadow: - `0 10px 20px -12px rgba(${ - hexToRgb (blackColor) - }, 0.42), 0 3px 20px 0px rgba(${ - hexToRgb (blackColor) - }, 0.12), 0 8px 10px -5px rgba(${ - hexToRgb (blackColor) - }, 0.2)`, - padding: '10px 0', - transition: 'all 150ms ease 0s', -}; - -const title = { - color: grayColor[2], - textDecoration: 'none', - fontWeight: '300', - marginTop: '30px', - marginBottom: '25px', - minHeight: '32px', - fontFamily: '\'Roboto\', \'Helvetica\', \'Arial\', sans-serif', - '& small': { - color: grayColor[1], - fontWeight: '400', - lineHeight: '1', - }, -}; - -const cardTitle = { - ...title, - marginTop: '0', - marginBottom: '3px', - minHeight: 'auto', - '& a': { - ...title, - marginTop: '.625rem', - marginBottom: '0.75rem', - minHeight: 'auto', - }, -}; - -const cardSubtitle = { - marginTop: '-.375rem', -}; - -const cardLink = { - '& + $cardLink': { - marginLeft: '1.25rem', - }, -}; - -export { - hexToRgb, - // variables - drawerWidth, - transition, - container, - boxShadow, - card, - defaultFont, - primaryColor, - warningColor, - dangerColor, - successColor, - infoColor, - roseColor, - grayColor, - blackColor, - whiteColor, - primaryBoxShadow, - infoBoxShadow, - successBoxShadow, - warningBoxShadow, - dangerBoxShadow, - roseBoxShadow, - warningCardHeader, - successCardHeader, - dangerCardHeader, - infoCardHeader, - primaryCardHeader, - roseCardHeader, - cardActions, - cardHeader, - defaultBoxShadow, - title, - cardTitle, - cardSubtitle, - cardLink, -}; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/cardImagesStyles.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/cardImagesStyles.js deleted file mode 100755 index b7fc0bc6..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/cardImagesStyles.js +++ /dev/null @@ -1,26 +0,0 @@ -const cardImagesStyles = { - cardImgTop: { - width: '100%', - borderTopLeftRadius: 'calc(.25rem - 1px)', - borderTopRightRadius: 'calc(.25rem - 1px)', - }, - cardImgBottom: { - width: '100%', - borderBottomRightRadius: 'calc(.25rem - 1px)', - borderBottomLeftRadius: 'calc(.25rem - 1px)', - }, - cardImgOverlay: { - position: 'absolute', - top: '0', - right: '0', - bottom: '0', - left: '0', - padding: '1.25rem', - }, - cardImg: { - width: '100%', - borderRadius: 'calc(.25rem - 1px)', - }, -}; - -export default cardImagesStyles; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/checkboxAdnRadioStyle.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/checkboxAdnRadioStyle.js deleted file mode 100755 index 578b10f7..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/checkboxAdnRadioStyle.js +++ /dev/null @@ -1,51 +0,0 @@ -import { - blackColor, - hexToRgb, - primaryColor, -} from '../material-dashboard-react'; - -const checkboxAdnRadioStyle = { - root: { - padding: '13px', - '&:hover': { - backgroundColor: 'unset', - }, - }, - labelRoot: { - marginLeft: '-14px', - }, - checked: { - color: `${primaryColor[0]}!important`, - }, - checkedIcon: { - width: '20px', - height: '20px', - border: `1px solid rgba(${hexToRgb (blackColor)}, .54)`, - borderRadius: '3px', - }, - uncheckedIcon: { - width: '0px', - height: '0px', - padding: '10px', - border: `1px solid rgba(${hexToRgb (blackColor)}, .54)`, - borderRadius: '3px', - }, - radio: { - color: `${primaryColor[0]}!important`, - }, - radioChecked: { - width: '20px', - height: '20px', - border: `1px solid ${primaryColor[0]}`, - borderRadius: '50%', - }, - radioUnchecked: { - width: '0px', - height: '0px', - padding: '10px', - border: `1px solid rgba(${hexToRgb (blackColor)}, .54)`, - borderRadius: '50%', - }, -}; - -export default checkboxAdnRadioStyle; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/buttonStyle.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/buttonStyle.js deleted file mode 100755 index 4b59cbfc..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/buttonStyle.js +++ /dev/null @@ -1,342 +0,0 @@ -import { - blackColor, - dangerColor, - grayColor, - hexToRgb, - infoColor, - primaryColor, - roseColor, - successColor, - warningColor, - whiteColor, -} from '../../material-dashboard-react'; - -const buttonStyle = { - button: { - minHeight: 'auto', - minWidth: 'auto', - backgroundColor: grayColor[0], - color: whiteColor, - boxShadow: - `0 2px 2px 0 rgba(${ - hexToRgb (grayColor[0]) - }, 0.14), 0 3px 1px -2px rgba(${ - hexToRgb (grayColor[0]) - }, 0.2), 0 1px 5px 0 rgba(${ - hexToRgb (grayColor[0]) - }, 0.12)`, - border: 'none', - borderRadius: '3px', - position: 'relative', - padding: '12px 30px', - margin: '.3125rem 1px', - fontSize: '12px', - fontWeight: '400', - textTransform: 'uppercase', - letterSpacing: '0', - willChange: 'box-shadow, transform', - transition: - 'box-shadow 0.2s cubic-bezier(0.4, 0, 1, 1), background-color 0.2s cubic-bezier(0.4, 0, 0.2, 1)', - lineHeight: '1.42857143', - textAlign: 'center', - whiteSpace: 'nowrap', - verticalAlign: 'middle', - touchAction: 'manipulation', - cursor: 'pointer', - '&:hover,&:focus': { - color: whiteColor, - backgroundColor: grayColor[0], - boxShadow: - `0 14px 26px -12px rgba(${ - hexToRgb (grayColor[0]) - }, 0.42), 0 4px 23px 0px rgba(${ - hexToRgb (blackColor) - }, 0.12), 0 8px 10px -5px rgba(${ - hexToRgb (grayColor[0]) - }, 0.2)`, - }, - '& .fab,& .fas,& .far,& .fal, &.material-icons': { - position: 'relative', - display: 'inline-block', - top: '0', - marginTop: '-1em', - marginBottom: '-1em', - fontSize: '1.1rem', - marginRight: '4px', - verticalAlign: 'middle', - }, - '& svg': { - position: 'relative', - display: 'inline-block', - top: '0', - width: '18px', - height: '18px', - marginRight: '4px', - verticalAlign: 'middle', - }, - '&$justIcon': { - '& .fab,& .fas,& .far,& .fal,& .material-icons': { - marginTop: '0px', - position: 'absolute', - width: '100%', - transform: 'none', - left: '0px', - top: '0px', - height: '100%', - lineHeight: '41px', - fontSize: '20px', - }, - }, - }, - white: { - '&,&:focus,&:hover': { - backgroundColor: whiteColor, - color: grayColor[0], - }, - }, - rose: { - backgroundColor: roseColor[0], - boxShadow: - `0 2px 2px 0 rgba(${ - hexToRgb (roseColor[0]) - }, 0.14), 0 3px 1px -2px rgba(${ - hexToRgb (roseColor[0]) - }, 0.2), 0 1px 5px 0 rgba(${ - hexToRgb (roseColor[0]) - }, 0.12)`, - '&:hover,&:focus': { - backgroundColor: roseColor[0], - boxShadow: - `0 14px 26px -12px rgba(${ - hexToRgb (roseColor[0]) - }, 0.42), 0 4px 23px 0px rgba(${ - hexToRgb (blackColor) - }, 0.12), 0 8px 10px -5px rgba(${ - hexToRgb (roseColor[0]) - }, 0.2)`, - }, - }, - primary: { - backgroundColor: primaryColor[0], - boxShadow: - `0 2px 2px 0 rgba(${ - hexToRgb (primaryColor[0]) - }, 0.14), 0 3px 1px -2px rgba(${ - hexToRgb (primaryColor[0]) - }, 0.2), 0 1px 5px 0 rgba(${ - hexToRgb (primaryColor[0]) - }, 0.12)`, - '&:hover,&:focus': { - backgroundColor: primaryColor[0], - boxShadow: - `0 14px 26px -12px rgba(${ - hexToRgb (primaryColor[0]) - }, 0.42), 0 4px 23px 0px rgba(${ - hexToRgb (blackColor) - }, 0.12), 0 8px 10px -5px rgba(${ - hexToRgb (primaryColor[0]) - }, 0.2)`, - }, - }, - info: { - backgroundColor: infoColor[0], - boxShadow: - `0 2px 2px 0 rgba(${ - hexToRgb (infoColor[0]) - }, 0.14), 0 3px 1px -2px rgba(${ - hexToRgb (infoColor[0]) - }, 0.2), 0 1px 5px 0 rgba(${ - hexToRgb (infoColor[0]) - }, 0.12)`, - '&:hover,&:focus': { - backgroundColor: infoColor[0], - boxShadow: - `0 14px 26px -12px rgba(${ - hexToRgb (infoColor[0]) - }, 0.42), 0 4px 23px 0px rgba(${ - hexToRgb (blackColor) - }, 0.12), 0 8px 10px -5px rgba(${ - hexToRgb (infoColor[0]) - }, 0.2)`, - }, - }, - success: { - backgroundColor: successColor[0], - boxShadow: - `0 2px 2px 0 rgba(${ - hexToRgb (successColor[0]) - }, 0.14), 0 3px 1px -2px rgba(${ - hexToRgb (successColor[0]) - }, 0.2), 0 1px 5px 0 rgba(${ - hexToRgb (successColor[0]) - }, 0.12)`, - '&:hover,&:focus': { - backgroundColor: successColor[0], - boxShadow: - `0 14px 26px -12px rgba(${ - hexToRgb (successColor[0]) - }, 0.42), 0 4px 23px 0px rgba(${ - hexToRgb (blackColor) - }, 0.12), 0 8px 10px -5px rgba(${ - hexToRgb (successColor[0]) - }, 0.2)`, - }, - }, - warning: { - backgroundColor: warningColor[0], - boxShadow: - `0 2px 2px 0 rgba(${ - hexToRgb (warningColor[0]) - }, 0.14), 0 3px 1px -2px rgba(${ - hexToRgb (warningColor[0]) - }, 0.2), 0 1px 5px 0 rgba(${ - hexToRgb (warningColor[0]) - }, 0.12)`, - '&:hover,&:focus': { - backgroundColor: warningColor[0], - boxShadow: - `0 14px 26px -12px rgba(${ - hexToRgb (warningColor[0]) - }, 0.42), 0 4px 23px 0px rgba(${ - hexToRgb (blackColor) - }, 0.12), 0 8px 10px -5px rgba(${ - hexToRgb (warningColor[0]) - }, 0.2)`, - }, - }, - danger: { - backgroundColor: dangerColor[0], - boxShadow: - `0 2px 2px 0 rgba(${ - hexToRgb (dangerColor[0]) - }, 0.14), 0 3px 1px -2px rgba(${ - hexToRgb (dangerColor[0]) - }, 0.2), 0 1px 5px 0 rgba(${ - hexToRgb (dangerColor[0]) - }, 0.12)`, - '&:hover,&:focus': { - backgroundColor: dangerColor[0], - boxShadow: - `0 14px 26px -12px rgba(${ - hexToRgb (dangerColor[0]) - }, 0.42), 0 4px 23px 0px rgba(${ - hexToRgb (blackColor) - }, 0.12), 0 8px 10px -5px rgba(${ - hexToRgb (dangerColor[0]) - }, 0.2)`, - }, - }, - simple: { - '&,&:focus,&:hover': { - color: whiteColor, - background: 'transparent', - boxShadow: 'none', - }, - '&$rose': { - '&,&:focus,&:hover,&:visited': { - color: roseColor[0], - }, - }, - '&$primary': { - '&,&:focus,&:hover,&:visited': { - color: primaryColor[0], - }, - }, - '&$info': { - '&,&:focus,&:hover,&:visited': { - color: infoColor[0], - }, - }, - '&$success': { - '&,&:focus,&:hover,&:visited': { - color: successColor[0], - }, - }, - '&$warning': { - '&,&:focus,&:hover,&:visited': { - color: warningColor[0], - }, - }, - '&$danger': { - '&,&:focus,&:hover,&:visited': { - color: dangerColor[0], - }, - }, - }, - transparent: { - '&,&:focus,&:hover': { - color: 'inherit', - background: 'transparent', - boxShadow: 'none', - }, - }, - disabled: { - opacity: '0.65', - pointerEvents: 'none', - }, - lg: { - padding: '1.125rem 2.25rem', - fontSize: '0.875rem', - lineHeight: '1.333333', - borderRadius: '0.2rem', - }, - sm: { - padding: '0.40625rem 1.25rem', - fontSize: '0.6875rem', - lineHeight: '1.5', - borderRadius: '0.2rem', - }, - round: { - borderRadius: '30px', - }, - block: { - width: '100% !important', - }, - link: { - '&,&:hover,&:focus': { - backgroundColor: 'transparent', - color: grayColor[0], - boxShadow: 'none', - }, - }, - justIcon: { - paddingLeft: '12px', - paddingRight: '12px', - fontSize: '20px', - height: '41px', - minWidth: '41px', - width: '41px', - '& .fab,& .fas,& .far,& .fal,& svg,& .material-icons': { - marginRight: '0px', - }, - '&$lg': { - height: '57px', - minWidth: '57px', - width: '57px', - lineHeight: '56px', - '& .fab,& .fas,& .far,& .fal,& .material-icons': { - fontSize: '32px', - lineHeight: '56px', - }, - '& svg': { - width: '32px', - height: '32px', - }, - }, - '&$sm': { - height: '30px', - minWidth: '30px', - width: '30px', - '& .fab,& .fas,& .far,& .fal,& .material-icons': { - fontSize: '17px', - lineHeight: '29px', - }, - '& svg': { - width: '17px', - height: '17px', - }, - }, - }, -}; - -export default buttonStyle; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/cardAvatarStyle.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/cardAvatarStyle.js deleted file mode 100755 index 292c859b..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/cardAvatarStyle.js +++ /dev/null @@ -1,32 +0,0 @@ -import { blackColor, hexToRgb } from '../../material-dashboard-react'; - -const cardAvatarStyle = { - cardAvatar: { - '&$cardAvatarProfile img': { - width: '100%', - height: 'auto', - }, - }, - cardAvatarProfile: { - maxWidth: '130px', - maxHeight: '130px', - margin: '-50px auto 0', - borderRadius: '50%', - overflow: 'hidden', - padding: '0', - boxShadow: - `0 16px 38px -12px rgba(${ - hexToRgb (blackColor) - }, 0.56), 0 4px 25px 0px rgba(${ - hexToRgb (blackColor) - }, 0.12), 0 8px 10px -5px rgba(${ - hexToRgb (blackColor) - }, 0.2)`, - '&$cardAvatarPlain': { - marginTop: '0', - }, - }, - cardAvatarPlain: {}, -}; - -export default cardAvatarStyle; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/cardBodyStyle.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/cardBodyStyle.js deleted file mode 100755 index ec5f58a0..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/cardBodyStyle.js +++ /dev/null @@ -1,17 +0,0 @@ -const cardBodyStyle = { - cardBody: { - padding: '0.9375rem 20px', - flex: '1 1 auto', - WebkitBoxFlex: '1', - position: 'relative', - }, - cardBodyPlain: { - paddingLeft: '5px', - paddingRight: '5px', - }, - cardBodyProfile: { - marginTop: '15px', - }, -}; - -export default cardBodyStyle; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/cardFooterStyle.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/cardFooterStyle.js deleted file mode 100755 index c59f7b6a..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/cardFooterStyle.js +++ /dev/null @@ -1,47 +0,0 @@ -import { grayColor } from '../../material-dashboard-react'; - -const cardFooterStyle = { - cardFooter: { - padding: '0', - paddingTop: '10px', - margin: '0 15px 10px', - borderRadius: '0', - justifyContent: 'space-between', - alignItems: 'center', - display: 'flex', - backgroundColor: 'transparent', - border: '0', - }, - cardFooterProfile: { - marginTop: '-15px', - }, - cardFooterPlain: { - paddingLeft: '5px', - paddingRight: '5px', - backgroundColor: 'transparent', - }, - cardFooterStats: { - borderTop: `1px solid ${grayColor[10]}`, - marginTop: '20px', - '& svg': { - position: 'relative', - top: '4px', - marginRight: '3px', - marginLeft: '3px', - width: '16px', - height: '16px', - }, - '& .fab,& .fas,& .far,& .fal,& .material-icons': { - fontSize: '16px', - position: 'relative', - top: '4px', - marginRight: '3px', - marginLeft: '3px', - }, - }, - cardFooterChart: { - borderTop: `1px solid ${grayColor[10]}`, - }, -}; - -export default cardFooterStyle; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/cardHeaderStyle.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/cardHeaderStyle.js deleted file mode 100755 index a2663e33..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/cardHeaderStyle.js +++ /dev/null @@ -1,124 +0,0 @@ -import { - dangerCardHeader, - infoCardHeader, - primaryCardHeader, - roseCardHeader, - successCardHeader, - warningCardHeader, - whiteColor, -} from '../../material-dashboard-react'; - -const cardHeaderStyle = { - cardHeader: { - padding: '0.75rem 1.25rem', - marginBottom: '0', - borderBottom: 'none', - background: 'transparent', - zIndex: '3 !important', - '&$cardHeaderPlain,&$cardHeaderIcon,&$cardHeaderStats,&$warningCardHeader,&$successCardHeader,&$dangerCardHeader,&$infoCardHeader,&$primaryCardHeader,&$roseCardHeader': { - margin: '0 15px', - padding: '0', - position: 'relative', - color: whiteColor, - }, - '&:first-child': { - borderRadius: 'calc(.25rem - 1px) calc(.25rem - 1px) 0 0', - }, - '&$warningCardHeader,&$successCardHeader,&$dangerCardHeader,&$infoCardHeader,&$primaryCardHeader,&$roseCardHeader': { - '&:not($cardHeaderIcon)': { - borderRadius: '3px', - marginTop: '-20px', - padding: '15px', - }, - }, - '&$cardHeaderStats svg': { - fontSize: '36px', - lineHeight: '56px', - textAlign: 'center', - width: '36px', - height: '36px', - margin: '10px 10px 4px', - }, - '&$cardHeaderStats i,&$cardHeaderStats .material-icons': { - fontSize: '36px', - lineHeight: '56px', - width: '56px', - height: '56px', - textAlign: 'center', - overflow: 'unset', - marginBottom: '1px', - }, - '&$cardHeaderStats$cardHeaderIcon': { - textAlign: 'right', - }, - }, - cardHeaderPlain: { - marginLeft: '0px !important', - marginRight: '0px !important', - }, - cardHeaderStats: { - '& $cardHeaderIcon': { - textAlign: 'right', - }, - '& h1,& h2,& h3,& h4,& h5,& h6': { - margin: '0 !important', - }, - }, - cardHeaderIcon: { - '&$warningCardHeader,&$successCardHeader,&$dangerCardHeader,&$infoCardHeader,&$primaryCardHeader,&$roseCardHeader': { - background: 'transparent', - boxShadow: 'none', - }, - '& i,& .material-icons': { - width: '33px', - height: '33px', - textAlign: 'center', - lineHeight: '33px', - }, - '& svg': { - width: '24px', - height: '24px', - textAlign: 'center', - lineHeight: '33px', - margin: '5px 4px 0px', - }, - }, - warningCardHeader: { - color: whiteColor, - '&:not($cardHeaderIcon)': { - ...warningCardHeader, - }, - }, - successCardHeader: { - color: whiteColor, - '&:not($cardHeaderIcon)': { - ...successCardHeader, - }, - }, - dangerCardHeader: { - color: whiteColor, - '&:not($cardHeaderIcon)': { - ...dangerCardHeader, - }, - }, - infoCardHeader: { - color: whiteColor, - '&:not($cardHeaderIcon)': { - ...infoCardHeader, - }, - }, - primaryCardHeader: { - color: whiteColor, - '&:not($cardHeaderIcon)': { - ...primaryCardHeader, - }, - }, - roseCardHeader: { - color: whiteColor, - '&:not($cardHeaderIcon)': { - ...roseCardHeader, - }, - }, -}; - -export default cardHeaderStyle; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/cardIconStyle.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/cardIconStyle.js deleted file mode 100755 index 302b1ef7..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/cardIconStyle.js +++ /dev/null @@ -1,30 +0,0 @@ -import { - dangerCardHeader, - grayColor, - infoCardHeader, - primaryCardHeader, - roseCardHeader, - successCardHeader, - warningCardHeader, -} from '../../material-dashboard-react'; - -const cardIconStyle = { - cardIcon: { - '&$warningCardHeader,&$successCardHeader,&$dangerCardHeader,&$infoCardHeader,&$primaryCardHeader,&$roseCardHeader': { - borderRadius: '3px', - backgroundColor: grayColor[0], - padding: '15px', - marginTop: '-20px', - marginRight: '15px', - float: 'left', - }, - }, - warningCardHeader, - successCardHeader, - dangerCardHeader, - infoCardHeader, - primaryCardHeader, - roseCardHeader, -}; - -export default cardIconStyle; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/cardStyle.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/cardStyle.js deleted file mode 100755 index 9e1b4bd7..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/cardStyle.js +++ /dev/null @@ -1,40 +0,0 @@ -import { - blackColor, - hexToRgb, - whiteColor, -} from '../../material-dashboard-react'; - -const cardStyle = { - card: { - border: '0', - marginBottom: '30px', - marginTop: '30px', - borderRadius: '6px', - color: `rgba(${hexToRgb (blackColor)}, 0.87)`, - background: whiteColor, - width: '100%', - boxShadow: `0 1px 4px 0 rgba(${hexToRgb (blackColor)}, 0.14)`, - position: 'relative', - display: 'flex', - flexDirection: 'column', - minWidth: '0', - wordWrap: 'break-word', - fontSize: '.875rem', - }, - cardPlain: { - background: 'transparent', - boxShadow: 'none', - }, - cardProfile: { - marginTop: '30px', - textAlign: 'center', - }, - cardChart: { - '& p': { - marginTop: '0px', - paddingTop: '0px', - }, - }, -}; - -export default cardStyle; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/customInputStyle.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/customInputStyle.js deleted file mode 100755 index e3774716..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/customInputStyle.js +++ /dev/null @@ -1,70 +0,0 @@ -import { - dangerColor, - defaultFont, - grayColor, - primaryColor, - successColor, -} from '../../material-dashboard-react'; - -const customInputStyle = { - disabled: { - '&:before': { - backgroundColor: 'transparent !important', - }, - }, - underline: { - '&:hover:not($disabled):before,&:before': { - borderColor: `${grayColor[4]} !important`, - borderWidth: '1px !important', - }, - '&:after': { - borderColor: primaryColor[0], - }, - }, - underlineError: { - '&:after': { - borderColor: dangerColor[0], - }, - }, - underlineSuccess: { - '&:after': { - borderColor: successColor[0], - }, - }, - labelRoot: { - ...defaultFont, - color: `${grayColor[3]} !important`, - fontWeight: '400', - fontSize: '14px', - lineHeight: '1.42857', - letterSpacing: 'unset', - }, - labelRootError: { - color: dangerColor[0], - }, - labelRootSuccess: { - color: successColor[0], - }, - feedback: { - position: 'absolute', - top: '18px', - right: '0', - zIndex: '2', - display: 'block', - width: '24px', - height: '24px', - textAlign: 'center', - pointerEvents: 'none', - }, - marginTop: { - marginTop: '16px', - }, - formControl: { - paddingBottom: '10px', - margin: '27px 0 0 0', - position: 'relative', - verticalAlign: 'unset', - }, -}; - -export default customInputStyle; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/customTabsStyle.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/customTabsStyle.js deleted file mode 100755 index 89e63a96..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/customTabsStyle.js +++ /dev/null @@ -1,62 +0,0 @@ -import { hexToRgb, whiteColor } from '../../material-dashboard-react'; - -const customTabsStyle = { - cardTitle: { - float: 'left', - padding: '10px 10px 10px 0px', - lineHeight: '24px', - }, - cardTitleRTL: { - float: 'right', - padding: '10px 0px 10px 10px !important', - }, - displayNone: { - display: 'none !important', - }, - tabsRoot: { - minHeight: 'unset !important', - overflowX: 'visible', - '& $tabRootButton': { - fontSize: '0.875rem', - }, - }, - tabRootButton: { - minHeight: 'unset !important', - minWidth: 'unset !important', - width: 'unset !important', - height: 'unset !important', - maxWidth: 'unset !important', - maxHeight: 'unset !important', - padding: '10px 15px', - borderRadius: '3px', - lineHeight: '24px', - border: '0 !important', - color: `${whiteColor} !important`, - marginLeft: '4px', - '&:last-child': { - marginLeft: '0px', - }, - }, - tabSelected: { - backgroundColor: `rgba(${hexToRgb (whiteColor)}, 0.2)`, - transition: '0.2s background-color 0.1s', - }, - tabWrapper: { - display: 'inline-block', - minHeight: 'unset !important', - minWidth: 'unset !important', - width: 'unset !important', - height: 'unset !important', - maxWidth: 'unset !important', - maxHeight: 'unset !important', - fontWeight: '500', - fontSize: '12px', - marginTop: '1px', - '& > svg,& > .material-icons': { - verticalAlign: 'middle', - margin: '-1px 5px 0 0 !important', - }, - }, -}; - -export default customTabsStyle; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/footerStyle.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/footerStyle.js deleted file mode 100755 index 51b705f1..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/footerStyle.js +++ /dev/null @@ -1,54 +0,0 @@ -import { - container, - defaultFont, - grayColor, - primaryColor, -} from '../../material-dashboard-react'; - -const footerStyle = { - block: { - color: 'inherit', - padding: '15px', - textTransform: 'uppercase', - borderRadius: '3px', - textDecoration: 'none', - position: 'relative', - display: 'block', - ...defaultFont, - fontWeight: '500', - fontSize: '12px', - }, - left: { - float: 'left!important', - display: 'block', - }, - right: { - padding: '15px 0', - margin: '0', - fontSize: '14px', - float: 'right!important', - }, - footer: { - bottom: '0', - borderTop: `1px solid ${grayColor[11]}`, - padding: '15px 0', - ...defaultFont, - }, - container, - a: { - color: primaryColor, - textDecoration: 'none', - backgroundColor: 'transparent', - }, - list: { - marginBottom: '0', - padding: '0', - marginTop: '0', - }, - inlineBlock: { - display: 'inline-block', - padding: '0px', - width: 'auto', - }, -}; -export default footerStyle; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/headerLinksStyle.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/headerLinksStyle.js deleted file mode 100755 index cf1cd1ce..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/headerLinksStyle.js +++ /dev/null @@ -1,112 +0,0 @@ -import { - dangerColor, - defaultFont, - whiteColor, -} from '../../material-dashboard-react'; -import dropdownStyle from '../dropdownStyle'; - -const headerLinksStyle = theme => ({ - ...dropdownStyle (theme), - search: { - '& > div': { - marginTop: '0', - }, - [theme.breakpoints.down ('sm')]: { - margin: '10px 15px !important', - float: 'none !important', - paddingTop: '1px', - paddingBottom: '1px', - padding: '0!important', - width: '60%', - marginTop: '40px', - '& input': { - color: whiteColor, - }, - }, - }, - linkText: { - zIndex: '4', - ...defaultFont, - fontSize: '14px', - margin: '0px', - }, - buttonLink: { - [theme.breakpoints.down ('sm')]: { - display: 'flex', - margin: '10px 15px 0', - width: '-webkit-fill-available', - '& svg': { - width: '24px', - height: '30px', - marginRight: '15px', - marginLeft: '-15px', - }, - '& .fab,& .fas,& .far,& .fal,& .material-icons': { - fontSize: '24px', - lineHeight: '30px', - width: '24px', - height: '30px', - marginRight: '15px', - marginLeft: '-15px', - }, - '& > span': { - justifyContent: 'flex-start', - width: '100%', - }, - }, - }, - searchButton: { - [theme.breakpoints.down ('sm')]: { - top: '-50px !important', - marginRight: '22px', - float: 'right', - }, - }, - margin: { - zIndex: '4', - margin: '0', - }, - searchIcon: { - width: '17px', - zIndex: '4', - }, - notifications: { - zIndex: '4', - [theme.breakpoints.up ('md')]: { - position: 'absolute', - top: '2px', - border: `1px solid ${whiteColor}`, - right: '4px', - fontSize: '9px', - background: dangerColor[0], - color: whiteColor, - minWidth: '16px', - height: '16px', - borderRadius: '10px', - textAlign: 'center', - lineHeight: '16px', - verticalAlign: 'middle', - display: 'block', - }, - [theme.breakpoints.down ('sm')]: { - ...defaultFont, - fontSize: '14px', - marginRight: '8px', - }, - }, - manager: { - [theme.breakpoints.down ('sm')]: { - width: '100%', - }, - display: 'inline-block', - }, - searchWrapper: { - [theme.breakpoints.down ('sm')]: { - width: '-webkit-fill-available', - margin: '10px 15px 0', - }, - display: 'inline-block', - }, -}); - -export default headerLinksStyle; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/headerStyle.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/headerStyle.js deleted file mode 100755 index 6945e3e5..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/headerStyle.js +++ /dev/null @@ -1,82 +0,0 @@ -import { - container, - dangerColor, - defaultBoxShadow, - defaultFont, - grayColor, - infoColor, - primaryColor, - successColor, - warningColor, - whiteColor, -} from '../../material-dashboard-react'; - -const headerStyle = () => ({ - appBar: { - backgroundColor: 'transparent', - boxShadow: 'none', - borderBottom: '0', - marginBottom: '0', - position: 'absolute', - width: '100%', - paddingTop: '10px', - zIndex: '1029', - color: grayColor[7], - border: '0', - borderRadius: '3px', - padding: '10px 0', - transition: 'all 150ms ease 0s', - minHeight: '50px', - display: 'block', - }, - container: { - ...container, - minHeight: '50px', - }, - flex: { - flex: 1, - }, - title: { - ...defaultFont, - letterSpacing: 'unset', - lineHeight: '30px', - fontSize: '18px', - borderRadius: '3px', - textTransform: 'none', - color: 'inherit', - margin: '0', - '&:hover,&:focus': { - background: 'transparent', - }, - }, - appResponsive: { - top: '8px', - }, - primary: { - backgroundColor: primaryColor[0], - color: whiteColor, - ...defaultBoxShadow, - }, - info: { - backgroundColor: infoColor[0], - color: whiteColor, - ...defaultBoxShadow, - }, - success: { - backgroundColor: successColor[0], - color: whiteColor, - ...defaultBoxShadow, - }, - warning: { - backgroundColor: warningColor[0], - color: whiteColor, - ...defaultBoxShadow, - }, - danger: { - backgroundColor: dangerColor[0], - color: whiteColor, - ...defaultBoxShadow, - }, -}); - -export default headerStyle; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/rtlHeaderLinksStyle.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/rtlHeaderLinksStyle.js deleted file mode 100755 index cf1cd1ce..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/rtlHeaderLinksStyle.js +++ /dev/null @@ -1,112 +0,0 @@ -import { - dangerColor, - defaultFont, - whiteColor, -} from '../../material-dashboard-react'; -import dropdownStyle from '../dropdownStyle'; - -const headerLinksStyle = theme => ({ - ...dropdownStyle (theme), - search: { - '& > div': { - marginTop: '0', - }, - [theme.breakpoints.down ('sm')]: { - margin: '10px 15px !important', - float: 'none !important', - paddingTop: '1px', - paddingBottom: '1px', - padding: '0!important', - width: '60%', - marginTop: '40px', - '& input': { - color: whiteColor, - }, - }, - }, - linkText: { - zIndex: '4', - ...defaultFont, - fontSize: '14px', - margin: '0px', - }, - buttonLink: { - [theme.breakpoints.down ('sm')]: { - display: 'flex', - margin: '10px 15px 0', - width: '-webkit-fill-available', - '& svg': { - width: '24px', - height: '30px', - marginRight: '15px', - marginLeft: '-15px', - }, - '& .fab,& .fas,& .far,& .fal,& .material-icons': { - fontSize: '24px', - lineHeight: '30px', - width: '24px', - height: '30px', - marginRight: '15px', - marginLeft: '-15px', - }, - '& > span': { - justifyContent: 'flex-start', - width: '100%', - }, - }, - }, - searchButton: { - [theme.breakpoints.down ('sm')]: { - top: '-50px !important', - marginRight: '22px', - float: 'right', - }, - }, - margin: { - zIndex: '4', - margin: '0', - }, - searchIcon: { - width: '17px', - zIndex: '4', - }, - notifications: { - zIndex: '4', - [theme.breakpoints.up ('md')]: { - position: 'absolute', - top: '2px', - border: `1px solid ${whiteColor}`, - right: '4px', - fontSize: '9px', - background: dangerColor[0], - color: whiteColor, - minWidth: '16px', - height: '16px', - borderRadius: '10px', - textAlign: 'center', - lineHeight: '16px', - verticalAlign: 'middle', - display: 'block', - }, - [theme.breakpoints.down ('sm')]: { - ...defaultFont, - fontSize: '14px', - marginRight: '8px', - }, - }, - manager: { - [theme.breakpoints.down ('sm')]: { - width: '100%', - }, - display: 'inline-block', - }, - searchWrapper: { - [theme.breakpoints.down ('sm')]: { - width: '-webkit-fill-available', - margin: '10px 15px 0', - }, - display: 'inline-block', - }, -}); - -export default headerLinksStyle; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/sidebarStyle.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/sidebarStyle.js deleted file mode 100755 index e942bb3a..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/sidebarStyle.js +++ /dev/null @@ -1,304 +0,0 @@ -import { - blackColor, - boxShadow, - dangerColor, - defaultFont, - drawerWidth, - grayColor, - hexToRgb, - infoColor, - primaryBoxShadow, - primaryColor, - successColor, - transition, - warningColor, - whiteColor, -} from '../../material-dashboard-react'; - -const sidebarStyle = theme => ({ - drawerPaper: { - border: 'none', - position: 'fixed', - top: '0', - bottom: '0', - left: '0', - zIndex: '1', - ...boxShadow, - width: drawerWidth, - [theme.breakpoints.up ('md')]: { - width: drawerWidth, - position: 'fixed', - height: '100%', - }, - [theme.breakpoints.down ('sm')]: { - width: drawerWidth, - ...boxShadow, - position: 'fixed', - display: 'block', - top: '0', - height: '100vh', - right: '0', - left: 'auto', - zIndex: '1032', - visibility: 'visible', - overflowY: 'visible', - borderTop: 'none', - textAlign: 'left', - paddingRight: '0px', - paddingLeft: '0', - transform: `translate3d(${drawerWidth}px, 0, 0)`, - ...transition, - }, - }, - drawerPaperRTL: { - [theme.breakpoints.up ('md')]: { - left: 'auto !important', - right: '0 !important', - }, - [theme.breakpoints.down ('sm')]: { - left: '0 !important', - right: 'auto !important', - }, - }, - logo: { - display: 'flex', - position: 'relative', - padding: '15px 15px', - justifyContent: 'center', - height: '100px', - zIndex: '4', - '&:after': { - content: '""', - position: 'absolute', - bottom: '0', - - height: '1px', - right: '15px', - width: 'calc(100% - 30px)', - backgroundColor: `rgba(${hexToRgb (grayColor[6])}, 0.3)`, - }, - }, - logoLink: { - ...defaultFont, - textTransform: 'uppercase', - padding: '5px 0', - display: 'block', - fontSize: '18px', - textAlign: 'left', - fontWeight: '400', - lineHeight: '30px', - textDecoration: 'none', - backgroundColor: 'transparent', - '&,&:hover': { - color: whiteColor, - }, - }, - logoLinkRTL: { - textAlign: 'right', - }, - logoImage: { - width: '30px', - display: 'inline-block', - maxHeight: '30px', - marginLeft: '10px', - marginRight: '15px', - }, - img: { - width: '35px', - top: '22px', - position: 'absolute', - verticalAlign: 'middle', - border: '0', - }, - background: { - position: 'absolute', - zIndex: '1', - height: '100%', - width: '100%', - display: 'block', - top: '0', - left: '0', - backgroundSize: 'cover', - backgroundPosition: 'center center', - '&:after': { - position: 'absolute', - zIndex: '3', - width: '100%', - height: '100%', - content: '""', - display: 'block', - background: blackColor, - opacity: '.8', - }, - }, - list: { - marginTop: '20px', - paddingLeft: '0', - paddingTop: '0', - paddingBottom: '0', - marginBottom: '0', - listStyle: 'none', - position: 'unset', - }, - item: { - position: 'relative', - display: 'block', - textDecoration: 'none', - '&:hover,&:focus,&:visited,&': { - color: whiteColor, - }, - }, - itemLink: { - width: 'auto', - transition: 'all 300ms linear', - margin: '10px 15px 0', - borderRadius: '3px', - position: 'relative', - display: 'block', - padding: '10px 15px', - backgroundColor: 'transparent', - ...defaultFont, - }, - itemIcon: { - width: '24px', - height: '30px', - fontSize: '24px', - lineHeight: '30px', - float: 'left', - marginRight: '15px', - textAlign: 'center', - verticalAlign: 'middle', - color: `rgba(${hexToRgb (whiteColor)}, 0.8)`, - }, - itemIconRTL: { - marginRight: '3px', - marginLeft: '15px', - float: 'right', - }, - itemText: { - ...defaultFont, - margin: '0', - lineHeight: '30px', - fontSize: '14px', - color: whiteColor, - }, - itemTextRTL: { - textAlign: 'right', - }, - whiteFont: { - color: whiteColor, - }, - purple: { - backgroundColor: primaryColor[0], - ...primaryBoxShadow, - '&:hover,&:focus': { - backgroundColor: primaryColor[0], - ...primaryBoxShadow, - }, - }, - blue: { - backgroundColor: infoColor[0], - boxShadow: - `0 12px 20px -10px rgba(${ - hexToRgb (infoColor[0]) - },.28), 0 4px 20px 0 rgba(${ - hexToRgb (blackColor) - },.12), 0 7px 8px -5px rgba(${ - hexToRgb (infoColor[0]) - },.2)`, - '&:hover,&:focus': { - backgroundColor: infoColor[0], - boxShadow: - `0 12px 20px -10px rgba(${ - hexToRgb (infoColor[0]) - },.28), 0 4px 20px 0 rgba(${ - hexToRgb (blackColor) - },.12), 0 7px 8px -5px rgba(${ - hexToRgb (infoColor[0]) - },.2)`, - }, - }, - green: { - backgroundColor: successColor[0], - boxShadow: - `0 12px 20px -10px rgba(${ - hexToRgb (successColor[0]) - },.28), 0 4px 20px 0 rgba(${ - hexToRgb (blackColor) - },.12), 0 7px 8px -5px rgba(${ - hexToRgb (successColor[0]) - },.2)`, - '&:hover,&:focus': { - backgroundColor: successColor[0], - boxShadow: - `0 12px 20px -10px rgba(${ - hexToRgb (successColor[0]) - },.28), 0 4px 20px 0 rgba(${ - hexToRgb (blackColor) - },.12), 0 7px 8px -5px rgba(${ - hexToRgb (successColor[0]) - },.2)`, - }, - }, - orange: { - backgroundColor: warningColor[0], - boxShadow: - `0 12px 20px -10px rgba(${ - hexToRgb (warningColor[0]) - },.28), 0 4px 20px 0 rgba(${ - hexToRgb (blackColor) - },.12), 0 7px 8px -5px rgba(${ - hexToRgb (warningColor[0]) - },.2)`, - '&:hover,&:focus': { - backgroundColor: warningColor[0], - boxShadow: - `0 12px 20px -10px rgba(${ - hexToRgb (warningColor[0]) - },.28), 0 4px 20px 0 rgba(${ - hexToRgb (blackColor) - },.12), 0 7px 8px -5px rgba(${ - hexToRgb (warningColor[0]) - },.2)`, - }, - }, - red: { - backgroundColor: dangerColor[0], - boxShadow: - `0 12px 20px -10px rgba(${ - hexToRgb (dangerColor[0]) - },.28), 0 4px 20px 0 rgba(${ - hexToRgb (blackColor) - },.12), 0 7px 8px -5px rgba(${ - hexToRgb (dangerColor[0]) - },.2)`, - '&:hover,&:focus': { - backgroundColor: dangerColor[0], - boxShadow: - `0 12px 20px -10px rgba(${ - hexToRgb (dangerColor[0]) - },.28), 0 4px 20px 0 rgba(${ - hexToRgb (blackColor) - },.12), 0 7px 8px -5px rgba(${ - hexToRgb (dangerColor[0]) - },.2)`, - }, - }, - sidebarWrapper: { - position: 'relative', - height: 'calc(100vh - 75px)', - overflow: 'auto', - width: '260px', - zIndex: '4', - overflowScrolling: 'touch', - }, - activePro: { - [theme.breakpoints.up ('md')]: { - position: 'absolute', - width: '100%', - bottom: '13px', - }, - }, -}); - -export default sidebarStyle; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/snackbarContentStyle.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/snackbarContentStyle.js deleted file mode 100755 index b611c077..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/snackbarContentStyle.js +++ /dev/null @@ -1,131 +0,0 @@ -import { - blackColor, - dangerBoxShadow, - dangerColor, - defaultFont, - grayColor, - hexToRgb, - infoBoxShadow, - infoColor, - primaryBoxShadow, - primaryColor, - roseBoxShadow, - roseColor, - successBoxShadow, - successColor, - warningBoxShadow, - warningColor, - whiteColor, -} from '../../material-dashboard-react'; - -const snackbarContentStyle = { - root: { - ...defaultFont, - flexWrap: 'unset', - position: 'relative', - padding: '20px 15px', - lineHeight: '20px', - marginBottom: '20px', - fontSize: '14px', - backgroundColor: whiteColor, - color: grayColor[7], - borderRadius: '3px', - minWidth: 'unset', - maxWidth: 'unset', - boxShadow: - `0 12px 20px -10px rgba(${ - hexToRgb (whiteColor) - }, 0.28), 0 4px 20px 0px rgba(${ - hexToRgb (blackColor) - }, 0.12), 0 7px 8px -5px rgba(${ - hexToRgb (whiteColor) - }, 0.2)`, - }, - top20: { - top: '20px', - }, - top40: { - top: '40px', - }, - info: { - backgroundColor: infoColor[3], - color: whiteColor, - ...infoBoxShadow, - }, - success: { - backgroundColor: successColor[3], - color: whiteColor, - ...successBoxShadow, - }, - warning: { - backgroundColor: warningColor[3], - color: whiteColor, - ...warningBoxShadow, - }, - danger: { - backgroundColor: dangerColor[3], - color: whiteColor, - ...dangerBoxShadow, - }, - primary: { - backgroundColor: primaryColor[3], - color: whiteColor, - ...primaryBoxShadow, - }, - rose: { - backgroundColor: roseColor[3], - color: whiteColor, - ...roseBoxShadow, - }, - message: { - padding: '0', - display: 'block', - maxWidth: '89%', - }, - close: { - width: '11px', - height: '11px', - }, - iconButton: { - width: '24px', - height: '24px', - padding: '0px', - }, - icon: { - display: 'block', - left: '15px', - position: 'absolute', - top: '50%', - marginTop: '-15px', - width: '30px', - height: '30px', - }, - infoIcon: { - color: infoColor[3], - }, - successIcon: { - color: successColor[3], - }, - warningIcon: { - color: warningColor[3], - }, - dangerIcon: { - color: dangerColor[3], - }, - primaryIcon: { - color: primaryColor[3], - }, - roseIcon: { - color: roseColor[3], - }, - iconMessage: { - paddingLeft: '50px', - display: 'block', - }, - actionRTL: { - marginLeft: '-8px', - marginRight: 'auto', - }, -}; - -export default snackbarContentStyle; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/tableStyle.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/tableStyle.js deleted file mode 100755 index 1123b296..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/tableStyle.js +++ /dev/null @@ -1,77 +0,0 @@ -import { - dangerColor, - defaultFont, - grayColor, - infoColor, - primaryColor, - roseColor, - successColor, - warningColor, -} from '../../material-dashboard-react'; - -const tableStyle = theme => ({ - warningTableHeader: { - color: warningColor[0], - }, - primaryTableHeader: { - color: primaryColor[0], - }, - dangerTableHeader: { - color: dangerColor[0], - }, - successTableHeader: { - color: successColor[0], - }, - infoTableHeader: { - color: infoColor[0], - }, - roseTableHeader: { - color: roseColor[0], - }, - grayTableHeader: { - color: grayColor[0], - }, - table: { - marginBottom: '0', - width: '100%', - maxWidth: '100%', - backgroundColor: 'transparent', - borderSpacing: '0', - borderCollapse: 'collapse', - }, - tableHeadCell: { - color: 'inherit', - ...defaultFont, - '&, &$tableCell': { - fontSize: '1em', - }, - }, - tableCell: { - ...defaultFont, - lineHeight: '1.42857143', - padding: '12px 8px', - verticalAlign: 'middle', - fontSize: '0.8125rem', - }, - tableResponsive: { - width: '100%', - marginTop: theme.spacing (3), - overflowX: 'auto', - }, - tableHeadRow: { - height: '56px', - color: 'inherit', - display: 'table-row', - outline: 'none', - verticalAlign: 'middle', - }, - tableBodyRow: { - height: '48px', - color: 'inherit', - display: 'table-row', - outline: 'none', - verticalAlign: 'middle', - }, -}); - -export default tableStyle; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/tasksStyle.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/tasksStyle.js deleted file mode 100755 index 673d6fc9..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/tasksStyle.js +++ /dev/null @@ -1,59 +0,0 @@ -import { - dangerColor, - defaultFont, - grayColor, - primaryColor, -} from '../../material-dashboard-react'; -import checkboxAdnRadioStyle - from '../checkboxAdnRadioStyle'; -import tooltipStyle from '../tooltipStyle'; - -const tasksStyle = { - ...tooltipStyle, - ...checkboxAdnRadioStyle, - table: { - marginBottom: '0', - overflow: 'visible', - }, - tableRow: { - position: 'relative', - borderBottom: `1px solid ${grayColor[5]}`, - }, - tableActions: { - display: 'flex', - border: 'none', - padding: '12px 8px !important', - verticalAlign: 'middle', - }, - tableCell: { - ...defaultFont, - padding: '8px', - verticalAlign: 'middle', - border: 'none', - lineHeight: '1.42857143', - fontSize: '14px', - }, - tableCellRTL: { - textAlign: 'right', - }, - tableActionButton: { - width: '27px', - height: '27px', - padding: '0', - }, - tableActionButtonIcon: { - width: '17px', - height: '17px', - }, - edit: { - backgroundColor: 'transparent', - color: primaryColor[0], - boxShadow: 'none', - }, - close: { - backgroundColor: 'transparent', - color: dangerColor[0], - boxShadow: 'none', - }, -}; -export default tasksStyle; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/typographyStyle.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/typographyStyle.js deleted file mode 100755 index 0c53a390..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/components/typographyStyle.js +++ /dev/null @@ -1,56 +0,0 @@ -import { - dangerColor, - defaultFont, - grayColor, - infoColor, - primaryColor, - successColor, - warningColor, -} from '../../material-dashboard-react'; - -const typographyStyle = { - defaultFontStyle: { - ...defaultFont, - fontSize: '14px', - }, - defaultHeaderMargins: { - marginTop: '20px', - marginBottom: '10px', - }, - quote: { - padding: '10px 20px', - margin: '0 0 20px', - fontSize: '17.5px', - borderLeft: `5px solid ${grayColor[10]}`, - }, - quoteText: { - margin: '0 0 10px', - fontStyle: 'italic', - }, - quoteAuthor: { - display: 'block', - fontSize: '80%', - lineHeight: '1.42857143', - color: grayColor[1], - }, - mutedText: { - color: grayColor[1], - }, - primaryText: { - color: primaryColor[0], - }, - infoText: { - color: infoColor[0], - }, - successText: { - color: successColor[0], - }, - warningText: { - color: warningColor[0], - }, - dangerText: { - color: dangerColor[0], - }, -}; - -export default typographyStyle; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/dropdownStyle.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/dropdownStyle.js deleted file mode 100755 index c02cfa6b..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/dropdownStyle.js +++ /dev/null @@ -1,124 +0,0 @@ -import { - blackColor, - defaultFont, - grayColor, - hexToRgb, - primaryBoxShadow, - primaryColor, - whiteColor, -} from '../material-dashboard-react'; - -const dropdownStyle = theme => ({ - buttonLink: { - [theme.breakpoints.down ('md')]: { - display: 'flex', - marginLeft: '30px', - width: 'auto', - }, - }, - links: { - width: '20px', - height: '20px', - zIndex: '4', - [theme.breakpoints.down ('md')]: { - display: 'block', - width: '30px', - height: '30px', - color: grayColor[9], - marginRight: '15px', - }, - }, - linkText: { - zIndex: '4', - ...defaultFont, - fontSize: '14px', - }, - popperClose: { - pointerEvents: 'none', - }, - pooperResponsive: { - [theme.breakpoints.down ('md')]: { - zIndex: '1640', - position: 'static', - float: 'none', - width: 'auto', - marginTop: '0', - backgroundColor: 'transparent', - border: '0', - WebkitBoxShadow: 'none', - boxShadow: 'none', - color: 'black', - }, - }, - popperNav: { - [theme.breakpoints.down ('sm')]: { - position: 'static !important', - left: 'unset !important', - top: 'unset !important', - transform: 'none !important', - willChange: 'unset !important', - '& > div': { - boxShadow: 'none !important', - marginLeft: '0rem', - marginRight: '0rem', - transition: 'none !important', - marginTop: '0px !important', - marginBottom: '0px !important', - padding: '0px !important', - backgroundColor: 'transparent !important', - '& ul li': { - color: `${whiteColor} !important`, - margin: '10px 15px 0!important', - padding: '10px 15px !important', - '&:hover': { - backgroundColor: 'hsla(0,0%,78%,.2)', - boxShadow: 'none', - }, - }, - }, - }, - }, - dropdown: { - borderRadius: '3px', - border: '0', - boxShadow: `0 2px 5px 0 rgba(${hexToRgb (blackColor)}, 0.26)`, - top: '100%', - zIndex: '1000', - minWidth: '160px', - padding: '5px 0', - margin: '2px 0 0', - fontSize: '14px', - textAlign: 'left', - listStyle: 'none', - backgroundColor: whiteColor, - WebkitBackgroundClip: 'padding-box', - backgroundClip: 'padding-box', - }, - dropdownItem: { - ...defaultFont, - fontSize: '13px', - padding: '10px 20px', - margin: '0 5px', - borderRadius: '2px', - WebkitTransition: 'all 150ms linear', - MozTransition: 'all 150ms linear', - OTransition: 'all 150ms linear', - MsTransition: 'all 150ms linear', - transition: 'all 150ms linear', - display: 'block', - clear: 'both', - fontWeight: '400', - lineHeight: '1.42857143', - color: grayColor[8], - whiteSpace: 'nowrap', - height: 'unset', - minHeight: 'unset', - '&:hover': { - backgroundColor: primaryColor[0], - color: whiteColor, - ...primaryBoxShadow, - }, - }, -}); - -export default dropdownStyle; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/layouts/adminStyle.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/layouts/adminStyle.js deleted file mode 100755 index c2698184..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/layouts/adminStyle.js +++ /dev/null @@ -1,36 +0,0 @@ -import { - container, - drawerWidth, - transition, -} from '../../material-dashboard-react'; - -const appStyle = theme => ({ - wrapper: { - position: 'relative', - top: '0', - height: '100vh', - }, - mainPanel: { - [theme.breakpoints.up ('md')]: { - width: `calc(100% - ${drawerWidth}px)`, - }, - overflow: 'auto', - position: 'relative', - float: 'right', - ...transition, - maxHeight: '100%', - width: '100%', - overflowScrolling: 'touch', - }, - content: { - marginTop: '70px', - padding: '30px 15px', - minHeight: 'calc(100vh - 123px)', - }, - container, - map: { - marginTop: '70px', - }, -}); - -export default appStyle; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/layouts/rtlStyle.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/layouts/rtlStyle.js deleted file mode 100755 index 4d9f41a9..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/layouts/rtlStyle.js +++ /dev/null @@ -1,37 +0,0 @@ -import { - container, - drawerWidth, - transition, -} from '../../material-dashboard-react'; - -const appStyle = theme => ({ - wrapper: { - position: 'relative', - top: '0', - height: '100vh', - direction: 'rtl', - }, - mainPanel: { - [theme.breakpoints.up ('md')]: { - width: `calc(100% - ${drawerWidth}px)`, - }, - overflow: 'auto', - position: 'relative', - float: 'left', - ...transition, - maxHeight: '100%', - width: '100%', - overflowScrolling: 'touch', - }, - content: { - marginTop: '70px', - padding: '30px 15px', - minHeight: 'calc(100vh - 123px)', - }, - container, - map: { - marginTop: '70px', - }, -}); - -export default appStyle; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/tooltipStyle.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/tooltipStyle.js deleted file mode 100755 index 81ca9ed3..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/tooltipStyle.js +++ /dev/null @@ -1,34 +0,0 @@ -import { blackColor, hexToRgb } from '../material-dashboard-react'; - -const tooltipStyle = { - tooltip: { - padding: '10px 15px', - minWidth: '130px', - lineHeight: '1.7em', - border: 'none', - borderRadius: '3px', - boxShadow: - `0 8px 10px 1px rgba(${ - hexToRgb (blackColor) - }, 0.14), 0 3px 14px 2px rgba(${ - hexToRgb (blackColor) - }, 0.12), 0 5px 5px -3px rgba(${ - hexToRgb (blackColor) - }, 0.2)`, - maxWidth: '200px', - textAlign: 'center', - fontFamily: '"Helvetica Neue",Helvetica,Arial,sans-serif', - fontSize: '12px', - fontStyle: 'normal', - fontWeight: '400', - textShadow: 'none', - textTransform: 'none', - letterSpacing: 'normal', - wordBreak: 'normal', - wordSpacing: 'normal', - wordWrap: 'normal', - whiteSpace: 'normal', - lineBreak: 'auto', - }, -}; -export default tooltipStyle; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/views/dashboardStyle.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/views/dashboardStyle.js deleted file mode 100755 index cfdd0a4e..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/views/dashboardStyle.js +++ /dev/null @@ -1,109 +0,0 @@ -import { - dangerColor, - grayColor, - hexToRgb, - successColor, - whiteColor, -} from '../../material-dashboard-react'; - -const dashboardStyle = { - containerTitle: { - fontSize: '32px', - fontWeight: '400', - marginBottom: '5px', - color: 'rgb(85, 85, 85)', - }, - successText: { - color: successColor[0], - }, - arrowCardCategory: { - width: '16px', - height: '16px', - }, - stats: { - color: grayColor[0], - display: 'inline-flex', - fontSize: '14px', - fontWeight: '400', - lineHeight: '22px', - '& svg': { - top: '4px', - width: '16px', - height: '16px', - position: 'relative', - marginRight: '3px', - marginLeft: '3px', - }, - '& .fab,& .fas,& .far,& .fal,& .material-icons': { - top: '4px', - fontSize: '16px', - position: 'relative', - marginRight: '3px', - marginLeft: '3px', - }, - }, - cardEmphasizeSuccess: { - color: successColor[0], - fontWeight: '400', - fontSize: '16px', - marginLeft: '4px', - }, - cardEmphasizeDanger: { - color: dangerColor[3], - fontWeight: '400', - fontSize: '16px', - marginLeft: '4px', - }, - cardEmphasizeNormal: { - color: grayColor[0], - fontWeight: '400', - fontSize: '16px', - marginLeft: '4px', - }, - cardCategory: { - color: grayColor[0], - margin: '0', - fontSize: '16px', - marginTop: '0', - paddingTop: '10px', - marginBottom: '0', - fontWeight: '400', - }, - cardCategoryWhite: { - color: `rgba(${hexToRgb (whiteColor)},.62)`, - margin: '0', - fontSize: '16px', - marginTop: '0', - marginBottom: '0', - }, - cardTitle: { - color: grayColor[2], - marginTop: '0px', - minHeight: 'auto', - fontWeight: '400', - fontFamily: '\'Roboto\', \'Helvetica\', \'Arial\', sans-serif', - marginBottom: '3px', - textDecoration: 'none', - '& small': { - color: grayColor[1], - fontWeight: '400', - lineHeight: '1', - }, - }, - cardTitleWhite: { - color: whiteColor, - marginTop: '0px', - minHeight: 'auto', - fontWeight: '300', - fontFamily: '\'Roboto\', \'Helvetica\', \'Arial\', sans-serif', - marginBottom: '3px', - textDecoration: 'none', - '& small': { - color: grayColor[1], - fontWeight: '400', - lineHeight: '1', - }, - }, -}; - -export default dashboardStyle; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/views/iconsStyle.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/views/iconsStyle.js deleted file mode 100755 index 06c9e635..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/views/iconsStyle.js +++ /dev/null @@ -1,46 +0,0 @@ -import { - boxShadow, - grayColor, - hexToRgb, - whiteColor, -} from '../../material-dashboard-react'; - -const iconsStyle = { - iframe: { - width: '100%', - height: '500px', - border: '0', - ...boxShadow, - }, - iframeContainer: { - margin: '0 -20px 0', - }, - cardCategoryWhite: { - '&,& a,& a:hover,& a:focus': { - color: `rgba(${hexToRgb (whiteColor)},.62)`, - margin: '0', - fontSize: '14px', - marginTop: '0', - marginBottom: '0', - }, - '& a,& a:hover,& a:focus': { - color: whiteColor, - }, - }, - cardTitleWhite: { - color: whiteColor, - marginTop: '0px', - minHeight: 'auto', - fontWeight: '300', - fontFamily: '\'Roboto\', \'Helvetica\', \'Arial\', sans-serif', - marginBottom: '3px', - textDecoration: 'none', - '& small': { - color: grayColor[1], - fontWeight: '400', - lineHeight: '1', - }, - }, -}; - -export default iconsStyle; diff --git a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/views/rtlStyle.js b/src/components/pages/AdminPage/assets/jss/material-dashboard-react/views/rtlStyle.js deleted file mode 100755 index 0d6e24ff..00000000 --- a/src/components/pages/AdminPage/assets/jss/material-dashboard-react/views/rtlStyle.js +++ /dev/null @@ -1,85 +0,0 @@ -import { - grayColor, - hexToRgb, - successColor, - whiteColor, -} from '../../material-dashboard-react'; - -const rtlStyle = { - successText: { - color: successColor[0], - }, - upArrowCardCategory: { - width: '16px', - height: '16px', - }, - stats: { - color: grayColor[0], - display: 'inline-flex', - fontSize: '12px', - lineHeight: '22px', - '& svg': { - top: '4px', - width: '16px', - height: '16px', - position: 'relative', - marginRight: '3px', - marginLeft: '3px', - }, - '& .fab,& .fas,& .far,& .fal,& .material-icons': { - top: '4px', - fontSize: '16px', - position: 'relative', - marginRight: '3px', - marginLeft: '3px', - }, - }, - cardCategory: { - color: grayColor[0], - margin: '0', - fontSize: '14px', - marginTop: '0', - paddingTop: '10px', - marginBottom: '0', - }, - cardCategoryWhite: { - color: `rgba(${hexToRgb (whiteColor)},.62)`, - margin: '0', - fontSize: '14px', - marginTop: '0', - marginBottom: '0', - '& a': { - color: whiteColor, - }, - }, - cardTitle: { - color: grayColor[2], - marginTop: '0px', - minHeight: 'auto', - fontWeight: '300', - fontFamily: '\'Roboto\', \'Helvetica\', \'Arial\', sans-serif', - marginBottom: '3px', - textDecoration: 'none', - '& small': { - color: grayColor[1], - fontWeight: '400', - lineHeight: '1', - }, - }, - cardTitleWhite: { - color: whiteColor, - marginTop: '0px', - minHeight: 'auto', - fontWeight: '300', - fontFamily: '\'Roboto\', \'Helvetica\', \'Arial\', sans-serif', - marginBottom: '3px', - textDecoration: 'none', - '& small': { - color: grayColor[1], - fontWeight: '400', - lineHeight: '1', - }, - }, -}; - -export default rtlStyle; diff --git a/src/components/pages/AdminPage/chartist.min.css b/src/components/pages/AdminPage/chartist.min.css deleted file mode 100644 index b4ae4cad..00000000 --- a/src/components/pages/AdminPage/chartist.min.css +++ /dev/null @@ -1,752 +0,0 @@ -.ct-double-octave:after, .ct-major-eleventh:after, .ct-major-second:after, .ct-major-seventh:after, .ct-major-sixth:after, .ct-major-tenth:after, .ct-major-third:after, .ct-major-twelfth:after, .ct-minor-second:after, .ct-minor-seventh:after, .ct-minor-sixth:after, .ct-minor-third:after, .ct-octave:after, .ct-perfect-fifth:after, .ct-perfect-fourth:after, .ct-square:after { - content: ""; - clear: both; -} - -.ct-label { - fill: rgba(0, 0, 0, .4); - color: rgba(0, 0, 0, .4); - font-size: .75rem; - line-height: 1; -} - -.ct-grid-background, .ct-line { - fill: none; -} - -.ct-chart-bar .ct-label, .ct-chart-line .ct-label { - display: block; - display: -webkit-box; - display: -moz-box; - display: -ms-flexbox; - display: -webkit-flex; - display: flex; -} - -.ct-chart-donut .ct-label, .ct-chart-pie .ct-label { - dominant-baseline: central; -} - -.ct-label.ct-horizontal.ct-start { - -webkit-box-align: flex-end; - -webkit-align-items: flex-end; - -ms-flex-align: flex-end; - align-items: flex-end; - -webkit-box-pack: flex-start; - -webkit-justify-content: flex-start; - -ms-flex-pack: flex-start; - justify-content: flex-start; - text-align: left; - text-anchor: start; -} - -.ct-label.ct-horizontal.ct-end { - -webkit-box-align: flex-start; - -webkit-align-items: flex-start; - -ms-flex-align: flex-start; - align-items: flex-start; - -webkit-box-pack: flex-start; - -webkit-justify-content: flex-start; - -ms-flex-pack: flex-start; - justify-content: flex-start; - text-align: left; - text-anchor: start; -} - -.ct-label.ct-vertical.ct-start { - -webkit-box-align: flex-end; - -webkit-align-items: flex-end; - -ms-flex-align: flex-end; - align-items: flex-end; - -webkit-box-pack: flex-end; - -webkit-justify-content: flex-end; - -ms-flex-pack: flex-end; - justify-content: flex-end; - text-align: right; - text-anchor: end; -} - -.ct-label.ct-vertical.ct-end { - -webkit-box-align: flex-end; - -webkit-align-items: flex-end; - -ms-flex-align: flex-end; - align-items: flex-end; - -webkit-box-pack: flex-start; - -webkit-justify-content: flex-start; - -ms-flex-pack: flex-start; - justify-content: flex-start; - text-align: left; - text-anchor: start -} - -.ct-chart-bar .ct-label.ct-horizontal.ct-start { - -webkit-box-align: flex-end; - -webkit-align-items: flex-end; - -ms-flex-align: flex-end; - align-items: flex-end; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - text-align: center; - text-anchor: start -} - -.ct-chart-bar .ct-label.ct-horizontal.ct-end { - -webkit-box-align: flex-start; - -webkit-align-items: flex-start; - -ms-flex-align: flex-start; - align-items: flex-start; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - text-align: center; - text-anchor: start -} - -.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-start { - -webkit-box-align: flex-end; - -webkit-align-items: flex-end; - -ms-flex-align: flex-end; - align-items: flex-end; - -webkit-box-pack: flex-start; - -webkit-justify-content: flex-start; - -ms-flex-pack: flex-start; - justify-content: flex-start; - text-align: left; - text-anchor: start -} - -.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-end { - -webkit-box-align: flex-start; - -webkit-align-items: flex-start; - -ms-flex-align: flex-start; - align-items: flex-start; - -webkit-box-pack: flex-start; - -webkit-justify-content: flex-start; - -ms-flex-pack: flex-start; - justify-content: flex-start; - text-align: left; - text-anchor: start -} - -.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-start { - -webkit-box-align: center; - -webkit-align-items: center; - -ms-flex-align: center; - align-items: center; - -webkit-box-pack: flex-end; - -webkit-justify-content: flex-end; - -ms-flex-pack: flex-end; - justify-content: flex-end; - text-align: right; - text-anchor: end -} - -.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-end { - -webkit-box-align: center; - -webkit-align-items: center; - -ms-flex-align: center; - align-items: center; - -webkit-box-pack: flex-start; - -webkit-justify-content: flex-start; - -ms-flex-pack: flex-start; - justify-content: flex-start; - text-align: left; - text-anchor: end -} - -.ct-grid { - stroke: rgba(0, 0, 0, .2); - stroke-width: 1px; - stroke-dasharray: 2px -} - -.ct-point { - stroke-width: 10px; - stroke-linecap: round -} - -.ct-line { - stroke-width: 4px -} - -.ct-area { - stroke: none; - fill-opacity: .1 -} - -.ct-bar { - fill: none; - stroke-width: 10px -} - -.ct-slice-donut { - fill: none; - stroke-width: 60px -} - -.ct-series-a .ct-bar, .ct-series-a .ct-line, .ct-series-a .ct-point, .ct-series-a .ct-slice-donut { - stroke: #d70206 -} - -.ct-series-a .ct-area, .ct-series-a .ct-slice-donut-solid, .ct-series-a .ct-slice-pie { - fill: #d70206 -} - -.ct-series-b .ct-bar, .ct-series-b .ct-line, .ct-series-b .ct-point, .ct-series-b .ct-slice-donut { - stroke: #f05b4f -} - -.ct-series-b .ct-area, .ct-series-b .ct-slice-donut-solid, .ct-series-b .ct-slice-pie { - fill: #f05b4f -} - -.ct-series-c .ct-bar, .ct-series-c .ct-line, .ct-series-c .ct-point, .ct-series-c .ct-slice-donut { - stroke: #f4c63d -} - -.ct-series-c .ct-area, .ct-series-c .ct-slice-donut-solid, .ct-series-c .ct-slice-pie { - fill: #f4c63d -} - -.ct-series-d .ct-bar, .ct-series-d .ct-line, .ct-series-d .ct-point, .ct-series-d .ct-slice-donut { - stroke: #d17905 -} - -.ct-series-d .ct-area, .ct-series-d .ct-slice-donut-solid, .ct-series-d .ct-slice-pie { - fill: #d17905 -} - -.ct-series-e .ct-bar, .ct-series-e .ct-line, .ct-series-e .ct-point, .ct-series-e .ct-slice-donut { - stroke: #453d3f -} - -.ct-series-e .ct-area, .ct-series-e .ct-slice-donut-solid, .ct-series-e .ct-slice-pie { - fill: #453d3f -} - -.ct-series-f .ct-bar, .ct-series-f .ct-line, .ct-series-f .ct-point, .ct-series-f .ct-slice-donut { - stroke: #59922b -} - -.ct-series-f .ct-area, .ct-series-f .ct-slice-donut-solid, .ct-series-f .ct-slice-pie { - fill: #59922b -} - -.ct-series-g .ct-bar, .ct-series-g .ct-line, .ct-series-g .ct-point, .ct-series-g .ct-slice-donut { - stroke: #0544d3 -} - -.ct-series-g .ct-area, .ct-series-g .ct-slice-donut-solid, .ct-series-g .ct-slice-pie { - fill: #0544d3 -} - -.ct-series-h .ct-bar, .ct-series-h .ct-line, .ct-series-h .ct-point, .ct-series-h .ct-slice-donut { - stroke: #6b0392 -} - -.ct-series-h .ct-area, .ct-series-h .ct-slice-donut-solid, .ct-series-h .ct-slice-pie { - fill: #6b0392 -} - -.ct-series-i .ct-bar, .ct-series-i .ct-line, .ct-series-i .ct-point, .ct-series-i .ct-slice-donut { - stroke: #f05b4f -} - -.ct-series-i .ct-area, .ct-series-i .ct-slice-donut-solid, .ct-series-i .ct-slice-pie { - fill: #f05b4f -} - -.ct-series-j .ct-bar, .ct-series-j .ct-line, .ct-series-j .ct-point, .ct-series-j .ct-slice-donut { - stroke: #dda458 -} - -.ct-series-j .ct-area, .ct-series-j .ct-slice-donut-solid, .ct-series-j .ct-slice-pie { - fill: #dda458 -} - -.ct-series-k .ct-bar, .ct-series-k .ct-line, .ct-series-k .ct-point, .ct-series-k .ct-slice-donut { - stroke: #eacf7d -} - -.ct-series-k .ct-area, .ct-series-k .ct-slice-donut-solid, .ct-series-k .ct-slice-pie { - fill: #eacf7d -} - -.ct-series-l .ct-bar, .ct-series-l .ct-line, .ct-series-l .ct-point, .ct-series-l .ct-slice-donut { - stroke: #86797d -} - -.ct-series-l .ct-area, .ct-series-l .ct-slice-donut-solid, .ct-series-l .ct-slice-pie { - fill: #86797d -} - -.ct-series-m .ct-bar, .ct-series-m .ct-line, .ct-series-m .ct-point, .ct-series-m .ct-slice-donut { - stroke: #b2c326 -} - -.ct-series-m .ct-area, .ct-series-m .ct-slice-donut-solid, .ct-series-m .ct-slice-pie { - fill: #b2c326 -} - -.ct-series-n .ct-bar, .ct-series-n .ct-line, .ct-series-n .ct-point, .ct-series-n .ct-slice-donut { - stroke: #6188e2 -} - -.ct-series-n .ct-area, .ct-series-n .ct-slice-donut-solid, .ct-series-n .ct-slice-pie { - fill: #6188e2 -} - -.ct-series-o .ct-bar, .ct-series-o .ct-line, .ct-series-o .ct-point, .ct-series-o .ct-slice-donut { - stroke: #a748ca -} - -.ct-series-o .ct-area, .ct-series-o .ct-slice-donut-solid, .ct-series-o .ct-slice-pie { - fill: #a748ca -} - -.ct-square { - display: block; - position: relative; - width: 100% -} - -.ct-square:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 100% -} - -.ct-square:after { - display: table -} - -.ct-square > svg { - display: block; - position: absolute; - top: 0; - left: 0 -} - -.ct-minor-second { - display: block; - position: relative; - width: 100% -} - -.ct-minor-second:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 93.75% -} - -.ct-minor-second:after { - display: table -} - -.ct-minor-second > svg { - display: block; - position: absolute; - top: 0; - left: 0 -} - -.ct-major-second { - display: block; - position: relative; - width: 100% -} - -.ct-major-second:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 88.8888888889% -} - -.ct-major-second:after { - display: table -} - -.ct-major-second > svg { - display: block; - position: absolute; - top: 0; - left: 0 -} - -.ct-minor-third { - display: block; - position: relative; - width: 100% -} - -.ct-minor-third:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 83.3333333333% -} - -.ct-minor-third:after { - display: table -} - -.ct-minor-third > svg { - display: block; - position: absolute; - top: 0; - left: 0 -} - -.ct-major-third { - display: block; - position: relative; - width: 100% -} - -.ct-major-third:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 80% -} - -.ct-major-third:after { - display: table -} - -.ct-major-third > svg { - display: block; - position: absolute; - top: 0; - left: 0 -} - -.ct-perfect-fourth { - display: block; - position: relative; - width: 100% -} - -.ct-perfect-fourth:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 75% -} - -.ct-perfect-fourth:after { - display: table -} - -.ct-perfect-fourth > svg { - display: block; - position: absolute; - top: 0; - left: 0 -} - -.ct-perfect-fifth { - display: block; - position: relative; - width: 100% -} - -.ct-perfect-fifth:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 66.6666666667% -} - -.ct-perfect-fifth:after { - display: table -} - -.ct-perfect-fifth > svg { - display: block; - position: absolute; - top: 0; - left: 0 -} - -.ct-minor-sixth { - display: block; - position: relative; - width: 100% -} - -.ct-minor-sixth:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 62.5% -} - -.ct-minor-sixth:after { - display: table -} - -.ct-minor-sixth > svg { - display: block; - position: absolute; - top: 0; - left: 0 -} - -.ct-golden-section { - display: block; - position: relative; - width: 100% -} - -.ct-golden-section:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 61.804697157% -} - -.ct-golden-section:after { - content: ""; - display: table; - clear: both -} - -.ct-golden-section > svg { - display: block; - position: absolute; - top: 0; - left: 0 -} - -.ct-major-sixth { - display: block; - position: relative; - width: 100% -} - -.ct-major-sixth:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 60% -} - -.ct-major-sixth:after { - display: table -} - -.ct-major-sixth > svg { - display: block; - position: absolute; - top: 0; - left: 0 -} - -.ct-minor-seventh { - display: block; - position: relative; - width: 100% -} - -.ct-minor-seventh:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 56.25% -} - -.ct-minor-seventh:after { - display: table -} - -.ct-minor-seventh > svg { - display: block; - position: absolute; - top: 0; - left: 0 -} - -.ct-major-seventh { - display: block; - position: relative; - width: 100% -} - -.ct-major-seventh:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 53.3333333333% -} - -.ct-major-seventh:after { - display: table -} - -.ct-major-seventh > svg { - display: block; - position: absolute; - top: 0; - left: 0 -} - -.ct-octave { - display: block; - position: relative; - width: 100% -} - -.ct-octave:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 50% -} - -.ct-octave:after { - display: table -} - -.ct-octave > svg { - display: block; - position: absolute; - top: 0; - left: 0 -} - -.ct-major-tenth { - display: block; - position: relative; - width: 100% -} - -.ct-major-tenth:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 40% -} - -.ct-major-tenth:after { - display: table -} - -.ct-major-tenth > svg { - display: block; - position: absolute; - top: 0; - left: 0 -} - -.ct-major-eleventh { - display: block; - position: relative; - width: 100% -} - -.ct-major-eleventh:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 37.5% -} - -.ct-major-eleventh:after { - display: table -} - -.ct-major-eleventh > svg { - display: block; - position: absolute; - top: 0; - left: 0 -} - -.ct-major-twelfth { - display: block; - position: relative; - width: 100% -} - -.ct-major-twelfth:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 33.3333333333% -} - -.ct-major-twelfth:after { - display: table -} - -.ct-major-twelfth > svg { - display: block; - position: absolute; - top: 0; - left: 0 -} - -.ct-double-octave { - display: block; - position: relative; - width: 100% -} - -.ct-double-octave:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 25% -} - -.ct-double-octave:after { - display: table -} - -.ct-double-octave > svg { - display: block; - position: absolute; - top: 0; - left: 0 -} diff --git a/src/components/pages/AdminPage/components/Card/Card.js b/src/components/pages/AdminPage/components/Card/Card.js deleted file mode 100755 index 0003ccfa..00000000 --- a/src/components/pages/AdminPage/components/Card/Card.js +++ /dev/null @@ -1,40 +0,0 @@ -import React from 'react'; -// nodejs library to set properties for components -import PropTypes from 'prop-types'; -// @material-ui/core components -import { makeStyles } from '@material-ui/core/styles'; -// nodejs library that concatenates classes -import classNames from 'classnames'; - -// @material-ui/icons -// core components -import styles from '../../assets/jss/material-dashboard-react/components/cardStyle'; - -const useStyles = makeStyles (styles); - -export default function Card (props) { - const classes = useStyles (); - const { - className, children, plain, profile, chart, ...rest - } = props; - const cardClasses = classNames ({ - [classes.card]: true, - [classes.cardPlain]: plain, - [classes.cardProfile]: profile, - [classes.cardChart]: chart, - [className]: className !== undefined, - }); - return ( -
- {children} -
- ); -} - -Card.propTypes = { - className: PropTypes.string, - plain: PropTypes.bool, - profile: PropTypes.bool, - chart: PropTypes.bool, - children: PropTypes.node, -}; diff --git a/src/components/pages/AdminPage/components/Card/CardAvatar.js b/src/components/pages/AdminPage/components/Card/CardAvatar.js deleted file mode 100755 index 2820d746..00000000 --- a/src/components/pages/AdminPage/components/Card/CardAvatar.js +++ /dev/null @@ -1,38 +0,0 @@ -import React from 'react'; -// nodejs library to set properties for components -import PropTypes from 'prop-types'; -// @material-ui/core components -import { makeStyles } from '@material-ui/core/styles'; -// nodejs library that concatenates classes -import classNames from 'classnames'; - -// @material-ui/icons -// core components -import styles from '../../assets/jss/material-dashboard-react/components/cardAvatarStyle'; - -const useStyles = makeStyles (styles); - -export default function CardAvatar (props) { - const classes = useStyles (); - const { - children, className, plain, profile, ...rest - } = props; - const cardAvatarClasses = classNames ({ - [classes.cardAvatar]: true, - [classes.cardAvatarProfile]: profile, - [classes.cardAvatarPlain]: plain, - [className]: className !== undefined, - }); - return ( -
- {children} -
- ); -} - -CardAvatar.propTypes = { - children: PropTypes.node.isRequired, - className: PropTypes.string, - profile: PropTypes.bool, - plain: PropTypes.bool, -}; diff --git a/src/components/pages/AdminPage/components/Card/CardBody.js b/src/components/pages/AdminPage/components/Card/CardBody.js deleted file mode 100755 index a4f407f5..00000000 --- a/src/components/pages/AdminPage/components/Card/CardBody.js +++ /dev/null @@ -1,38 +0,0 @@ -import React from 'react'; -// nodejs library to set properties for components -import PropTypes from 'prop-types'; -// @material-ui/core components -import { makeStyles } from '@material-ui/core/styles'; -// nodejs library that concatenates classes -import classNames from 'classnames'; - -// @material-ui/icons -// core components -import styles from '../../assets/jss/material-dashboard-react/components/cardBodyStyle'; - -const useStyles = makeStyles (styles); - -export default function CardBody (props) { - const classes = useStyles (); - const { - className, children, plain, profile, ...rest - } = props; - const cardBodyClasses = classNames ({ - [classes.cardBody]: true, - [classes.cardBodyPlain]: plain, - [classes.cardBodyProfile]: profile, - [className]: className !== undefined, - }); - return ( -
- {children} -
- ); -} - -CardBody.propTypes = { - className: PropTypes.string, - plain: PropTypes.bool, - profile: PropTypes.bool, - children: PropTypes.node, -}; diff --git a/src/components/pages/AdminPage/components/Card/CardFooter.js b/src/components/pages/AdminPage/components/Card/CardFooter.js deleted file mode 100755 index 7a16eb38..00000000 --- a/src/components/pages/AdminPage/components/Card/CardFooter.js +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react'; -// nodejs library to set properties for components -import PropTypes from 'prop-types'; -// @material-ui/core components -import { makeStyles } from '@material-ui/core/styles'; -// nodejs library that concatenates classes -import classNames from 'classnames'; - -// @material-ui/icons -// core components -import styles from '../../assets/jss/material-dashboard-react/components/cardFooterStyle'; - -const useStyles = makeStyles (styles); - -export default function CardFooter (props) { - const classes = useStyles (); - const { - className, children, plain, profile, stats, chart, ...rest - } = props; - const cardFooterClasses = classNames ({ - [classes.cardFooter]: true, - [classes.cardFooterPlain]: plain, - [classes.cardFooterProfile]: profile, - [classes.cardFooterStats]: stats, - [classes.cardFooterChart]: chart, - [className]: className !== undefined, - }); - return ( -
- {children} -
- ); -} - -CardFooter.propTypes = { - className: PropTypes.string, - plain: PropTypes.bool, - profile: PropTypes.bool, - stats: PropTypes.bool, - chart: PropTypes.bool, - children: PropTypes.node, -}; diff --git a/src/components/pages/AdminPage/components/Card/CardHeader.js b/src/components/pages/AdminPage/components/Card/CardHeader.js deleted file mode 100755 index e994542c..00000000 --- a/src/components/pages/AdminPage/components/Card/CardHeader.js +++ /dev/null @@ -1,49 +0,0 @@ -import React from 'react'; -// nodejs library to set properties for components -import PropTypes from 'prop-types'; -// @material-ui/core components -import { makeStyles } from '@material-ui/core/styles'; -// nodejs library that concatenates classes -import classNames from 'classnames'; - -// @material-ui/icons -// core components -import styles from '../../assets/jss/material-dashboard-react/components/cardHeaderStyle'; - -const useStyles = makeStyles (styles); - -export default function CardHeader (props) { - const classes = useStyles (); - const { - className, children, color, plain, stats, icon, ...rest - } = props; - const cardHeaderClasses = classNames ({ - [classes.cardHeader]: true, - [classes[`${color}CardHeader`]]: color, - [classes.cardHeaderPlain]: plain, - [classes.cardHeaderStats]: stats, - [classes.cardHeaderIcon]: icon, - [className]: className !== undefined, - }); - return ( -
- {children} -
- ); -} - -CardHeader.propTypes = { - className: PropTypes.string, - color: PropTypes.oneOf ([ - 'warning', - 'success', - 'danger', - 'info', - 'primary', - 'rose', - ]), - plain: PropTypes.bool, - stats: PropTypes.bool, - icon: PropTypes.bool, - children: PropTypes.node, -}; diff --git a/src/components/pages/AdminPage/components/Card/CardIcon.js b/src/components/pages/AdminPage/components/Card/CardIcon.js deleted file mode 100755 index 48f67684..00000000 --- a/src/components/pages/AdminPage/components/Card/CardIcon.js +++ /dev/null @@ -1,43 +0,0 @@ -import React from 'react'; -// nodejs library to set properties for components -import PropTypes from 'prop-types'; -// @material-ui/core components -import { makeStyles } from '@material-ui/core/styles'; -// nodejs library that concatenates classes -import classNames from 'classnames'; - -// @material-ui/icons -// core components -import styles from '../../assets/jss/material-dashboard-react/components/cardIconStyle'; - -const useStyles = makeStyles (styles); - -export default function CardIcon (props) { - const classes = useStyles (); - const { - className, children, color, ...rest - } = props; - const cardIconClasses = classNames ({ - [classes.cardIcon]: true, - [classes[`${color}CardHeader`]]: color, - [className]: className !== undefined, - }); - return ( -
- {children} -
- ); -} - -CardIcon.propTypes = { - className: PropTypes.string, - color: PropTypes.oneOf ([ - 'warning', - 'success', - 'danger', - 'info', - 'primary', - 'rose', - ]), - children: PropTypes.node, -}; diff --git a/src/components/pages/AdminPage/components/CustomButtons/Button.js b/src/components/pages/AdminPage/components/CustomButtons/Button.js deleted file mode 100755 index 69262bb0..00000000 --- a/src/components/pages/AdminPage/components/CustomButtons/Button.js +++ /dev/null @@ -1,72 +0,0 @@ -import React from 'react'; -// nodejs library to set properties for components -import PropTypes from 'prop-types'; -import Button from '@material-ui/core/Button'; -// material-ui components -import { makeStyles } from '@material-ui/core/styles'; -// nodejs library that concatenates classes -import classNames from 'classnames'; - -import styles from '../../assets/jss/material-dashboard-react/components/buttonStyle'; - -const useStyles = makeStyles (styles); - -export default function RegularButton (props) { - const classes = useStyles (); - const { - color, - round, - children, - disabled, - simple, - size, - block, - link, - justIcon, - className, - muiClasses, - ...rest - } = props; - const btnClasses = classNames ({ - [classes.button]: true, - [classes[size]]: size, - [classes[color]]: color, - [classes.round]: round, - [classes.disabled]: disabled, - [classes.simple]: simple, - [classes.block]: block, - [classes.link]: link, - [classes.justIcon]: justIcon, - [className]: className, - }); - return ( - - ); -} - -RegularButton.propTypes = { - color: PropTypes.oneOf ([ - 'primary', - 'info', - 'success', - 'warning', - 'danger', - 'rose', - 'white', - 'transparent', - ]), - size: PropTypes.oneOf (['sm', 'lg']), - simple: PropTypes.bool, - round: PropTypes.bool, - disabled: PropTypes.bool, - block: PropTypes.bool, - link: PropTypes.bool, - justIcon: PropTypes.bool, - className: PropTypes.string, - // use this to pass the classes props from Material-UI - // eslint-disable-next-line react/forbid-prop-types - muiClasses: PropTypes.object, - children: PropTypes.node, -}; diff --git a/src/components/pages/AdminPage/components/CustomInput/CustomInput.js b/src/components/pages/AdminPage/components/CustomInput/CustomInput.js deleted file mode 100755 index 07c8a1e7..00000000 --- a/src/components/pages/AdminPage/components/CustomInput/CustomInput.js +++ /dev/null @@ -1,85 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import FormControl from '@material-ui/core/FormControl'; -import Input from '@material-ui/core/Input'; -import InputLabel from '@material-ui/core/InputLabel'; -// @material-ui/core components -import { makeStyles } from '@material-ui/core/styles'; -import Check from '@material-ui/icons/Check'; -// @material-ui/icons -import Clear from '@material-ui/icons/Clear'; -import classNames from 'classnames'; - -// core components -import styles from '../../assets/jss/material-dashboard-react/components/customInputStyle'; - -const useStyles = makeStyles (styles); - -export default function CustomInput (props) { - const classes = useStyles (); - const { - formControlProps, - labelText, - id, - labelProps, - inputProps, - error, - success, - } = props; - - const labelClasses = classNames ({ - [` ${classes.labelRootError}`]: error, - [` ${classes.labelRootSuccess}`]: success && !error, - }); - const underlineClasses = classNames ({ - [classes.underlineError]: error, - [classes.underlineSuccess]: success && !error, - [classes.underline]: true, - }); - const marginTop = classNames ({ - [classes.marginTop]: labelText === undefined, - }); - return ( - - {labelText !== undefined ? ( - - {labelText} - - ) : null} - - {error ? ( - - ) : success ? ( - - ) : null} - - ); -} - -CustomInput.propTypes = { - labelText: PropTypes.node, - // eslint-disable-next-line react/forbid-prop-types - labelProps: PropTypes.object, - id: PropTypes.string, - // eslint-disable-next-line react/forbid-prop-types - inputProps: PropTypes.object, - // eslint-disable-next-line react/forbid-prop-types - formControlProps: PropTypes.object, - error: PropTypes.bool, - success: PropTypes.bool, -}; diff --git a/src/components/pages/AdminPage/components/CustomTabs/CustomTabs.js b/src/components/pages/AdminPage/components/CustomTabs/CustomTabs.js deleted file mode 100755 index 860a6264..00000000 --- a/src/components/pages/AdminPage/components/CustomTabs/CustomTabs.js +++ /dev/null @@ -1,100 +0,0 @@ -import React from 'react'; -// nodejs library to set properties for components -import PropTypes from 'prop-types'; -// material-ui components -import { makeStyles } from '@material-ui/core/styles'; -import Tab from '@material-ui/core/Tab'; -import Tabs from '@material-ui/core/Tabs'; -// nodejs library that concatenates classes -import classNames from 'classnames'; - -import styles from '../../assets/jss/material-dashboard-react/components/customTabsStyle'; -// core components -import Card from '../Card/Card'; -import CardBody from '../Card/CardBody'; -import CardHeader from '../Card/CardHeader'; - -const useStyles = makeStyles (styles); - -export default function CustomTabs (props) { - const [value, setValue] = React.useState (0); - const handleChange = (event, value) => { - setValue (value); - }; - const classes = useStyles (); - const { - headerColor, plainTabs, tabs, title, rtlActive, - } = props; - const cardTitle = classNames ({ - [classes.cardTitle]: true, - [classes.cardTitleRTL]: rtlActive, - }); - return ( - - - {title !== undefined ?
{title}
: null} - - {tabs.map ((prop, key) => { - let icon = {}; - if (prop.tabIcon) { - icon = { - icon: , - }; - } - return ( - - ); - })} - -
- - {tabs.map ((prop, key) => { - if (key === value) { - return
{prop.tabContent}
; - } - return null; - })} -
-
- ); -} - -CustomTabs.propTypes = { - headerColor: PropTypes.oneOf ([ - 'warning', - 'success', - 'danger', - 'info', - 'primary', - 'rose', - ]), - title: PropTypes.string, - tabs: PropTypes.arrayOf ( - PropTypes.shape ({ - tabName: PropTypes.string.isRequired, - tabIcon: PropTypes.object, - tabContent: PropTypes.node.isRequired, - }), - ), - rtlActive: PropTypes.bool, - plainTabs: PropTypes.bool, -}; diff --git a/src/components/pages/AdminPage/components/FixedPlugin/FixedPlugin.js b/src/components/pages/AdminPage/components/FixedPlugin/FixedPlugin.js deleted file mode 100755 index dda13d02..00000000 --- a/src/components/pages/AdminPage/components/FixedPlugin/FixedPlugin.js +++ /dev/null @@ -1,191 +0,0 @@ -/*eslint-disable*/ -import React, { Component } from 'react'; -// nodejs library to set properties for components -import PropTypes from 'prop-types'; -// nodejs library that concatenates classes -import classnames from 'classnames'; -import SettingsIcon from '@material-ui/icons/Settings'; - -import imagine1 from '../../assets/img/sidebar-1.jpg'; -import imagine2 from '../../assets/img/sidebar-2.jpg'; -import imagine3 from '../../assets/img/sidebar-3.jpg'; -import imagine4 from '../../assets/img/sidebar-4.jpg'; - -import Button from '../CustomButtons/Button'; - -export default function FixedPlugin(props) { - const [classes, setClasses] = React.useState('dropdown'); - const [bg_checked, setBg_checked] = React.useState(true); - const [bgImage, setBgImage] = React.useState(props.bgImage); - const handleClick = () => { - props.handleFixedClick(); - }; - return ( - - ); -} - -FixedPlugin.propTypes = { - bgImage: PropTypes.string, - handleFixedClick: PropTypes.func, - rtlActive: PropTypes.bool, - fixedClasses: PropTypes.string, - bgColor: PropTypes.oneOf(['purple', 'blue', 'green', 'orange', 'red']), - handleColorClick: PropTypes.func, - handleImageClick: PropTypes.func, -}; diff --git a/src/components/pages/AdminPage/components/Footer/Footer.js b/src/components/pages/AdminPage/components/Footer/Footer.js deleted file mode 100755 index 5fad7ce2..00000000 --- a/src/components/pages/AdminPage/components/Footer/Footer.js +++ /dev/null @@ -1,58 +0,0 @@ -/*eslint-disable*/ -import React from 'react'; -import PropTypes from 'prop-types'; -// @material-ui/core components -import { makeStyles } from '@material-ui/core/styles'; -import ListItem from '@material-ui/core/ListItem'; -import List from '@material-ui/core/List'; -// core components -import styles from '../../assets/jss/material-dashboard-react/components/footerStyle'; - -const useStyles = makeStyles(styles); - -export default function Footer(props) { - const classes = useStyles(); - return ( - - ); -} diff --git a/src/components/pages/AdminPage/components/Grid/GridContainer.js b/src/components/pages/AdminPage/components/Grid/GridContainer.js deleted file mode 100755 index ec3bd315..00000000 --- a/src/components/pages/AdminPage/components/Grid/GridContainer.js +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; -// nodejs library to set properties for components -import PropTypes from 'prop-types'; -import Grid from '@material-ui/core/Grid'; -// @material-ui/core components -import { makeStyles } from '@material-ui/core/styles'; - -const styles = { - grid: { - margin: '0 -15px !important', - width: 'unset', - }, -}; - -const useStyles = makeStyles (styles); - -export default function GridContainer (props) { - const classes = useStyles (); - const { children, ...rest } = props; - return ( - - {children} - - ); -} - -GridContainer.propTypes = { - children: PropTypes.node, -}; diff --git a/src/components/pages/AdminPage/components/Grid/GridItem.js b/src/components/pages/AdminPage/components/Grid/GridItem.js deleted file mode 100755 index 18c10c77..00000000 --- a/src/components/pages/AdminPage/components/Grid/GridItem.js +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react'; -// nodejs library to set properties for components -import PropTypes from 'prop-types'; -import Grid from '@material-ui/core/Grid'; -// @material-ui/core components -import { makeStyles } from '@material-ui/core/styles'; - -const styles = { - grid: { - padding: '0 15px !important', - }, -}; - -const useStyles = makeStyles (styles); - -export default function GridItem (props) { - const classes = useStyles (); - const { children, ...rest } = props; - return ( - - {children} - - ); -} - -GridItem.propTypes = { - children: PropTypes.node, -}; diff --git a/src/components/pages/AdminPage/components/Navbars/AdminNavbarLinks.js b/src/components/pages/AdminPage/components/Navbars/AdminNavbarLinks.js deleted file mode 100755 index 3e499c55..00000000 --- a/src/components/pages/AdminPage/components/Navbars/AdminNavbarLinks.js +++ /dev/null @@ -1,224 +0,0 @@ -import React from 'react'; -import ClickAwayListener from '@material-ui/core/ClickAwayListener'; -import Divider from '@material-ui/core/Divider'; -import Grow from '@material-ui/core/Grow'; -import Hidden from '@material-ui/core/Hidden'; -import MenuItem from '@material-ui/core/MenuItem'; -import MenuList from '@material-ui/core/MenuList'; -import Paper from '@material-ui/core/Paper'; -import Poppers from '@material-ui/core/Popper'; -// @material-ui/core components -import { makeStyles } from '@material-ui/core/styles'; -import Dashboard from '@material-ui/icons/Dashboard'; -import Notifications from '@material-ui/icons/Notifications'; -// @material-ui/icons -import Person from '@material-ui/icons/Person'; -import Search from '@material-ui/icons/Search'; -import classNames from 'classnames'; - -import styles from '../../assets/jss/material-dashboard-react/components/headerLinksStyle'; -import Button from '../CustomButtons/Button'; -// core components -import CustomInput from '../CustomInput/CustomInput'; - -const useStyles = makeStyles (styles); - -export default function AdminNavbarLinks () { - const classes = useStyles (); - const [openNotification, setOpenNotification] = React.useState (null); - const [openProfile, setOpenProfile] = React.useState (null); - const handleClickNotification = event => { - if (openNotification && openNotification.contains (event.target)) { - setOpenNotification (null); - } else { - setOpenNotification (event.currentTarget); - } - }; - const handleCloseNotification = () => { - setOpenNotification (null); - }; - const handleClickProfile = event => { - if (openProfile && openProfile.contains (event.target)) { - setOpenProfile (null); - } else { - setOpenProfile (event.currentTarget); - } - }; - const handleCloseProfile = () => { - setOpenProfile (null); - }; - return ( -
-
- - -
- -
- - - {({ TransitionProps, placement }) => ( - - - - - - Mike John responded to your email - - - You have 5 new tasks - - - You{'\''}re now friend with Andrew - - - Another Notification - - - Another One - - - - - - )} - -
-
- - - {({ TransitionProps, placement }) => ( - - - - - - Profile - - - Settings - - - - Logout - - - - - - )} - -
-
- ); -} diff --git a/src/components/pages/AdminPage/components/Navbars/Navbar.js b/src/components/pages/AdminPage/components/Navbars/Navbar.js deleted file mode 100755 index 461a8120..00000000 --- a/src/components/pages/AdminPage/components/Navbars/Navbar.js +++ /dev/null @@ -1,71 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import AppBar from '@material-ui/core/AppBar'; -import Hidden from '@material-ui/core/Hidden'; -import IconButton from '@material-ui/core/IconButton'; -// @material-ui/core components -import { makeStyles } from '@material-ui/core/styles'; -import Toolbar from '@material-ui/core/Toolbar'; -// @material-ui/icons -import Menu from '@material-ui/icons/Menu'; -import classNames from 'classnames'; - -import styles from '../../assets/jss/material-dashboard-react/components/headerStyle'; -// core components -import Button from '../CustomButtons/Button'; -import AdminNavbarLinks from './AdminNavbarLinks'; -import RTLNavbarLinks from './RTLNavbarLinks'; - - -const useStyles = makeStyles (styles); - -export default function Header (props) { - const classes = useStyles (); - - function makeBrand () { - let name; - props.routes.map (prop => { - if (window.location.href.indexOf (prop.layout + prop.path) !== -1) { - name = props.rtlActive ? prop.rtlName : prop.name; - } - return null; - }); - return name; - } - - const { color } = props; - const appBarClasses = classNames ({ - [` ${classes[color]}`]: color, - }); - return ( - - -
- {/* Here we create navbar brand, based on route name */} - -
- - {props.rtlActive ? : } - - - - - - - - - ); -} - -Header.propTypes = { - color: PropTypes.oneOf (['primary', 'info', 'success', 'warning', 'danger']), - rtlActive: PropTypes.bool, - handleDrawerToggle: PropTypes.func, - routes: PropTypes.arrayOf (PropTypes.object), -}; diff --git a/src/components/pages/AdminPage/components/Navbars/RTLNavbarLinks.js b/src/components/pages/AdminPage/components/Navbars/RTLNavbarLinks.js deleted file mode 100755 index b3b76498..00000000 --- a/src/components/pages/AdminPage/components/Navbars/RTLNavbarLinks.js +++ /dev/null @@ -1,162 +0,0 @@ -import React from 'react'; -import ClickAwayListener from '@material-ui/core/ClickAwayListener'; -import Grow from '@material-ui/core/Grow'; -import Hidden from '@material-ui/core/Hidden'; -import MenuItem from '@material-ui/core/MenuItem'; -import MenuList from '@material-ui/core/MenuList'; -import Paper from '@material-ui/core/Paper'; -import Poppers from '@material-ui/core/Popper'; -// @material-ui/core components -import { makeStyles } from '@material-ui/core/styles'; -import Dashboard from '@material-ui/icons/Dashboard'; -import Notifications from '@material-ui/icons/Notifications'; -// @material-ui/icons -import Person from '@material-ui/icons/Person'; -import Search from '@material-ui/icons/Search'; -import classNames from 'classnames'; - -import styles from '../../assets/jss/material-dashboard-react/components/rtlHeaderLinksStyle'; -import Button from '../CustomButtons/Button'; -// core components -import CustomInput from '../CustomInput/CustomInput'; - -const useStyles = makeStyles (styles); - -export default function RTLNavbarLinks () { - const classes = useStyles (); - const [open, setOpen] = React.useState (null); - const handleToggle = event => { - if (open && open.contains (event.target)) { - setOpen (null); - } else { - setOpen (event.currentTarget); - } - }; - - const handleClose = () => { - setOpen (null); - }; - - return ( -
-
- - -
- -
- - - {({ TransitionProps, placement }) => ( - - - - - - محمدرضا به ایمیل شما پاسخ داد - - - شما ۵ وظیفه جدید دارید - - - از حالا شما با علیرضا دوست هستید - - - اعلان دیگر - - - اعلان دیگر - - - - - - )} - -
- -
- ); -} diff --git a/src/components/pages/AdminPage/components/Sidebar/Sidebar.js b/src/components/pages/AdminPage/components/Sidebar/Sidebar.js deleted file mode 100755 index 68c3404b..00000000 --- a/src/components/pages/AdminPage/components/Sidebar/Sidebar.js +++ /dev/null @@ -1,149 +0,0 @@ -/*eslint-disable*/ -import React from 'react'; -import classNames from 'classnames'; -import PropTypes from 'prop-types'; -import { NavLink } from 'react-router-dom'; -// @material-ui/core components -import { makeStyles } from '@material-ui/core/styles'; -import Drawer from '@material-ui/core/Drawer'; -import Hidden from '@material-ui/core/Hidden'; -import List from '@material-ui/core/List'; -import ListItem from '@material-ui/core/ListItem'; -import ListItemText from '@material-ui/core/ListItemText'; -import Icon from '@material-ui/core/Icon'; -// core components -import AdminNavbarLinks from '../Navbars/AdminNavbarLinks'; -import RTLNavbarLinks from '../Navbars/RTLNavbarLinks'; - -import styles from '../../assets/jss/material-dashboard-react/components/sidebarStyle'; - -const useStyles = makeStyles(styles); - -export default function Sidebar(props) { - const classes = useStyles(); - - // verifies if routeName is the one active (in browser input) - function activeRoute(routeName) { - return window.location.href.indexOf(routeName) > -1 ? true : false; - } - - const { color, logo, image, logoText, routes } = props; - var links = ( - - {routes.map((prop, key) => { - var activePro = ' '; - var listItemClasses; - listItemClasses = classNames({ - [' ' + classes[color]]: activeRoute(prop.layout + prop.path), - }); - const whiteFontClasses = classNames({ - [' ' + classes.whiteFont]: activeRoute(prop.layout + prop.path), - }); - return ( - - - {typeof prop.icon === 'string' ? ( - - {prop.icon} - - ) : ( - - )} - - - - ); - })} - - ); - var brand = ( -
- - logo - -
- ); - return ( -
- - - {brand} -
- {props.rtlActive ? : } - {links} -
- {image !== undefined ? ( -
- ) : null} - - - - - {brand} -
{links}
- {image !== undefined ? ( -
- ) : null} - - -
- ); -} - -Sidebar.propTypes = { - rtlActive: PropTypes.bool, - handleDrawerToggle: PropTypes.func, - bgColor: PropTypes.oneOf(['purple', 'blue', 'green', 'orange', 'red']), - logo: PropTypes.string, - image: PropTypes.string, - logoText: PropTypes.string, - routes: PropTypes.arrayOf(PropTypes.object), - open: PropTypes.bool, -}; diff --git a/src/components/pages/AdminPage/components/Snackbar/Snackbar.js b/src/components/pages/AdminPage/components/Snackbar/Snackbar.js deleted file mode 100755 index 65217290..00000000 --- a/src/components/pages/AdminPage/components/Snackbar/Snackbar.js +++ /dev/null @@ -1,78 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import IconButton from '@material-ui/core/IconButton'; -import Snack from '@material-ui/core/Snackbar'; -// @material-ui/core components -import { makeStyles } from '@material-ui/core/styles'; -// @material-ui/icons -import Close from '@material-ui/icons/Close'; -import classNames from 'classnames'; - -// core components -import styles from '../../assets/jss/material-dashboard-react/components/snackbarContentStyle'; - -const useStyles = makeStyles (styles); - -export default function Snackbar (props) { - const classes = useStyles (); - const { - message, color, close, icon, place, open, rtlActive, - } = props; - let action = []; - const messageClasses = classNames ({ - [classes.iconMessage]: icon !== undefined, - }); - if (close !== undefined) { - action = [ - props.closeNotification ()} - > - - , - ]; - } - return ( - - {icon !== undefined ? : null} - {message} -
- )} - action={action} - ContentProps={{ - classes: { - root: `${classes.root} ${classes[color]}`, - message: classes.message, - action: classNames ({ [classes.actionRTL]: rtlActive }), - }, - }} - /> - ); -} - -Snackbar.propTypes = { - message: PropTypes.node.isRequired, - color: PropTypes.oneOf (['info', 'success', 'warning', 'danger', 'primary']), - close: PropTypes.bool, - // eslint-disable-next-line react/forbid-prop-types - icon: PropTypes.object, - place: PropTypes.oneOf (['tl', 'tr', 'tc', 'br', 'bl', 'bc']), - open: PropTypes.bool, - rtlActive: PropTypes.bool, - closeNotification: PropTypes.func, -}; diff --git a/src/components/pages/AdminPage/components/Snackbar/SnackbarContent.js b/src/components/pages/AdminPage/components/Snackbar/SnackbarContent.js deleted file mode 100755 index c5fe218d..00000000 --- a/src/components/pages/AdminPage/components/Snackbar/SnackbarContent.js +++ /dev/null @@ -1,62 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import IconButton from '@material-ui/core/IconButton'; -import Snack from '@material-ui/core/SnackbarContent'; -// @material-ui/core components -import { makeStyles } from '@material-ui/core/styles'; -// @material-ui/icons -import Close from '@material-ui/icons/Close'; -import classNames from 'classnames'; - -// core components -import styles from '../../assets/jss/material-dashboard-react/components/snackbarContentStyle'; - -const useStyles = makeStyles (styles); - -export default function SnackbarContent (props) { - const classes = useStyles (); - const { - message, color, close, icon, rtlActive, - } = props; - let action = []; - const messageClasses = classNames ({ - [classes.iconMessage]: icon !== undefined, - }); - if (close !== undefined) { - action = [ - - - , - ]; - } - return ( - - {icon !== undefined ? : null} - {message} -
- )} - classes={{ - root: `${classes.root} ${classes[color]}`, - message: classes.message, - action: classNames ({ [classes.actionRTL]: rtlActive }), - }} - action={action} - /> - ); -} - -SnackbarContent.propTypes = { - message: PropTypes.node.isRequired, - color: PropTypes.oneOf (['info', 'success', 'warning', 'danger', 'primary']), - close: PropTypes.bool, - // eslint-disable-next-line react/forbid-prop-types - icon: PropTypes.object, - rtlActive: PropTypes.bool, -}; diff --git a/src/components/pages/AdminPage/components/Table/Table.js b/src/components/pages/AdminPage/components/Table/Table.js deleted file mode 100755 index a2899642..00000000 --- a/src/components/pages/AdminPage/components/Table/Table.js +++ /dev/null @@ -1,68 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -// @material-ui/core components -import { makeStyles } from '@material-ui/core/styles'; -import Table from '@material-ui/core/Table'; -import TableBody from '@material-ui/core/TableBody'; -import TableCell from '@material-ui/core/TableCell'; -import TableHead from '@material-ui/core/TableHead'; -import TableRow from '@material-ui/core/TableRow'; - -// core components -import styles from '../../assets/jss/material-dashboard-react/components/tableStyle'; - -const useStyles = makeStyles (styles); - -export default function CustomTable (props) { - const classes = useStyles (); - const { tableHead, tableData, tableHeaderColor } = props; - return ( -
-
- {tableHead !== undefined ? ( - - - {tableHead.map ((prop, key) => ( - - {prop} - - ))} - - - ) : null} - - {tableData.map ((prop, key) => ( - - {prop.map ((prop, key) => ( - - {prop} - - ))} - - ))} - -
-
- ); -} - -CustomTable.defaultProps = { - tableHeaderColor: 'gray', -}; - -CustomTable.propTypes = { - tableHeaderColor: PropTypes.oneOf ([ - 'warning', - 'primary', - 'danger', - 'success', - 'info', - 'rose', - 'gray', - ]), - tableHead: PropTypes.arrayOf (PropTypes.string), - tableData: PropTypes.arrayOf (PropTypes.arrayOf (PropTypes.string)), -}; diff --git a/src/components/pages/AdminPage/components/Tasks/Tasks.js b/src/components/pages/AdminPage/components/Tasks/Tasks.js deleted file mode 100755 index e7bb5a32..00000000 --- a/src/components/pages/AdminPage/components/Tasks/Tasks.js +++ /dev/null @@ -1,110 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import Checkbox from '@material-ui/core/Checkbox'; -import IconButton from '@material-ui/core/IconButton'; -// @material-ui/core components -import { makeStyles } from '@material-ui/core/styles'; -import Table from '@material-ui/core/Table'; -import TableBody from '@material-ui/core/TableBody'; -import TableCell from '@material-ui/core/TableCell'; -import TableRow from '@material-ui/core/TableRow'; -import Tooltip from '@material-ui/core/Tooltip'; -import Check from '@material-ui/icons/Check'; -import Close from '@material-ui/icons/Close'; -// @material-ui/icons -import Edit from '@material-ui/icons/Edit'; -import classnames from 'classnames'; - -// core components -import styles from '../../assets/jss/material-dashboard-react/components/tasksStyle'; - -const useStyles = makeStyles (styles); - -export default function Tasks (props) { - const classes = useStyles (); - const [checked, setChecked] = React.useState ([...props.checkedIndexes]); - const handleToggle = value => { - const currentIndex = checked.indexOf (value); - const newChecked = [...checked]; - if (currentIndex === -1) { - newChecked.push (value); - } else { - newChecked.splice (currentIndex, 1); - } - setChecked (newChecked); - }; - const { tasksIndexes, tasks, rtlActive } = props; - const tableCellClasses = classnames (classes.tableCell, { - [classes.tableCellRTL]: rtlActive, - }); - return ( - - - {tasksIndexes.map (value => ( - - - handleToggle (value)} - checkedIcon={} - icon={} - classes={{ - checked: classes.checked, - root: classes.root, - }} - /> - - {tasks[value]} - - - - - - - - - - - - - - ))} - -
- ); -} - -Tasks.propTypes = { - tasksIndexes: PropTypes.arrayOf (PropTypes.number), - tasks: PropTypes.arrayOf (PropTypes.node), - rtlActive: PropTypes.bool, - // eslint-disable-next-line react/forbid-prop-types - checkedIndexes: PropTypes.array, -}; diff --git a/src/components/pages/AdminPage/components/Typography/Danger.js b/src/components/pages/AdminPage/components/Typography/Danger.js deleted file mode 100755 index 2e76e66f..00000000 --- a/src/components/pages/AdminPage/components/Typography/Danger.js +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -// @material-ui/core components -import { makeStyles } from '@material-ui/core/styles'; - -// core components -import styles from '../../assets/jss/material-dashboard-react/components/typographyStyle'; - -const useStyles = makeStyles (styles); - -export default function Danger (props) { - const classes = useStyles (); - const { children } = props; - return ( -
- {children} -
- ); -} - -Danger.propTypes = { - children: PropTypes.node, -}; diff --git a/src/components/pages/AdminPage/components/Typography/Info.js b/src/components/pages/AdminPage/components/Typography/Info.js deleted file mode 100755 index e9eea628..00000000 --- a/src/components/pages/AdminPage/components/Typography/Info.js +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -// @material-ui/core components -import { makeStyles } from '@material-ui/core/styles'; - -// core components -import styles from '../../assets/jss/material-dashboard-react/components/typographyStyle'; - -const useStyles = makeStyles (styles); - -export default function Info (props) { - const classes = useStyles (); - const { children } = props; - return ( -
- {children} -
- ); -} - -Info.propTypes = { - children: PropTypes.node, -}; diff --git a/src/components/pages/AdminPage/components/Typography/Muted.js b/src/components/pages/AdminPage/components/Typography/Muted.js deleted file mode 100755 index 572b2cb1..00000000 --- a/src/components/pages/AdminPage/components/Typography/Muted.js +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -// @material-ui/core components -import { makeStyles } from '@material-ui/core/styles'; - -// core components -import styles from '../../assets/jss/material-dashboard-react/components/typographyStyle'; - -const useStyles = makeStyles (styles); - -export default function Muted (props) { - const classes = useStyles (); - const { children } = props; - return ( -
- {children} -
- ); -} - -Muted.propTypes = { - children: PropTypes.node, -}; diff --git a/src/components/pages/AdminPage/components/Typography/Primary.js b/src/components/pages/AdminPage/components/Typography/Primary.js deleted file mode 100755 index bdce435b..00000000 --- a/src/components/pages/AdminPage/components/Typography/Primary.js +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -// @material-ui/core components -import { makeStyles } from '@material-ui/core/styles'; - -// core components -import styles from '../../assets/jss/material-dashboard-react/components/typographyStyle'; - -const useStyles = makeStyles (styles); - -export default function Primary (props) { - const classes = useStyles (); - const { children } = props; - return ( -
- {children} -
- ); -} - -Primary.propTypes = { - children: PropTypes.node, -}; diff --git a/src/components/pages/AdminPage/components/Typography/Quote.js b/src/components/pages/AdminPage/components/Typography/Quote.js deleted file mode 100755 index 4ba9cb5c..00000000 --- a/src/components/pages/AdminPage/components/Typography/Quote.js +++ /dev/null @@ -1,25 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -// @material-ui/core components -import { makeStyles } from '@material-ui/core/styles'; - -// core components -import styles from '../../assets/jss/material-dashboard-react/components/typographyStyle'; - -const useStyles = makeStyles (styles); - -export default function Quote (props) { - const classes = useStyles (); - const { text, author } = props; - return ( -
-

{text}

- {author} -
- ); -} - -Quote.propTypes = { - text: PropTypes.node, - author: PropTypes.node, -}; diff --git a/src/components/pages/AdminPage/components/Typography/Success.js b/src/components/pages/AdminPage/components/Typography/Success.js deleted file mode 100755 index e6c59453..00000000 --- a/src/components/pages/AdminPage/components/Typography/Success.js +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -// @material-ui/core components -import { makeStyles } from '@material-ui/core/styles'; - -// core components -import styles from '../../assets/jss/material-dashboard-react/components/typographyStyle'; - -const useStyles = makeStyles (styles); - -export default function Success (props) { - const classes = useStyles (); - const { children } = props; - return ( -
- {children} -
- ); -} - -Success.propTypes = { - children: PropTypes.node, -}; diff --git a/src/components/pages/AdminPage/components/Typography/Warning.js b/src/components/pages/AdminPage/components/Typography/Warning.js deleted file mode 100755 index b11f9f11..00000000 --- a/src/components/pages/AdminPage/components/Typography/Warning.js +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -// @material-ui/core components -import { makeStyles } from '@material-ui/core/styles'; - -// core components -import styles from '../../assets/jss/material-dashboard-react/components/typographyStyle'; - -const useStyles = makeStyles (styles); - -export default function Warning (props) { - const classes = useStyles (); - const { children } = props; - return ( -
- {children} -
- ); -} - -Warning.propTypes = { - children: PropTypes.node, -}; diff --git a/src/components/pages/AdminPage/index.js b/src/components/pages/AdminPage/index.js deleted file mode 100644 index a4450582..00000000 --- a/src/components/pages/AdminPage/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Admin'; diff --git a/src/components/pages/AdminPage/propTypes.js b/src/components/pages/AdminPage/propTypes.js deleted file mode 100644 index e69de29b..00000000 diff --git a/src/components/pages/AdminPage/tableIcons.js b/src/components/pages/AdminPage/tableIcons.js deleted file mode 100644 index 60cb949e..00000000 --- a/src/components/pages/AdminPage/tableIcons.js +++ /dev/null @@ -1,38 +0,0 @@ -import React, { forwardRef } from 'react'; -import AddBox from '@material-ui/icons/AddBox'; -import ArrowDownward from '@material-ui/icons/ArrowDownward'; -import Check from '@material-ui/icons/Check'; -import ChevronLeft from '@material-ui/icons/ChevronLeft'; -import ChevronRight from '@material-ui/icons/ChevronRight'; -import Clear from '@material-ui/icons/Clear'; -import DeleteOutline from '@material-ui/icons/DeleteOutline'; -import Edit from '@material-ui/icons/Edit'; -import FilterList from '@material-ui/icons/FilterList'; -import FirstPage from '@material-ui/icons/FirstPage'; -import LastPage from '@material-ui/icons/LastPage'; -import Remove from '@material-ui/icons/Remove'; -import SaveAlt from '@material-ui/icons/SaveAlt'; -import Search from '@material-ui/icons/Search'; -import ViewColumn from '@material-ui/icons/ViewColumn'; - -const tableIcons = { - Add: forwardRef ((props, ref) => ), - Check: forwardRef ((props, ref) => ), - Clear: forwardRef ((props, ref) => ), - Delete: forwardRef ((props, ref) => ), - DetailPanel: forwardRef ((props, ref) => ), - Edit: forwardRef ((props, ref) => ), - Export: forwardRef ((props, ref) => ), - Filter: forwardRef ((props, ref) => ), - FirstPage: forwardRef ((props, ref) => ), - LastPage: forwardRef ((props, ref) => ), - NextPage: forwardRef ((props, ref) => ), - PreviousPage: forwardRef ((props, ref) => ), - ResetSearch: forwardRef ((props, ref) => ), - Search: forwardRef ((props, ref) => ), - SortArrow: forwardRef ((props, ref) => ), - ThirdStateCheck: forwardRef ((props, ref) => ), - ViewColumn: forwardRef ((props, ref) => ), -}; - -export default tableIcons; diff --git a/src/components/pages/AdminPage/variables/charts.js b/src/components/pages/AdminPage/variables/charts.js deleted file mode 100644 index 9e7767eb..00000000 --- a/src/components/pages/AdminPage/variables/charts.js +++ /dev/null @@ -1,190 +0,0 @@ -// ############################## -// // // javascript library for creating charts -// ############################# -const Chartist = require ('chartist'); - -// ############################## -// // // variables used to create animation on charts -// ############################# -const delays = 80; -const durations = 500; -const delays2 = 80; -const durations2 = 500; - -// ############################## -// // // Daily Sales -// ############################# - -const dailySalesChart = { - data: { - labels: ['M', 'T', 'W', 'T', 'F', 'S', 'S'], - series: [[12, 17, 7, 17, 23, 18, 38]], - }, - options: { - lineSmooth: Chartist.Interpolation.cardinal ({ - tension: 0, - }), - low: 0, - high: 50, // creative tim: we recommend you to set the high sa the biggest value + something for a better look - chartPadding: { - top: 0, - right: 0, - bottom: 0, - left: 0, - }, - }, - // for animation - animation: { - draw (data) { - if (data.type === 'line' || data.type === 'area') { - data.element.animate ({ - d: { - begin: 600, - dur: 700, - from: data.path - .clone () - .scale (1, 0) - .translate (0, data.chartRect.height ()) - .stringify (), - to: data.path.clone ().stringify (), - easing: Chartist.Svg.Easing.easeOutQuint, - }, - }); - } else if (data.type === 'point') { - data.element.animate ({ - opacity: { - begin: (data.index + 1) * delays, - dur: durations, - from: 0, - to: 1, - easing: 'ease', - }, - }); - } - }, - }, -}; - -// ############################## -// // // Email Subscriptions -// ############################# - -const emailsSubscriptionChart = { - data: { - labels: [ - 'Jan', - 'Feb', - 'Mar', - 'Apr', - 'Mai', - 'Jun', - 'Jul', - 'Aug', - 'Sep', - 'Oct', - 'Nov', - 'Dec', - ], - series: [[542, 443, 320, 780, 553, 453, 326, 434, 568, 610, 756, 895]], - }, - options: { - axisX: { - showGrid: false, - }, - low: 0, - high: 1000, - chartPadding: { - top: 0, - right: 5, - bottom: 0, - left: 0, - }, - }, - responsiveOptions: [ - [ - 'screen and (max-width: 640px)', - { - seriesBarDistance: 5, - axisX: { - labelInterpolationFnc (value) { - return value[0]; - }, - }, - }, - ], - ], - animation: { - draw (data) { - if (data.type === 'bar') { - data.element.animate ({ - opacity: { - begin: (data.index + 1) * delays2, - dur: durations2, - from: 0, - to: 1, - easing: 'ease', - }, - }); - } - }, - }, -}; - -// ############################## -// // // Completed Tasks -// ############################# - -const completedTasksChart = { - data: { - labels: ['12am', '3pm', '6pm', '9pm', '12pm', '3am', '6am', '9am'], - series: [[230, 750, 450, 300, 280, 240, 200, 190]], - }, - options: { - lineSmooth: Chartist.Interpolation.cardinal ({ - tension: 0, - }), - low: 0, - high: 1000, // creative tim: we recommend you to set the high sa the biggest value + something for a better look - chartPadding: { - top: 0, - right: 0, - bottom: 0, - left: 0, - }, - }, - animation: { - draw (data) { - if (data.type === 'line' || data.type === 'area') { - data.element.animate ({ - d: { - begin: 600, - dur: 700, - from: data.path - .clone () - .scale (1, 0) - .translate (0, data.chartRect.height ()) - .stringify (), - to: data.path.clone ().stringify (), - easing: Chartist.Svg.Easing.easeOutQuint, - }, - }); - } else if (data.type === 'point') { - data.element.animate ({ - opacity: { - begin: (data.index + 1) * delays, - dur: durations, - from: 0, - to: 1, - easing: 'ease', - }, - }); - } - }, - }, -}; - -module.exports = { - dailySalesChart, - emailsSubscriptionChart, - completedTasksChart, -}; diff --git a/src/components/pages/AdminPage/variables/general.js b/src/components/pages/AdminPage/variables/general.js deleted file mode 100644 index cd26eeeb..00000000 --- a/src/components/pages/AdminPage/variables/general.js +++ /dev/null @@ -1,26 +0,0 @@ -// ############################## -// // // Tasks for TasksCard - see Dashboard view -// ############################# - -const bugs = [ - 'Sign contract for "What are conference organizers afraid of?"', - 'Lines From Great Russian Literature? Or E-mails From My Boss?', - 'Flooded: One year later, assessing what was lost and what was found when a ravaging rain swept through metro Detroit', - 'Create 4 Invisible User Experiences you Never Knew About', -]; -const website = [ - 'Flooded: One year later, assessing what was lost and what was found when a ravaging rain swept through metro Detroit', - 'Sign contract for "What are conference organizers afraid of?"', -]; -const server = [ - 'Lines From Great Russian Literature? Or E-mails From My Boss?', - 'Flooded: One year later, assessing what was lost and what was found when a ravaging rain swept through metro Detroit', - 'Sign contract for "What are conference organizers afraid of?"', -]; - -module.exports = { - // these 3 are used to create the tasks lists in TasksCard - Dashboard view - bugs, - website, - server, -}; diff --git a/src/components/pages/ApiPage/ApiPage.js b/src/components/pages/ApiPage/ApiPage.js index b3076828..02f09b5d 100644 --- a/src/components/pages/ApiPage/ApiPage.js +++ b/src/components/pages/ApiPage/ApiPage.js @@ -1,25 +1,26 @@ -import React, { useEffect } from 'react'; -import { Switch, useRouteMatch } from 'react-router-dom'; +import React, { useEffect } from "react"; +import { Switch, useRouteMatch } from "react-router-dom"; -import { PublicRoute } from 'hoc/AuthRoutes'; -import axios from 'lib/axios'; +import { PublicRoute } from "hoc/AuthRoutes"; +import axios from "lib/axios"; const Login = () => { - useEffect (() => { - axios.get ('/auth/loginApi') - .then (data => { + useEffect(() => { + axios + .get("/auth/loginApi") + .then((data) => { window.location.href = data.url; }) - .catch (error => { - console.error (error); - alert ('로그인에 실패하였습니다.'); + .catch((error) => { + console.error(error); + alert("로그인에 실패하였습니다."); }); }, []); return null; }; const ApiPage = () => { - const { path } = useRouteMatch (); + const { path } = useRouteMatch(); return ( diff --git a/src/components/pages/ApiPage/index.js b/src/components/pages/ApiPage/index.js index 24c1ecd3..80029226 100644 --- a/src/components/pages/ApiPage/index.js +++ b/src/components/pages/ApiPage/index.js @@ -1 +1 @@ -export { default } from './ApiPage'; +export { default } from "./ApiPage"; diff --git a/src/components/pages/AuthPage/AuthPage.container.js b/src/components/pages/AuthPage/AuthPage.container.js index ff707194..de70626e 100644 --- a/src/components/pages/AuthPage/AuthPage.container.js +++ b/src/components/pages/AuthPage/AuthPage.container.js @@ -1,16 +1,16 @@ -import React, { PureComponent } from 'react'; -import { connect } from 'react-redux'; +import React, { PureComponent } from "react"; +import { connect } from "react-redux"; -import AuthPage from './AuthPage'; +import AuthPage from "./AuthPage"; class AuthPageContainer extends PureComponent { - render () { + render() { return ; } } -const mapStateToProps = state => ({}); +const mapStateToProps = (state) => ({}); -const mapDispatchToProps = dispatch => ({}); +const mapDispatchToProps = (dispatch) => ({}); -export default connect (mapStateToProps, mapDispatchToProps) (AuthPageContainer); +export default connect(mapStateToProps, mapDispatchToProps)(AuthPageContainer); diff --git a/src/components/pages/AuthPage/AuthPage.js b/src/components/pages/AuthPage/AuthPage.js index d278b006..32e7dec6 100644 --- a/src/components/pages/AuthPage/AuthPage.js +++ b/src/components/pages/AuthPage/AuthPage.js @@ -1,12 +1,12 @@ -import React, { PureComponent } from 'react'; -import { Redirect, Route, Switch } from 'react-router-dom'; +import React, { PureComponent } from "react"; +import { Redirect, Route, Switch } from "react-router-dom"; -import { LoginPage } from 'pages'; +import { LoginPage } from "components/pages"; -import AuthPageWrapper from './AuthPage.styled'; +import AuthPageWrapper from "./AuthPage.styled"; class AuthPage extends PureComponent { - render () { + render() { return ( diff --git a/src/components/pages/AuthPage/AuthPage.stories.js b/src/components/pages/AuthPage/AuthPage.stories.js index 05591d07..25bc5841 100644 --- a/src/components/pages/AuthPage/AuthPage.stories.js +++ b/src/components/pages/AuthPage/AuthPage.stories.js @@ -1,8 +1,8 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; +import React from "react"; +import { storiesOf } from "@storybook/react"; -import AuthPage from './index'; +import AuthPage from "./index"; -storiesOf ('pages/AuthPage', module).add ('Default', () => , { - notes: '', +storiesOf("pages/AuthPage", module).add("Default", () => , { + notes: "", }); diff --git a/src/components/pages/AuthPage/AuthPage.styled.js b/src/components/pages/AuthPage/AuthPage.styled.js index 2e5118c6..9b0085c2 100644 --- a/src/components/pages/AuthPage/AuthPage.styled.js +++ b/src/components/pages/AuthPage/AuthPage.styled.js @@ -1,4 +1,4 @@ -import styled from 'styled-components'; +import styled from "styled-components"; const AuthPageWrapper = styled.div``; diff --git a/src/components/pages/AuthPage/index.js b/src/components/pages/AuthPage/index.js index ec67a148..d3df2596 100644 --- a/src/components/pages/AuthPage/index.js +++ b/src/components/pages/AuthPage/index.js @@ -1 +1 @@ -export { default } from './AuthPage.container'; +export { default } from "./AuthPage.container"; diff --git a/src/components/pages/HomePage/HomePage.container.js b/src/components/pages/HomePage/HomePage.container.js index 7c35f2aa..25723820 100644 --- a/src/components/pages/HomePage/HomePage.container.js +++ b/src/components/pages/HomePage/HomePage.container.js @@ -1,21 +1,21 @@ -import React, { PureComponent } from 'react'; -import { connect } from 'react-redux'; -import get from 'lodash.get'; +import React, { PureComponent } from "react"; +import { connect } from "react-redux"; +import get from "lodash.get"; -import { getZaboList } from 'store/reducers/zabo'; +import { getZaboList } from "store/reducers/zabo"; -import HomePage from './HomePage'; +import HomePage from "./HomePage"; // deliver states(Redux) as props to the HomePage component class HomePageContainer extends PureComponent { - render () { + render() { return ; } } // Subscribe to the Redux "state" -const mapStateToProps = state => ({ - zaboList: get (state, ['zabo', 'zaboList']), +const mapStateToProps = (state) => ({ + zaboList: get(state, ["zabo", "zaboList"]), }); // HomePage 에서 변경 사항이 생긴다면 널리 알려라. @@ -24,4 +24,4 @@ const mapDispatchToProps = { }; // index.js 가 HomePage 를 import 하는 것이 아닌, HomePage -export default connect (mapStateToProps, mapDispatchToProps) (HomePageContainer); +export default connect(mapStateToProps, mapDispatchToProps)(HomePageContainer); diff --git a/src/components/pages/HomePage/HomePage.js b/src/components/pages/HomePage/HomePage.js index fff17b9d..ffaf4d70 100644 --- a/src/components/pages/HomePage/HomePage.js +++ b/src/components/pages/HomePage/HomePage.js @@ -1,9 +1,9 @@ -import React from 'react'; +import React from "react"; -import Header from 'templates/Header'; -import ZaboList from 'templates/ZaboList'; +import Header from "components/templates/Header"; +import ZaboList from "components/templates/ZaboList"; -import HomePageWrapper from './HomePage.styled'; +import HomePageWrapper from "./HomePage.styled"; const HomePage = () => ( diff --git a/src/components/pages/HomePage/HomePage.stories.js b/src/components/pages/HomePage/HomePage.stories.js index 88449770..c93203a8 100644 --- a/src/components/pages/HomePage/HomePage.stories.js +++ b/src/components/pages/HomePage/HomePage.stories.js @@ -1,9 +1,9 @@ /* eslint-disable */ -import React from 'react'; -import { storiesOf } from '@storybook/react'; +import React from "react"; +import { storiesOf } from "@storybook/react"; -import HomePage from './index'; +import HomePage from "./index"; -storiesOf ('pages/HomePage', module).add ('Default', () => , { - notes: '', +storiesOf("pages/HomePage", module).add("Default", () => , { + notes: "", }); diff --git a/src/components/pages/HomePage/HomePage.styled.js b/src/components/pages/HomePage/HomePage.styled.js index 3b06e53d..b5ed0f53 100644 --- a/src/components/pages/HomePage/HomePage.styled.js +++ b/src/components/pages/HomePage/HomePage.styled.js @@ -1,4 +1,4 @@ -import styled from 'styled-components'; +import styled from "styled-components"; /* ============ Wrapper ============ */ const HomePageWrapper = styled.div` @@ -16,7 +16,7 @@ const HomePageWrapper = styled.div` * 4: 1020px => 1060 ~ */ -/* @media (min-width: 0px) and (max-width: 530px) { + /* @media (min-width: 0px) and (max-width: 530px) { !* .container width auto with padding *! } @media (min-width: 530px) and (max-width: 800px) { diff --git a/src/components/pages/HomePage/index.js b/src/components/pages/HomePage/index.js index 360953e2..52b471b8 100644 --- a/src/components/pages/HomePage/index.js +++ b/src/components/pages/HomePage/index.js @@ -1 +1 @@ -export { default } from './HomePage.container'; +export { default } from "./HomePage.container"; diff --git a/src/components/pages/LandingPage/LandingPage.js b/src/components/pages/LandingPage/LandingPage.js index 942d1f44..5fe7157e 100644 --- a/src/components/pages/LandingPage/LandingPage.js +++ b/src/components/pages/LandingPage/LandingPage.js @@ -1,84 +1,86 @@ -import React, { - useEffect, useReducer, useState, -} from 'react'; -import PropTypes from 'prop-types'; -import { Link, useHistory } from 'react-router-dom'; -import { useDispatch, useSelector } from 'react-redux'; -import Slider from 'react-slick'; -import Tooltip from '@material-ui/core/Tooltip'; -import get from 'lodash.get'; -import moment from 'moment'; -import useSWR from 'swr'; +import React, { useEffect, useReducer, useState } from "react"; +import PropTypes from "prop-types"; +import { Link, useHistory } from "react-router-dom"; +import { useDispatch, useSelector } from "react-redux"; +import Slider from "react-slick"; +import Tooltip from "@material-ui/core/Tooltip"; +import get from "lodash.get"; +import moment from "moment"; +import useSWR from "swr"; -import { CategoryListW, CategoryW } from 'atoms/Category'; -import SVG from 'atoms/SVG'; -import TwoCol from 'atoms/TwoCol'; -import ScrollBtn from 'molecules/ScrollBtn'; -import ZaboCard from 'organisms/ZaboCard'; -import Header from 'templates/Header'; -import ZaboList from 'templates/ZaboList'; +import { CategoryListW, CategoryW } from "components/atoms/Category"; +import SVG from "components/atoms/SVG"; +import TwoCol from "components/atoms/TwoCol"; +import ScrollBtn from "components/molecules/ScrollBtn"; +import ZaboCard from "components/organisms/ZaboCard"; +import Header from "components/templates/Header"; +import ZaboList from "components/templates/ZaboList"; -import { getHotZaboList as getHotZaboListAction } from 'store/reducers/zabo'; -import { getRecommendedGroups } from 'lib/api/group'; -import { getDeadlineZaboList } from 'lib/api/zabo'; -import { isAuthedSelector, pushWithAuth } from 'lib/utils'; +import { getHotZaboList as getHotZaboListAction } from "store/reducers/zabo"; +import { getRecommendedGroups } from "lib/api/group"; +import { getDeadlineZaboList } from "lib/api/zabo"; +import { isAuthedSelector, pushWithAuth } from "lib/utils"; -import helpIcon from 'static/icon/help.svg'; -import bannerPoster from 'static/images/banner_poster.jpg'; -import bannerPosterWebp from 'static/images/banner_poster.webp'; -import bannerSparcs from 'static/images/banner_sparcs.jpg'; -import bannerSparcsWebp from 'static/images/banner_sparcs.webp'; -import leftArrow from 'static/images/leftScroll.png'; -import rightArrow from 'static/images/rightScroll.png'; +import helpIcon from "static/icon/help.svg"; +import bannerPoster from "static/images/banner_poster.jpg"; +import bannerPosterWebp from "static/images/banner_poster.webp"; +import bannerSparcs from "static/images/banner_sparcs.jpg"; +import bannerSparcsWebp from "static/images/banner_sparcs.webp"; +import leftArrow from "static/images/leftScroll.png"; +import rightArrow from "static/images/rightScroll.png"; import LandingPageWrapper, { BannersW, - BannerW, ButtonW, + BannerW, + ButtonW, CategoryBannerW, CategoryNavW, Container, - GroupBoxW, RecommendsTitleW, + GroupBoxW, + RecommendsTitleW, RecommendsW, TopBannerW, - UpcomingW, ZaboListTitleW, ZaboListW, -} from './LandingPage.styled'; + UpcomingW, + ZaboListTitleW, + ZaboListW, +} from "./LandingPage.styled"; const categories = [ - 'all', - 'hangsa', - 'performance', - 'festival', - 'seminar', - 'education', - 'meeting', - 'event', - 'contest', - 'exhibition', - 'notice', - 'recruit', - 'hire', - 'volunteer', - 'openclub', - 'demoday', + "all", + "hangsa", + "performance", + "festival", + "seminar", + "education", + "meeting", + "event", + "contest", + "exhibition", + "notice", + "recruit", + "hire", + "volunteer", + "openclub", + "demoday", ]; const categoriesK = { - all: '전체보기', - hangsa: '행사', - performance: '공연', - festival: '축제', - seminar: '세미나', - education: '교육', - meeting: '모임', - event: '이벤트', - contest: '공모전', - exhibition: '전시', - notice: '공지', - recruit: '모집', - hire: '채용', - volunteer: '봉사', - openclub: '오픈동방', - demoday: '데모데이', + all: "전체보기", + hangsa: "행사", + performance: "공연", + festival: "축제", + seminar: "세미나", + education: "교육", + meeting: "모임", + event: "이벤트", + contest: "공모전", + exhibition: "전시", + notice: "공지", + recruit: "모집", + hire: "채용", + volunteer: "봉사", + openclub: "오픈동방", + demoday: "데모데이", }; const swrOpts = { @@ -87,8 +89,8 @@ const swrOpts = { }; const TopBanner = () => { - const history = useHistory (); - const isAuthed = useSelector (isAuthedSelector); + const history = useHistory(); + const isAuthed = useSelector(isAuthedSelector); return ( @@ -98,7 +100,9 @@ const TopBanner = () => { { pushWithAuth ('/settings/group/apply', history, isAuthed); }} + onClick={(e) => { + pushWithAuth("/settings/group/apply", history, isAuthed); + }} >
신규 그룹 신청
@@ -106,8 +110,8 @@ const TopBanner = () => { { - pushWithAuth ('/zabo/upload', history, isAuthed); + onClick={(e) => { + pushWithAuth("/zabo/upload", history, isAuthed); }} >
자보 업로드
@@ -120,14 +124,13 @@ const TopBanner = () => { }; const Category = ({ category }) => ( - - - {categoriesK[category]} - + {categoriesK[category]} ); @@ -139,7 +142,7 @@ const CategoryBanner = () => ( - {categories.map (category => ( + {categories.map((category) => ( ))} @@ -148,78 +151,79 @@ const CategoryBanner = () => ( ); -const ArrowLeft = props => ( - +const ArrowLeft = (props) => ( + ); -const ArrowRight = props => ( - +const ArrowRight = (props) => ( + ); const SlickItem = ({ zabo, width }) => ( {width < 640 ? ( - + ) : ( - + )} ); -const twoDigits = number => { +const twoDigits = (number) => { if (number >= 0 && number < 10) return `0${number}`; return number; }; const CountDown = ({ initialValue }) => { - const [tick, dispatch] = useReducer ((state, action) => { - if (action.type === 'decrease') return state - 1; - if (action.type === 'set') return action.payload; + const [tick, dispatch] = useReducer((state, action) => { + if (action.type === "decrease") return state - 1; + if (action.type === "set") return action.payload; return 0; }, 0); - useEffect (() => { - const timer = setInterval (() => dispatch ({ type: 'decrease' }), 1000); - return () => clearInterval (timer); + useEffect(() => { + const timer = setInterval(() => dispatch({ type: "decrease" }), 1000); + return () => clearInterval(timer); }, [initialValue]); - useEffect (() => { - dispatch ({ type: 'set', payload: initialValue / 1000 }); + useEffect(() => { + dispatch({ type: "set", payload: initialValue / 1000 }); }, [initialValue]); - const days = Math.floor (tick / 86400); - const hours = Math.floor (tick / 3600) % 24; - const mins = Math.floor (tick / 60) % 60; - const secs = Math.floor (tick % 60); - return
{!!days && days}{!!days && } {`${twoDigits (hours)}:${twoDigits (mins)}:${twoDigits (secs)}`}
; + const days = Math.floor(tick / 86400); + const hours = Math.floor(tick / 3600) % 24; + const mins = Math.floor(tick / 60) % 60; + const secs = Math.floor(tick % 60); + return ( +
+ {!!days && days} + {!!days && } {`${twoDigits(hours)}:${twoDigits(mins)}:${twoDigits(secs)}`} +
+ ); }; const Upcoming = () => { - const history = useHistory (); - const [current, setCurrent] = useState (0); - const width = useSelector (state => get (state, ['app', 'windowSize', 'width'])); - const { data: zabos, zaboError } = useSWR ('/zabo/list/deadline', getDeadlineZaboList, swrOpts); + const history = useHistory(); + const [current, setCurrent] = useState(0); + const width = useSelector((state) => get(state, ["app", "windowSize", "width"])); + const { data: zabos, zaboError } = useSWR("/zabo/list/deadline", getDeadlineZaboList, swrOpts); if (!zabos) { return ( - - Loading... - + Loading... ); } if (!zabos.length) { - return ( - - - 현재 마감이 임박한 자보가 없습니다. - - - ); + return ""; } const settings = { @@ -240,24 +244,20 @@ const Upcoming = () => { const { _id, title, schedules } = currentZabo; const schedule = schedules[0]; const { type, title: scheduleTitle, startAt } = schedule; - const label = `${(type === '신청' ? '신청이 ' : '')}얼마 남지 않았어요`; - const startAtMoment = moment (startAt); - const timeLeft = startAtMoment.diff (moment ()); + const label = `${type === "신청" ? "신청이 " : ""}얼마 남지 않았어요`; + const startAtMoment = moment(startAt); + const timeLeft = startAtMoment.diff(moment()); return ( - - {scheduleTitle} - - - {label} - + {scheduleTitle} + {label} - history.push (`/zabo/${_id}`)}> + history.push(`/zabo/${_id}`)}> 자세히 보기 @@ -267,9 +267,11 @@ const Upcoming = () => { - {zabos ? zabos.map (zabo => ( - - )) :
none
} + {zabos ? ( + zabos.map((zabo) => ) + ) : ( +
none
+ )}
@@ -280,34 +282,42 @@ const Upcoming = () => { }; const Recommends = () => { - const dispatch = useDispatch (); - const getHotZaboList = () => dispatch (getHotZaboListAction ()); - const { data: zabos, zaboError } = useSWR ('/zabo/list/hot', getHotZaboList, swrOpts); - const { data: groups, groupError } = useSWR ('/group/recommends', getRecommendedGroups, swrOpts); + const dispatch = useDispatch(); + const getHotZaboList = () => dispatch(getHotZaboListAction()); + const { data: zabos, zaboError } = useSWR("/zabo/list/hot", getHotZaboList, swrOpts); + const { data: groups, groupError } = useSWR("/group/recommends", getRecommendedGroups, swrOpts); return ( - 인기 있는 자보 - + 인기 있는 자보 + recommendation guide - {zabos ? zabos.map (({ _id }) => ) : 'Loading'} + {zabos + ? zabos.map(({ _id }) => ) + : "Loading"} 이 그룹은 어때요? - {['동아리', '학생 단체', 'KAIST 부서', '스타트업'].map (cat => {cat})} + {["동아리", "학생 단체", "KAIST 부서", "스타트업"].map((cat) => ( + {cat} + ))} recommendation guide - {groups ? groups.map (group => ) - : 'Loading'} + {groups + ? groups.map((group) => ) + : "Loading"} @@ -316,23 +326,20 @@ const Recommends = () => { ); }; - export const Banners = () => { - const history = useHistory (); - const isAuthed = useSelector (isAuthedSelector); + const history = useHistory(); + const isAuthed = useSelector(isAuthedSelector); return ( - - 신규 그룹 신청하고 - - - 자보를 올려 쉽게 홍보하세요 - + 신규 그룹 신청하고 + 자보를 올려 쉽게 홍보하세요 { pushWithAuth ('/settings/group/apply', history, isAuthed); }} + onClick={(e) => { + pushWithAuth("/settings/group/apply", history, isAuthed); + }} color="red50" > 신규 그룹 신청 @@ -342,12 +349,8 @@ export const Banners = () => { - - 자보를 직접 만들고 싶다면? - - - SPARCS 지원 바로가기 - + 자보를 직접 만들고 싶다면? + SPARCS 지원 바로가기 지원하기 @@ -365,9 +368,7 @@ export const Banners = () => { const MainZaboList = () => ( - - 전체 자보 보기 - + 전체 자보 보기 diff --git a/src/components/pages/LandingPage/LandingPage.styled.js b/src/components/pages/LandingPage/LandingPage.styled.js index d803491c..3454e283 100644 --- a/src/components/pages/LandingPage/LandingPage.styled.js +++ b/src/components/pages/LandingPage/LandingPage.styled.js @@ -1,32 +1,32 @@ -import PropTypes from 'prop-types'; -import { Link } from 'react-router-dom'; -import styled, { css } from 'styled-components'; - -import ContainerAtom from 'atoms/Container'; -import TwoCol from 'atoms/TwoCol'; -import GroupBox from 'organisms/GroupBox'; - -import * as mixins from 'lib/mixins'; -import { media } from 'lib/utils/style'; - -import allIcon from 'static/icon/category/all.svg'; -import contestIcon from 'static/icon/category/contest.svg'; -import demodayIcon from 'static/icon/category/demoday.svg'; -import educationIcon from 'static/icon/category/education.svg'; -import eventIcon from 'static/icon/category/event.svg'; -import exhibitionIcon from 'static/icon/category/exhibition.svg'; -import festivalIcon from 'static/icon/category/festival.svg'; -import hangsaIcon from 'static/icon/category/hangsa.svg'; -import hireIcon from 'static/icon/category/hire.svg'; -import meetingIcon from 'static/icon/category/meeting.svg'; -import noticeIcon from 'static/icon/category/notice.svg'; -import openclubIcon from 'static/icon/category/openclub.svg'; -import performanceIcon from 'static/icon/category/performance.svg'; -import recruitIcon from 'static/icon/category/recruit.svg'; -import seminarIcon from 'static/icon/category/seminar.svg'; -import volunteerIcon from 'static/icon/category/volunteer.svg'; -import rightArrowIcon from 'static/icon/rightArrow.svg'; -import landingBackground from 'static/images/landing_background.jpg'; +import PropTypes from "prop-types"; +import { Link } from "react-router-dom"; +import styled, { css } from "styled-components"; + +import ContainerAtom from "components/atoms/Container"; +import TwoCol from "components/atoms/TwoCol"; +import GroupBox from "components/organisms/GroupBox"; + +import * as mixins from "lib/mixins"; +import { media } from "lib/utils/style"; + +import allIcon from "static/icon/category/all.svg"; +import contestIcon from "static/icon/category/contest.svg"; +import demodayIcon from "static/icon/category/demoday.svg"; +import educationIcon from "static/icon/category/education.svg"; +import eventIcon from "static/icon/category/event.svg"; +import exhibitionIcon from "static/icon/category/exhibition.svg"; +import festivalIcon from "static/icon/category/festival.svg"; +import hangsaIcon from "static/icon/category/hangsa.svg"; +import hireIcon from "static/icon/category/hire.svg"; +import meetingIcon from "static/icon/category/meeting.svg"; +import noticeIcon from "static/icon/category/notice.svg"; +import openclubIcon from "static/icon/category/openclub.svg"; +import performanceIcon from "static/icon/category/performance.svg"; +import recruitIcon from "static/icon/category/recruit.svg"; +import seminarIcon from "static/icon/category/seminar.svg"; +import volunteerIcon from "static/icon/category/volunteer.svg"; +import rightArrowIcon from "static/icon/rightArrow.svg"; +import landingBackground from "static/images/landing_background.jpg"; const categoryIcons = { allIcon, @@ -48,7 +48,7 @@ const categoryIcons = { rightArrowIcon, }; -export const Container = styled (ContainerAtom)` +export const Container = styled(ContainerAtom)` max-width: 1084px; scroll-behavior: smooth; `; @@ -64,8 +64,8 @@ export const TitleW = styled.div` font-weight: 800; font-size: 20px; line-height: 23px; - color: ${props => props.theme.gray90}; - ${media.tablet (css` + color: ${(props) => props.theme.gray90}; + ${media.tablet(css` margin-top: 0; font-size: 24px; line-height: 27px; @@ -77,21 +77,21 @@ export const TopBannerW = styled.div` margin: -55px 0 0; width: 100%; height: 349px; - background-color: rgb(13,26,31); - background-image - : url(${landingBackground}); + background-color: rgb(13, 26, 31); + background-image: url(${landingBackground}); background-repeat: no-repeat; background-size: cover; - + display: flex; flex-direction: column; ${Container} { flex-direction: column; } - - h1, h3 { + + h1, + h3 { font-size: 20px; - color: white; + color: white; } h1 { margin: 105px 0 0; @@ -104,7 +104,7 @@ export const TopBannerW = styled.div` a { width: 120px; } - ${media.tablet (css` + ${media.tablet(css` height: 520px; padding: 50px 0 0; h1 { @@ -132,15 +132,15 @@ export const TopBannerW = styled.div` `; const whiteBtn = css` - color: ${props => props.theme.white}; - border: 1px solid ${props => props.theme.white}; + color: ${(props) => props.theme.white}; + border: 1px solid ${(props) => props.theme.white}; background: rgba(255, 255, 255, 0.15); `; const mainBtn = css` - color: ${props => props.theme.main}; - border: 1px solid ${props => props.theme.main}; - background: ${props => props.theme.white}; + color: ${(props) => props.theme.main}; + border: 1px solid ${(props) => props.theme.main}; + background: ${(props) => props.theme.white}; `; const btnMixins = { @@ -155,11 +155,11 @@ export const ButtonW = styled.button` border-radius: 4px; color: white; ${mixins.flexCenter}; - ${props => btnMixins[props.color]}; + ${(props) => btnMixins[props.color]}; svg { margin-left: 4px; } - ${media.tablet (css` + ${media.tablet(css` height: 52px; font-size: 16px; padding: 0 16px; @@ -169,7 +169,7 @@ export const ButtonW = styled.button` `)}; `; ButtonW.propTypes = { - color: PropTypes.oneOf (['white', 'main']).isRequired, + color: PropTypes.oneOf(["white", "main"]).isRequired, }; TopBannerW.Buttons = styled.section` @@ -177,42 +177,42 @@ TopBannerW.Buttons = styled.section` ${ButtonW} { margin-left: 12px; } - ${media.tablet (css` + ${media.tablet(css` ${ButtonW} { margin-left: 20px; - } + } `)}; - + ${ButtonW}:first-child { margin-left: 0; } `; -export const CategoryNavW = styled (Link)` +export const CategoryNavW = styled(Link)` cursor: pointer; `; CategoryNavW.Image = styled.div` - background-image: ${props => css` + background-image: ${(props) => css` url(${categoryIcons[`${props.category}Icon`]}); `}; width: 48px; height: 48px; background-size: 48px 48px; - ${media.tablet (css` + ${media.tablet(css` width: 72px; height: 72px; - background-size: 72px 72px; + background-size: 72px 72px; `)}; `; CategoryNavW.Label = styled.div` - color: ${props => props.theme.gray90}; + color: ${(props) => props.theme.gray90}; font-size: 12px; line-height: 14px; margin-top: 8px; text-align: center; - ${media.tablet (css` + ${media.tablet(css` font-size: 18px; line-height: 20px; font-weight: bold; @@ -230,7 +230,7 @@ export const CategoryBannerW = styled.section` ${CategoryNavW} { margin-left: 20px; } - ${media.tablet (css` + ${media.tablet(css` padding: 72px 16px; ${CategoryNavW} { margin-left: 65px; @@ -247,29 +247,32 @@ CategoryNavW.Image.propTypes = { }; export const UpcomingW = styled.section` - background: ${props => props.theme.gray90}; - color: ${props => props.theme.gray1}; + background: ${(props) => props.theme.gray90}; + color: ${(props) => props.theme.gray1}; width: 100%; - /* height: 200px; */ + margin-bottom: 30px; padding: 36px 0; + ${Container} { - /* padding: 60px 24px 12px 24px; */ overflow: visible; } ${TwoCol.DRight} { position: relative; } - ${media.tablet (css` + + ${media.tablet(css` + margin-bottom: 165px; padding: 48px 0; height: 100%; `)}; `; + UpcomingW.Title = styled.div` font-weight: 800; font-size: 16px; line-height: 18px; - ${media.tablet (css` + ${media.tablet(css` font-size: 28px; line-height: 32px; `)}; @@ -279,7 +282,7 @@ UpcomingW.Description = styled.div` font-size: 12px; line-height: 14px; - ${media.tablet (css` + ${media.tablet(css` margin-top: 12px; font-size: 24px; line-height: 27px; @@ -289,12 +292,12 @@ UpcomingW.Timer = styled.div` margin-top: 21px; font-size: 20px; line-height: 23px; - color: ${props => props.theme.white}; + color: ${(props) => props.theme.white}; - ${media.tablet (css` + ${media.tablet(css` margin-top: 44px; font-size: 40px; - line-height: 45px; + line-height: 45px; `)}; `; UpcomingW.Button = styled.button` @@ -302,16 +305,16 @@ UpcomingW.Button = styled.button` padding: 14px 16px; width: 146px; height: 52px; - background: ${props => props.theme.gray90}; + background: ${(props) => props.theme.gray90}; border: 1.5px solid rgba(255, 255, 255, 0.2); border-radius: 4px; display: none; font-weight: bold; font-size: 16px; line-height: 18px; - color: ${props => props.theme.white}; - - ${media.tablet (css` + color: ${(props) => props.theme.white}; + + ${media.tablet(css` margin-top: 44px; display: inherit; svg { @@ -328,8 +331,8 @@ UpcomingW.Count = styled.div` border-radius: 20.5px; font-size: 10px; line-height: 11px; - color: ${props => props.theme.gray30}; - ${media.tablet (css` + color: ${(props) => props.theme.gray30}; + ${media.tablet(css` display: none; `)}; `; @@ -344,11 +347,15 @@ UpcomingW.Carousel = styled.section` opacity: 0; display: none; } - ${media.tablet (css` + ${media.tablet(css` height: 400px; - .slick-btn { display: inherit } + .slick-btn { + display: inherit; + } &:hover { - .slick-btn { opacity: 1 } + .slick-btn { + opacity: 1; + } } `)} `; @@ -368,17 +375,20 @@ UpcomingW.Carousel.Button = styled.img` top: 68px; right: 16px; } - ${media.tablet (css` + ${media.tablet(css` width: 40px; height: 40px; - &.prev, &.next { top: 164px; } + &.prev, + &.next { + top: 164px; + } `)} `; UpcomingW.SlickItemW = styled.div` padding-right: 12px; padding-bottom: 10px; - ${media.tablet (css` + ${media.tablet(css` padding-right: 24px; `)} `; @@ -388,67 +398,55 @@ UpcomingW.Image = styled.img` background: linear-gradient(0deg, rgba(0, 0, 0, 0.03), rgba(0, 0, 0, 0.03)); box-shadow: 2px 4px 10px rgba(0, 0, 0, 0.25); border-radius: 4px; - ${media.tablet (css` + ${media.tablet(css` height: 360px; `)} `; -UpcomingW.NoMagamImBak = styled.div` - font-size: 16px; - font-weight: 500; - ${media.tablet (css` - font-size: 24px; - `)}; -`; - export const RecommendsW = styled.section` width: 100%; - margin-top: 30px; - ${media.tablet (css` - margin-top: 165px; - `)}; padding-bottom: 12px; `; -export const RecommendsTitleW = styled (TitleW)` +export const RecommendsTitleW = styled(TitleW)` margin-bottom: 20px; margin-top: 53px; - ${media.tablet (css` + ${media.tablet(css` margin-top: 0; margin-bottom: 32px; `)}; `; -RecommendsW.Zabo = styled (TwoCol.Left)` +RecommendsW.Zabo = styled(TwoCol.Left)` width: 100%; max-width: 100%; - ${media.tablet (css` + ${media.tablet(css` max-width: inherit; `)}; `; -RecommendsW.Group = styled (TwoCol.Right)` +RecommendsW.Group = styled(TwoCol.Right)` width: 100%; padding-bottom: 2px; max-width: 100%; - ${media.tablet (css` + ${media.tablet(css` max-width: inherit; `)}; `; RecommendsW.GroupList = styled.div` margin-top: 8px; - ${media.tablet (css` + ${media.tablet(css` margin-top: 20px; `)}; `; -export const GroupBoxW = styled (GroupBox)` +export const GroupBoxW = styled(GroupBox)` margin-top: 8px; &:first-child { margin-top: 0; } - ${media.tablet (css` + ${media.tablet(css` margin-top: 16px; `)}; `; @@ -456,7 +454,7 @@ export const GroupBoxW = styled (GroupBox)` export const BannersW = styled.section` width: 100%; margin-top: 36px; - ${media.tablet (css` + ${media.tablet(css` margin-top: 80px; `)}; `; @@ -464,13 +462,13 @@ export const BannersW = styled.section` export const BannerW = styled.div` min-width: 312px; height: 136px; - border: 1px solid ${props => props.theme.gray10}; + border: 1px solid ${(props) => props.theme.gray10}; border-radius: 6px; padding: 0 24px; display: flex; margin-left: 12px; - - ${media.tablet (css` + + ${media.tablet(css` min-width: 500px; height: 200px; padding: 0 48px; @@ -482,9 +480,9 @@ export const BannerW = styled.div` `; BannerW.Writings = styled.div` - padding: 24px 0; - margin-right: 7px; - ${media.tablet (css` + padding: 24px 0; + margin-right: 7px; + ${media.tablet(css` padding: 48px 0; margin-right: 30px; `)}; @@ -494,8 +492,8 @@ BannerW.Title = styled.div` font-weight: 800; font-size: 14px; line-height: 16px; - color: ${props => props.theme.gray90}; - ${media.tablet (css` + color: ${(props) => props.theme.gray90}; + ${media.tablet(css` font-size: 20px; line-height: 23px; `)}; @@ -504,9 +502,9 @@ BannerW.Title = styled.div` BannerW.Description = styled.div` font-size: 14px; line-height: 16px; - color: ${props => props.theme.gray90}; + color: ${(props) => props.theme.gray90}; margin-top: 2px; - ${media.tablet (css` + ${media.tablet(css` margin-top: 4px; font-size: 20px; line-height: 23px; @@ -517,18 +515,18 @@ BannerW.Button = styled.button` font-weight: bold; font-size: 12px; line-height: 14px; - color: ${props => props.theme.white}; + color: ${(props) => props.theme.white}; width: 120px; height: 32px; ${mixins.flexCenter}; - border: 1px solid ${props => props.theme[props.color]}; - background: ${props => props.theme[props.color]}; + border: 1px solid ${(props) => props.theme[props.color]}; + background: ${(props) => props.theme[props.color]}; border-radius: 4px; margin-top: 20px; svg { margin-left: 10px; } - ${media.tablet (css` + ${media.tablet(css` margin-top: 14px; width: 136px; height: 40px; @@ -545,17 +543,15 @@ export const ZaboListW = styled.section` width: 100%; `; -export const ZaboListTitleW = styled (TitleW)` +export const ZaboListTitleW = styled(TitleW)` margin-top: 48px; margin-bottom: 16px; - ${media.tablet (css` + ${media.tablet(css` margin-top: 100px; margin-bottom: 24px; `)}; `; -export const Help = styled.div` - -`; +export const Help = styled.div``; export default Wrapper; diff --git a/src/components/pages/LandingPage/index.js b/src/components/pages/LandingPage/index.js index 1505ef7c..d91ae33d 100644 --- a/src/components/pages/LandingPage/index.js +++ b/src/components/pages/LandingPage/index.js @@ -1 +1 @@ -export { default } from './LandingPage'; +export { default } from "./LandingPage"; diff --git a/src/components/pages/LoginPage/LoginPage.container.js b/src/components/pages/LoginPage/LoginPage.container.js index 083e56bb..a45d1448 100644 --- a/src/components/pages/LoginPage/LoginPage.container.js +++ b/src/components/pages/LoginPage/LoginPage.container.js @@ -1,16 +1,16 @@ -import React, { PureComponent } from 'react'; -import { connect } from 'react-redux'; +import React, { PureComponent } from "react"; +import { connect } from "react-redux"; -import LoginPage from './LoginPage'; +import LoginPage from "./LoginPage"; class LoginPageContainer extends PureComponent { - render () { + render() { return ; } } -const mapStateToProps = state => ({}); +const mapStateToProps = (state) => ({}); -const mapDispatchToProps = dispatch => ({}); +const mapDispatchToProps = (dispatch) => ({}); -export default connect (mapStateToProps, mapDispatchToProps) (LoginPageContainer); +export default connect(mapStateToProps, mapDispatchToProps)(LoginPageContainer); diff --git a/src/components/pages/LoginPage/LoginPage.js b/src/components/pages/LoginPage/LoginPage.js index fb60d3ac..67af0d0d 100644 --- a/src/components/pages/LoginPage/LoginPage.js +++ b/src/components/pages/LoginPage/LoginPage.js @@ -1,21 +1,22 @@ -import { useEffect } from 'react'; +import { useEffect } from "react"; -import axios from 'lib/axios'; -import storage from 'lib/storage'; +import axios from "lib/axios"; +import storage from "lib/storage"; const LoginPage = ({ history }) => { - useEffect (() => { + useEffect(() => { const { state } = history.location; if (state && state.referrer) { - storage.setItem ('referrer', state.referrer); + storage.setItem("referrer", state.referrer); } - axios.get ('/auth/loginApi') - .then (data => { - window.location.replace (data.url); + axios + .get("/auth/loginApi") + .then((data) => { + window.location.replace(data.url); }) - .catch (error => { - console.error (error); - alert ('로그인에 실패하였습니다.'); + .catch((error) => { + console.error(error); + alert("로그인에 실패하였습니다."); }); }, [history]); return null; diff --git a/src/components/pages/LoginPage/LoginPage.stories.js b/src/components/pages/LoginPage/LoginPage.stories.js index f7d96523..7eac6fbe 100644 --- a/src/components/pages/LoginPage/LoginPage.stories.js +++ b/src/components/pages/LoginPage/LoginPage.stories.js @@ -1,8 +1,8 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; +import React from "react"; +import { storiesOf } from "@storybook/react"; -import LoginPage from './index'; +import LoginPage from "./index"; -storiesOf ('pages/LoginPage', module).add ('Default', () => , { - notes: '', +storiesOf("pages/LoginPage", module).add("Default", () => , { + notes: "", }); diff --git a/src/components/pages/LoginPage/index.js b/src/components/pages/LoginPage/index.js index ebaf17e5..5d098b76 100644 --- a/src/components/pages/LoginPage/index.js +++ b/src/components/pages/LoginPage/index.js @@ -1 +1 @@ -export { default } from './LoginPage.container'; +export { default } from "./LoginPage.container"; diff --git a/src/components/pages/NotFound/NotFound.js b/src/components/pages/NotFound/NotFound.js index 67a36f77..94527cac 100644 --- a/src/components/pages/NotFound/NotFound.js +++ b/src/components/pages/NotFound/NotFound.js @@ -1,24 +1,24 @@ -import React from 'react'; -import { NavLink } from 'react-router-dom'; +import React from "react"; +import { NavLink } from "react-router-dom"; -import notFoundImage from 'static/images/notFoundImage.jpg'; -import logo from 'static/logo/logo.svg'; +import notFoundImage from "static/images/notFoundImage.jpg"; +import logo from "static/logo/logo.svg"; -import { Page } from './NotFound.styled'; +import { Page } from "./NotFound.styled"; const NotFound = () => ( - logo + logo - 요청하신 페이지를 찾을 수 없습니다.
- 메인페이지 - 로 이동하기 + 요청하신 페이지를 찾을 수 없습니다. +
+ 메인페이지로 이동하기
diff --git a/src/components/pages/NotFound/NotFound.styled.js b/src/components/pages/NotFound/NotFound.styled.js index 4c16a04f..77ba5015 100644 --- a/src/components/pages/NotFound/NotFound.styled.js +++ b/src/components/pages/NotFound/NotFound.styled.js @@ -1,6 +1,6 @@ -import styled, { css } from 'styled-components'; +import styled, { css } from "styled-components"; -import { media } from 'lib/utils/style'; +import { media } from "lib/utils/style"; export const Page = styled.section` width: 100%; @@ -12,23 +12,23 @@ Page.Header = styled.div` top: 0; width: 100%; height: 55px; - border-top: 5px solid ${props => props.theme.main}; + border-top: 5px solid ${(props) => props.theme.main}; padding: 10px 18px; `; Page.Body = styled.div` width: 90vw; margin: 240px 5vw 0; - ${media.tablet (css` + ${media.tablet(css` width: 34vw; margin: 280px 33vw 0; `)}; `; -Page.Title = styled.img` +Page.Title = styled.img` width: 60vw; margin: 0 15vw; - ${media.tablet (css` + ${media.tablet(css` width: 34vw; margin: 0; `)}; @@ -39,15 +39,15 @@ Page.Description = styled.p` margin-top: 28px; line-height: 1.6; font-size: 16px; - color: ${props => props.theme.gray30}; - ${media.tablet (css` + color: ${(props) => props.theme.gray30}; + ${media.tablet(css` margin-top: 48px; font-size: 18px; `)}; `; Page.Description.Link = styled.a` - color: ${props => props.theme.main} !important; + color: ${(props) => props.theme.main} !important; font-weight: bold; text-decoration: underline; `; diff --git a/src/components/pages/NotFound/index.js b/src/components/pages/NotFound/index.js index 106131be..3fded62c 100644 --- a/src/components/pages/NotFound/index.js +++ b/src/components/pages/NotFound/index.js @@ -1 +1 @@ -export { default } from './NotFound'; +export { default } from "./NotFound"; diff --git a/src/components/pages/ProfilePage/GroupProfilePage.js b/src/components/pages/ProfilePage/GroupProfilePage.js index 2d106d0d..3be5fd46 100644 --- a/src/components/pages/ProfilePage/GroupProfilePage.js +++ b/src/components/pages/ProfilePage/GroupProfilePage.js @@ -1,56 +1,66 @@ -import React, { - useCallback, useEffect, useMemo, - useRef, useState, -} from 'react'; -import { Link, useHistory } from 'react-router-dom'; -import { useDispatch, useSelector } from 'react-redux'; -import get from 'lodash.get'; +import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { Link, useHistory } from "react-router-dom"; +import { useDispatch, useSelector } from "react-redux"; +import get from "lodash.get"; -import SuperTooltip from 'atoms/SuperTooltip'; -import ProfileStats from 'organisms/ProfileStats'; -import StyledQuill from 'organisms/StyledQuill'; -import Header from 'templates/Header'; -import ZaboList from 'templates/ZaboList'; +import SuperTooltip from "components/atoms/SuperTooltip"; +import ProfileStats from "components/organisms/ProfileStats"; +import StyledQuill from "components/organisms/StyledQuill"; +import Header from "components/templates/Header"; +import ZaboList from "components/templates/ZaboList"; -import { followProfile } from 'store/reducers/profile'; -import { GroupType } from 'lib/propTypes'; -import { - getLabeledTimeDiff, isAuthedSelector, isElemWidthOverflown, withAuth, -} from 'lib/utils'; -import { mediaSizes } from 'lib/utils/style'; +import { followProfile } from "store/reducers/profile"; +import { GroupType } from "lib/propTypes"; +import { getLabeledTimeDiff, isAuthedSelector, isElemWidthOverflown, withAuth } from "lib/utils"; +import { mediaSizes } from "lib/utils/style"; -import groupDefaultProfile from 'static/images/groupDefaultProfile.png'; +import groupDefaultProfile from "static/images/groupDefaultProfile.png"; -import { Page, Zabos } from './Profile.styled'; +import { Page, Zabos } from "./Profile.styled"; const GroupProfile = ({ profile }) => { const { - name, profilePhoto, members, zabosCount, followersCount, recentUpload, description = '', subtitle = '', myRole, following, + name, + profilePhoto, + members, + zabosCount, + followersCount, + recentUpload, + description = "", + subtitle = "", + myRole, + following, } = profile; - const dispatch = useDispatch (); - const history = useHistory (); - const isAuthed = useSelector (isAuthedSelector); - const width = useSelector (state => get (state, ['app', 'windowSize', 'width'])); - const isMobile = useMemo (() => mediaSizes.tablet > width, [width]); + const dispatch = useDispatch(); + const history = useHistory(); + const isAuthed = useSelector(isAuthedSelector); + const width = useSelector((state) => get(state, ["app", "windowSize", "width"])); + const isMobile = useMemo(() => mediaSizes.tablet > width, [width]); - const descRef = useRef (null); - const [showTooltip, setShowTooltip] = useState (false); - const follow = useCallback (() => { - if (withAuth (history, isAuthed)) dispatch (followProfile ({ name })); + const descRef = useRef(null); + const [showTooltip, setShowTooltip] = useState(false); + const follow = useCallback(() => { + if (withAuth(history, isAuthed)) dispatch(followProfile({ name })); }, [name]); - useEffect (() => { setShowTooltip (isElemWidthOverflown (descRef.current)); }, [descRef, width]); + useEffect(() => { + setShowTooltip(isElemWidthOverflown(descRef.current)); + }, [descRef, width]); - const timePast = recentUpload ? getLabeledTimeDiff (recentUpload, 60, 60, 24, 7, 5, 12) : '없음'; - const stats = [{ - name: '올린 자보', - value: zabosCount, - }, { - name: '팔로워', - value: followersCount, - }, { - name: '최근 활동', - value: timePast, - }]; + const timePast = recentUpload ? getLabeledTimeDiff(recentUpload, 60, 60, 24, 7, 5, 12) : "없음"; + const stats = [ + { + name: "올린 자보", + value: zabosCount, + }, + { + name: "팔로워", + value: followersCount, + }, + { + name: "최근 활동", + value: timePast, + }, + ]; return ( @@ -58,43 +68,51 @@ const GroupProfile = ({ profile }) => { - { - profilePhoto - ? profile photo - : default profile img - } + {profilePhoto ? ( + profile photo + ) : ( + default profile img + )}

{name}

-

{subtitle || '아직 소개가 없습니다.'}

+

{subtitle || "아직 소개가 없습니다."}

- { - myRole - ? ( - <> - - - - {myRole === 'admin' && ( - - - - )} - {following - ? - : } - - ) - : ( - <> - {following - ? - : } - - ) - } + {myRole ? ( + <> + + + + {myRole === "admin" && ( + + + + )} + {following ? ( + + ) : ( + + )} + + ) : ( + <> + {following ? ( + + ) : ( + + )} + + )}
@@ -104,15 +122,13 @@ const GroupProfile = ({ profile }) => {
- + -

업로드한 자보 {zabosCount}

+

+ 업로드한 자보 {zabosCount} +

diff --git a/src/components/pages/ProfilePage/Main.js b/src/components/pages/ProfilePage/Main.js index 8ca660b9..c23e2423 100644 --- a/src/components/pages/ProfilePage/Main.js +++ b/src/components/pages/ProfilePage/Main.js @@ -1,15 +1,15 @@ -import React from 'react'; -import { Route, Switch, useRouteMatch } from 'react-router-dom'; -import styled from 'styled-components'; +import React from "react"; +import { Route, Switch, useRouteMatch } from "react-router-dom"; +import styled from "styled-components"; -import { NotFound } from 'pages'; +import { NotFound } from "components/pages"; -import ProfilePage from './ProfilePage'; +import ProfilePage from "./ProfilePage"; const ProfilePageWrapper = styled.section``; const Main = () => { - const match = useRouteMatch (); + const match = useRouteMatch(); return ( @@ -21,9 +21,6 @@ const Main = () => { ); }; - -Main.propTypes = { - -}; +Main.propTypes = {}; export default Main; diff --git a/src/components/pages/ProfilePage/Profile.styled.js b/src/components/pages/ProfilePage/Profile.styled.js index f8cef691..31770dda 100644 --- a/src/components/pages/ProfilePage/Profile.styled.js +++ b/src/components/pages/ProfilePage/Profile.styled.js @@ -1,4 +1,4 @@ -import styled from 'styled-components'; +import styled from "styled-components"; export const Page = styled.section` padding: 120px 0 80px 0; @@ -44,7 +44,7 @@ Page.Header.Left.ProfilePhoto = styled.div` width: 120px; height: 120px; border-radius: 50%; - border: 1px solid ${props => props.theme.gray10}; + border: 1px solid ${(props) => props.theme.gray10}; @media (max-width: 640px) { width: 105px; height: 105px; @@ -60,7 +60,7 @@ Page.Header.Left.UserInfo = styled.div` max-width: 500px; h1 { font-size: 28px; - color: ${props => props.theme.main}; + color: ${(props) => props.theme.main}; margin: 0; font-weight: 800; } @@ -80,8 +80,8 @@ Page.Header.Left.UserInfo = styled.div` padding: 8px 14px; border-radius: 15px; margin-right: 8px; - background-color: #F8F8F8; - border: 1px solid ${props => props.theme.main}; + background-color: #f8f8f8; + border: 1px solid ${(props) => props.theme.main}; color: #143441; &.logout { border: 1px solid #8f8f8f; @@ -100,12 +100,16 @@ Page.Header.Left.UserInfo = styled.div` } @media (max-width: 640px) { min-width: 158px; - h1 { font-size: 24px } - p { font-size: 14px } + h1 { + font-size: 24px; + } + p { + font-size: 14px; + } button { margin-right: 6px; - } } + } `; Page.Header.Right = styled.section` @@ -133,7 +137,7 @@ Page.Body.User = styled.div` Page.Body.Group = styled.div` margin-bottom: 59px; - border-top: 1px solid #E9E9E9; + border-top: 1px solid #e9e9e9; padding-top: 16px; @media (max-width: 640px) { margin-bottom: 0; @@ -141,7 +145,7 @@ Page.Body.Group = styled.div` `; // TODO: Refactor dups -export const Zabos = styled.section` +export const Zabos = styled.section` width: 1032px; margin-top: 72px; @media (max-width: 640px) { @@ -159,5 +163,7 @@ export const Zabos = styled.section` `; Zabos.ZaboList = styled.div` - .masonry { margin: 0 } + .masonry { + margin: 0; + } `; diff --git a/src/components/pages/ProfilePage/ProfilePage.js b/src/components/pages/ProfilePage/ProfilePage.js index 5266dfca..8bac1c61 100644 --- a/src/components/pages/ProfilePage/ProfilePage.js +++ b/src/components/pages/ProfilePage/ProfilePage.js @@ -1,23 +1,22 @@ -import React, { useEffect, useMemo } from 'react'; -import { useParams } from 'react-router-dom'; -import { shallowEqual, useDispatch, useSelector } from 'react-redux'; -import get from 'lodash.get'; +import React, { useEffect, useMemo } from "react"; +import { useParams } from "react-router-dom"; +import { shallowEqual, useDispatch, useSelector } from "react-redux"; +import get from "lodash.get"; -import { NotFound } from 'pages'; +import { NotFound } from "components/pages"; -import { getProfile } from 'store/reducers/profile'; - -import GroupProfile from './GroupProfilePage'; -import UserProfile from './UserProfilePage'; +import { getProfile } from "store/reducers/profile"; +import GroupProfile from "./GroupProfilePage"; +import UserProfile from "./UserProfilePage"; const ProfilePage = () => { - const { name } = useParams (); - const dispatch = useDispatch (); - useEffect (() => { - dispatch (getProfile (name)).catch (error => {}); + const { name } = useParams(); + const dispatch = useDispatch(); + useEffect(() => { + dispatch(getProfile(name)).catch((error) => undefined); }, [name]); - const profile = useSelector (state => get (state, ['profile', 'profiles', name])); + const profile = useSelector((state) => get(state, ["profile", "profiles", name])); if (!profile) return null; if (profile.error) return ; if (profile.username === name) return ; @@ -25,13 +24,8 @@ const ProfilePage = () => { return null; }; +ProfilePage.propTypes = {}; -ProfilePage.propTypes = { - -}; - -ProfilePage.defaultProps = { - -}; +ProfilePage.defaultProps = {}; export default ProfilePage; diff --git a/src/components/pages/ProfilePage/UserProfilePage.js b/src/components/pages/ProfilePage/UserProfilePage.js index 1821291c..aa09890e 100644 --- a/src/components/pages/ProfilePage/UserProfilePage.js +++ b/src/components/pages/ProfilePage/UserProfilePage.js @@ -1,57 +1,67 @@ -import React, { - useEffect, useMemo, - useRef, useState, -} from 'react'; -import { useDispatch, useSelector } from 'react-redux'; -import get from 'lodash.get'; +import React, { useEffect, useMemo, useRef, useState } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import get from "lodash.get"; -import Button from 'atoms/Button'; -import SuperTooltip from 'atoms/SuperTooltip'; -import GroupList from 'organisms/GroupList'; -import ProfileStats from 'organisms/ProfileStats'; -import Header from 'templates/Header'; -import ZaboList from 'templates/ZaboList'; +import Button from "components/atoms/Button"; +import SuperTooltip from "components/atoms/SuperTooltip"; +import GroupList from "components/organisms/GroupList"; +import ProfileStats from "components/organisms/ProfileStats"; +import Header from "components/templates/Header"; +import ZaboList from "components/templates/ZaboList"; -import { logout as logoutAction } from 'store/reducers/auth'; -import { UserType } from 'lib/propTypes'; -import { isAdminSelector, isElemWidthOverflown } from 'lib/utils'; -import { mediaSizes } from 'lib/utils/style'; +import { logout as logoutAction } from "store/reducers/auth"; +import { UserType } from "lib/propTypes"; +import { isAdminSelector, isElemWidthOverflown } from "lib/utils"; +import { mediaSizes } from "lib/utils/style"; -import defaultProfile from 'static/images/defaultProfile.png'; +import defaultProfile from "static/images/defaultProfile.png"; -import { - Page, Zabos, -} from './Profile.styled'; +import { Page, Zabos } from "./Profile.styled"; const UserProfile = ({ profile }) => { const { - username, profilePhoto, groups, description, boards, stats: { likesCount, followingsCount } = {}, following, + username, + profilePhoto, + groups, + description, + boards, + stats: { likesCount, followingsCount } = {}, + following, } = profile; - const width = useSelector (state => get (state, ['app', 'windowSize', 'width'])); - const dispatch = useDispatch (); - const myUsername = useSelector (state => get (state, ['auth', 'info', 'username'])); - const pendingGroups = useSelector (state => get (state, ['auth', 'info', 'pendingGroups'])); - const isMyProfile = (myUsername === username); - const isAdmin = useSelector (isAdminSelector); - const logout = () => dispatch (logoutAction ()); - const descRef = useRef (null); - const [showTooltip, setShowTooltip] = useState (false); - useEffect (() => { setShowTooltip (isElemWidthOverflown (descRef.current)); }, [descRef, width]); - const isMobile = useMemo (() => mediaSizes.tablet > width, [width]); + const width = useSelector((state) => get(state, ["app", "windowSize", "width"])); + const dispatch = useDispatch(); + const myUsername = useSelector((state) => get(state, ["auth", "info", "username"])); + const pendingGroups = useSelector((state) => get(state, ["auth", "info", "pendingGroups"])); + const isMyProfile = myUsername === username; + const isAdmin = useSelector(isAdminSelector); + const logout = () => dispatch(logoutAction()); + const descRef = useRef(null); + const [showTooltip, setShowTooltip] = useState(false); + useEffect(() => { + setShowTooltip(isElemWidthOverflown(descRef.current)); + }, [descRef, width]); + const isMobile = useMemo(() => mediaSizes.tablet > width, [width]); - const pinsCount = boards.reduce ((acc, cur) => acc + cur.pinsCount, 0); - const stats = [{ - name: '저장한 자보', - value: pinsCount, - }, { - name: '좋아하는 자보', - value: likesCount, - }, { - name: '팔로잉', - value: followingsCount, - }]; + const pinsCount = boards.reduce((acc, cur) => acc + cur.pinsCount, 0); + const stats = [ + { + name: "저장한 자보", + value: pinsCount, + }, + { + name: "좋아하는 자보", + value: likesCount, + }, + { + name: "팔로잉", + value: followingsCount, + }, + ]; - const groupsWithPending = useMemo (() => [...groups, ...pendingGroups.map (group => ({ ...group, isPending: true }))], [groups, pendingGroups]); + const groupsWithPending = useMemo( + () => [...groups, ...pendingGroups.map((group) => ({ ...group, isPending: true }))], + [groups, pendingGroups], + ); return ( @@ -59,23 +69,33 @@ const UserProfile = ({ profile }) => { - { - profilePhoto - ? profile photo - : default profile img - } + {profilePhoto ? ( + profile photo + ) : ( + default profile img + )}

{username}

-

{description || '아직 소개가 없습니다.'}

+

{description || "아직 소개가 없습니다."}

{isMyProfile ? (
- - {isAdmin && ()} + + {isAdmin && ( + + )}
) : ( @@ -84,7 +104,7 @@ const UserProfile = ({ profile }) => { // ? // : } // - '' + "" )}
@@ -93,8 +113,7 @@ const UserProfile = ({ profile }) => {
- - + diff --git a/src/components/pages/ProfilePage/index.js b/src/components/pages/ProfilePage/index.js index 47dec621..0fdf55f5 100644 --- a/src/components/pages/ProfilePage/index.js +++ b/src/components/pages/ProfilePage/index.js @@ -1 +1 @@ -export { default } from './Main'; +export { default } from "./Main"; diff --git a/src/components/pages/SearchPage/SearchPage.js b/src/components/pages/SearchPage/SearchPage.js index 6c007270..1f1eca1c 100644 --- a/src/components/pages/SearchPage/SearchPage.js +++ b/src/components/pages/SearchPage/SearchPage.js @@ -1,41 +1,41 @@ -import React, { useCallback, useEffect } from 'react'; -import PropTypes from 'prop-types'; -import { useHistory, useLocation } from 'react-router-dom'; -import { useDispatch } from 'react-redux'; -import queryString from 'query-string'; +import React, { useCallback, useEffect } from "react"; +import PropTypes from "prop-types"; +import { useHistory, useLocation } from "react-router-dom"; +import { useDispatch } from "react-redux"; +import queryString from "query-string"; // import { searchAPI } from lib/api/search'; -import TagList from 'atoms/TagList'; -import GroupList from 'organisms/GroupList'; -import Header from 'templates/Header'; -import ZaboList from 'templates/ZaboList'; +import TagList from "components/atoms/TagList"; +import GroupList from "components/organisms/GroupList"; +import Header from "components/templates/Header"; +import ZaboList from "components/templates/ZaboList"; -import { getSearch } from 'store/reducers/zabo'; -import useSetState from 'hooks/useSetState'; -import { parseQuery } from 'lib/utils'; +import { getSearch } from "store/reducers/zabo"; +import useSetState from "hooks/useSetState"; +import { parseQuery } from "lib/utils"; -import searchIcon from 'static/images/search-icon-navy.png'; +import searchIcon from "static/images/search-icon-navy.png"; -import { - EmptyResultW, GroupResultW, Page, ZaboResultW, -} from './SearchPage.styled'; +import { EmptyResultW, GroupResultW, Page, ZaboResultW } from "./SearchPage.styled"; const Empty = ({ query, category, isZaboEmpty }) => { - let label = ''; + let label = ""; if (query) label = query; - if (category.length) label += ' #'.concat (category); + if (category.length) label += " #".concat(category); return ( search icon
-
{label}
- 에 대한 검색결과가 없습니다. +
{label}
에 대한 검색결과가 없습니다.
{!isZaboEmpty && (

- 없었어요?
- 없어요
- 아 있었는데?
+ 없었어요? +
+ 없어요 +
+ 아 있었는데? +
아니 없어요 그냥

)} @@ -49,7 +49,7 @@ Empty.defaultProps = { Empty.propTypes = { query: PropTypes.string.isRequired, - category: PropTypes.arrayOf (PropTypes.string).isRequired, + category: PropTypes.arrayOf(PropTypes.string).isRequired, isZaboEmpty: PropTypes.bool, }; @@ -59,72 +59,71 @@ const initialState = { }; const SearchPage = () => { - const dispatch = useDispatch (); - const { search, state: isResearch } = useLocation (); - const history = useHistory (); - const { safeQuery, safeCategory } = parseQuery (search); + const dispatch = useDispatch(); + const { search, state: isResearch } = useLocation(); + const history = useHistory(); + const { safeQuery, safeCategory } = parseQuery(search); - const [state, setState] = useSetState (initialState); + const [state, setState] = useSetState(initialState); const { zabos, groups } = state; const isZaboEmpty = !zabos.length; const isGroupEmpty = !groups.length; - const isAllEmpty = (isZaboEmpty && isGroupEmpty); - - const _updateResults = useCallback (data => { - const { zabos, groups } = data; - setState ({ zabos, groups }); - }, [setState]); - - useEffect (() => { - dispatch (getSearch ({ query: safeQuery, category: safeCategory, stat: true })) - .then (data => _updateResults (data)) - .catch (err => _updateResults (initialState)); - }, [safeQuery, safeCategory.join ('')]); - - const onTagClick = newCat => { - let newCats = safeCategory.slice (); - if (safeCategory.includes (newCat)) { - newCats = newCats.filter (c => c !== newCat); + const isAllEmpty = isZaboEmpty && isGroupEmpty; + + const _updateResults = useCallback( + (data) => { + const { zabos, groups } = data; + setState({ zabos, groups }); + }, + [setState], + ); + + useEffect(() => { + dispatch(getSearch({ query: safeQuery, category: safeCategory, stat: true })) + .then((data) => _updateResults(data)) + .catch((err) => _updateResults(initialState)); + }, [safeQuery, safeCategory.join("")]); + + const onTagClick = (newCat) => { + let newCats = safeCategory.slice(); + if (safeCategory.includes(newCat)) { + newCats = newCats.filter((c) => c !== newCat); } else { - newCats.push (newCat); + newCats.push(newCat); } const search = {}; if (safeQuery) search.query = safeQuery; if (newCats.length) search.category = newCats; - history.push (`/search?${queryString.stringify (search)}`, { state: true }); + history.push(`/search?${queryString.stringify(search)}`, { state: true }); }; return (
- {isAllEmpty && !isResearch - ? ( - - ) : ( - - - {!isGroupEmpty && } - - -

자보 검색 결과

- -
- {!isZaboEmpty - ? - : } -
-
- )} + {isAllEmpty && !isResearch ? ( + + ) : ( + + + {!isGroupEmpty && } + + +

자보 검색 결과

+ +
+ {!isZaboEmpty ? ( + + ) : ( + + )} +
+
+ )} ); }; -SearchPage.propTypes = { -}; +SearchPage.propTypes = {}; export default SearchPage; diff --git a/src/components/pages/SearchPage/SearchPage.styled.js b/src/components/pages/SearchPage/SearchPage.styled.js index 44b86d0d..00281bda 100644 --- a/src/components/pages/SearchPage/SearchPage.styled.js +++ b/src/components/pages/SearchPage/SearchPage.styled.js @@ -1,6 +1,6 @@ -import styled, { css } from 'styled-components'; +import styled, { css } from "styled-components"; -import { media } from 'lib/utils/style'; +import { media } from "lib/utils/style"; export const Page = styled.div` min-width: 1072px; @@ -24,8 +24,10 @@ Page.Body = styled.div` color: #363636; margin: 0; } - .emptySpace { margin-top: 8px } - + .emptySpace { + margin-top: 8px; + } + @media (max-width: 640px) { width: 100%; margin-top: 12px; @@ -33,14 +35,16 @@ Page.Body = styled.div` h1 { font-size: 18px; } - .emptySpace { margin-top: 0 } + .emptySpace { + margin-top: 0; + } } `; export const EmptyResultW = styled.section` text-align: center; font-size: 16px; - margin-top: ${props => (props.isZaboEmpty ? '90px' : '225px')}; + margin-top: ${(props) => (props.isZaboEmpty ? "90px" : "225px")}; img { width: 29.15px; height: 29.15px; @@ -53,16 +57,22 @@ export const EmptyResultW = styled.section` font-weight: 800; } } - .search-icon { margin-bottom: 22px } - .empty-text { margin-bottom: 44px } + .search-icon { + margin-bottom: 22px; + } + .empty-text { + margin-bottom: 44px; + } p { - color: #BCBCBC; + color: #bcbcbc; line-height: 28px; - margin: 0 + margin: 0; } - @media (max-width: 640px) { margin-top: 97px } - ${media.tablet (css` + @media (max-width: 640px) { + margin-top: 97px; + } + ${media.tablet(css` img { margin-bottom: 34px; } @@ -70,10 +80,10 @@ export const EmptyResultW = styled.section` `; // TODO: Refactor dups -export const ZaboResultW = styled.section` +export const ZaboResultW = styled.section` width: 100%; - margin-top: ${props => (props.isGroupEmpty ? '0' : '68px')}; - ${media.tablet (css` + margin-top: ${(props) => (props.isGroupEmpty ? "0" : "68px")}; + ${media.tablet(css` width: 1032px; `)}; `; diff --git a/src/components/pages/SearchPage/index.js b/src/components/pages/SearchPage/index.js index a8444af5..5a17ef04 100644 --- a/src/components/pages/SearchPage/index.js +++ b/src/components/pages/SearchPage/index.js @@ -1 +1 @@ -export { default } from './SearchPage'; +export { default } from "./SearchPage"; diff --git a/src/components/pages/SettingsPage/GroupApply.js b/src/components/pages/SettingsPage/GroupApply.js index 8bb72221..50a283a2 100644 --- a/src/components/pages/SettingsPage/GroupApply.js +++ b/src/components/pages/SettingsPage/GroupApply.js @@ -1,89 +1,94 @@ -import React, { - useCallback, useEffect, useMemo, - useState, -} from 'react'; -import { useHistory } from 'react-router-dom'; -import { useDispatch, useSelector } from 'react-redux'; -import Tooltip from '@material-ui/core/Tooltip'; -import get from 'lodash.get'; - -import SimpleSelect from 'molecules/SimpleSelect'; -import StyledQuill from 'organisms/StyledQuill'; -import Footer from 'templates/Footer'; -import Header from 'templates/Header'; - -import { applyNewGroup } from 'store/reducers/auth'; -import useSetState from 'hooks/useSetState'; -import { cropImage, dataURLToBlob } from 'lib/utils'; -import { GROUP_CATEGORIES, GROUP_CATEGORIES_2, GROUP_CATEGORY_HIERARCHIY } from 'lib/variables'; - -import checkGray from 'static/images/check_gray.png'; -import groupDefaultProfile from 'static/images/groupDefaultProfile.png'; +import React, { useCallback, useEffect, useMemo, useState } from "react"; +import { useHistory } from "react-router-dom"; +import { useDispatch, useSelector } from "react-redux"; +import Tooltip from "@material-ui/core/Tooltip"; +import get from "lodash.get"; + +import SimpleSelect from "components/molecules/SimpleSelect"; +import StyledQuill from "components/organisms/StyledQuill"; +import Footer from "components/templates/Footer"; +import Header from "components/templates/Header"; + +import { applyNewGroup } from "store/reducers/auth"; +import useSetState from "hooks/useSetState"; +import { cropImage, dataURLToBlob } from "lib/utils"; +import { GROUP_CATEGORIES, GROUP_CATEGORIES_2, GROUP_CATEGORY_HIERARCHIY } from "lib/variables"; + +import checkGray from "static/images/check_gray.png"; +import groupDefaultProfile from "static/images/groupDefaultProfile.png"; import { - AddCategoryW, BusinessW, - ErrorComponent, FooterStyle, FormGroup, Page, Submit, -} from './Setting.styled'; + AddCategoryW, + BusinessW, + ErrorComponent, + FooterStyle, + FormGroup, + Page, + Submit, +} from "./Setting.styled"; -const categoryOptions = GROUP_CATEGORIES.map (category => ( - { value: category, label: category } -)); +const categoryOptions = GROUP_CATEGORIES.map((category) => ({ value: category, label: category })); const ApplyForm = ({ profilePhoto }) => { - const dispatch = useDispatch (); - const history = useHistory (); - const myName = useSelector (state => get (state, ['auth', 'info', 'username'])); - const [state, setState, onChange] = useSetState ({ - name: '', - description: '', - subtitle: '', - purpose: '', + const dispatch = useDispatch(); + const history = useHistory(); + const myName = useSelector((state) => get(state, ["auth", "info", "username"])); + const [state, setState, onChange] = useSetState({ + name: "", + description: "", + subtitle: "", + purpose: "", categoryOption: categoryOptions[0], - categoryOption2: '', + categoryOption2: "", }); - const [error, setError] = useState (); - const { - name, purpose, description, subtitle, categoryOption, categoryOption2, - } = state; + const [error, setError] = useState(); + const { name, purpose, description, subtitle, categoryOption, categoryOption2 } = state; const hasHierarchy = categoryOption.value in GROUP_CATEGORY_HIERARCHIY; const categoryOptions2 = hasHierarchy - ? GROUP_CATEGORY_HIERARCHIY[categoryOption.value].map (category => ( - { value: category, label: category } - )) : []; - - useEffect (() => { - setState ({ categoryOption2: categoryOptions2[0] }); + ? GROUP_CATEGORY_HIERARCHIY[categoryOption.value].map((category) => ({ + value: category, + label: category, + })) + : []; + + useEffect(() => { + setState({ categoryOption2: categoryOptions2[0] }); }, [categoryOption]); - const isValid = useMemo (() => !!name && !!purpose && !!description && !!subtitle); + const isValid = useMemo(() => !!name && !!purpose && !!description && !!subtitle); - const onChangeDescription = e => { - setState ({ description: e }); + const onChangeDescription = (e) => { + setState({ description: e }); }; - const handleSubmit = useCallback (e => { - e.preventDefault (); - const category = categoryOption2 ? [categoryOption.value, categoryOption2.value] : [categoryOption.value]; - const formData = new FormData (); - formData.append ('name', name); - formData.append ('purpose', purpose); - formData.append ('description', description); - formData.append ('subtitle', subtitle); - formData.append ('category', JSON.stringify (category)); - if (profilePhoto) { - formData.append ('img', profilePhoto); - } - dispatch (applyNewGroup (formData)) - .then (() => { - history.push (`/${myName}`); - }) - .catch (err => { - setError (err); - alert (err.error); - }); - }, [state, profilePhoto]); + const handleSubmit = useCallback( + (e) => { + e.preventDefault(); + const category = categoryOption2 + ? [categoryOption.value, categoryOption2.value] + : [categoryOption.value]; + const formData = new FormData(); + formData.append("name", name); + formData.append("purpose", purpose); + formData.append("description", description); + formData.append("subtitle", subtitle); + formData.append("category", JSON.stringify(category)); + if (profilePhoto) { + formData.append("img", profilePhoto); + } + dispatch(applyNewGroup(formData)) + .then(() => { + history.push(`/${myName}`); + }) + .catch((err) => { + setError(err); + alert(err.error); + }); + }, + [state, profilePhoto], + ); return (
@@ -108,21 +113,19 @@ const ApplyForm = ({ profilePhoto }) => { setState ({ categoryOption: newOption })} + onChange={(newOption) => setState({ categoryOption: newOption })} isClearable={false} width="100%" /> - { - hasHierarchy && ( - setState ({ categoryOption2: newOption })} - isClearable={false} - width="100%" - /> - ) - } + {hasHierarchy && ( + setState({ categoryOption2: newOption })} + isClearable={false} + width="100%" + /> + )} @@ -176,9 +179,9 @@ const ApplyForm = ({ profilePhoto }) => { theme="bubble" modules={{ toolbar: [ - ['bold', 'underline', 'strike'], - [{ list: 'ordered' }, { list: 'bullet' }, { indent: '+1' }, { indent: '-1' }], - ['link'], + ["bold", "underline", "strike"], + [{ list: "ordered" }, { list: "bullet" }, { indent: "+1" }, { indent: "-1" }], + ["link"], ], }} groupSetting @@ -187,7 +190,9 @@ const ApplyForm = ({ profilePhoto }) => { {error && {error.message}}
- 신청하기 + + 신청하기 +
@@ -195,15 +200,15 @@ const ApplyForm = ({ profilePhoto }) => { }; const GroupApply = () => { - const [profilePreview, setProfilePreview] = useState (''); - const [profilePhoto, setProfilePhoto] = useState (null); + const [profilePreview, setProfilePreview] = useState(""); + const [profilePhoto, setProfilePhoto] = useState(null); - const handlePhotoChange = async e => { + const handlePhotoChange = async (e) => { const file = e.target.files[0]; - const imageSrc = await cropImage (file, 1); - const blob = dataURLToBlob (imageSrc); - setProfilePhoto (blob); - setProfilePreview (imageSrc); + const imageSrc = await cropImage(file, 1); + const blob = dataURLToBlob(imageSrc); + setProfilePhoto(blob); + setProfilePreview(imageSrc); }; return ( @@ -213,22 +218,20 @@ const GroupApply = () => {

그룹 신청

자보에 새 그룹을 등록해보세요.

- { - profilePreview - ? profile photo - : default profile img - } + {profilePreview ? ( + profile photo + ) : ( + default profile img + )} - diff --git a/src/components/pages/SettingsPage/GroupMembersSetting.js b/src/components/pages/SettingsPage/GroupMembersSetting.js index 642d34a2..ab18a4c0 100644 --- a/src/components/pages/SettingsPage/GroupMembersSetting.js +++ b/src/components/pages/SettingsPage/GroupMembersSetting.js @@ -1,65 +1,80 @@ -import React, { useCallback } from 'react'; -import { useDispatch } from 'react-redux'; -import AwesomeDebouncePromise from 'awesome-debounce-promise'; +import React, { useCallback } from "react"; +import { useDispatch } from "react-redux"; +import AwesomeDebouncePromise from "awesome-debounce-promise"; -import SimpleSelect from 'molecules/SimpleSelect'; -import List from 'organisms/List'; -import MemberItem from 'organisms/MemberItem'; -import SearchSelect from 'organisms/SearchSelect'; -import Header from 'templates/Header'; +import SimpleSelect from "components/molecules/SimpleSelect"; +import List from "components/organisms/List"; +import MemberItem from "components/organisms/MemberItem"; +import SearchSelect from "components/organisms/SearchSelect"; +import Header from "components/templates/Header"; -import * as profileActions from 'store/reducers/profile'; -import useSetState from 'hooks/useSetState'; -import { searchUsers } from 'lib/api/search'; -import { GroupType } from 'lib/propTypes'; +import * as profileActions from "store/reducers/profile"; +import useSetState from "hooks/useSetState"; +import { searchUsers } from "lib/api/search"; +import { GroupType } from "lib/propTypes"; -import { alerts } from '../../../lib/variables'; -import { AddMember, Page } from './Setting.styled'; -import withGroupProfile from './withGroupProfile'; +import { alerts } from "../../../lib/variables"; +import { AddMember, Page } from "./Setting.styled"; +import withGroupProfile from "./withGroupProfile"; -const debouncedSearchAPI = AwesomeDebouncePromise (searchUsers, 300); +const debouncedSearchAPI = AwesomeDebouncePromise(searchUsers, 300); const roleOptions = [ - { value: 'editor', label: '편집자' }, - { value: 'admin', label: '관리자' }, + { value: "editor", label: "편집자" }, + { value: "admin", label: "관리자" }, ]; const GroupMembersSetting = ({ profile }) => { - const dispatch = useDispatch (); + const dispatch = useDispatch(); const { name, members } = profile; - const [state, setState, onChange] = useSetState ({ - query: '', + const [state, setState, onChange] = useSetState({ + query: "", roleOption: roleOptions[0], userOption: null, }); - const loadOptions = useCallback (async (query, callback) => { - const users = await debouncedSearchAPI (query); - const outUsers = users.filter (user => !members.find (member => member._id === user._id)); - const options = outUsers.map (user => ({ - ...user, - value: user._id, - label: `${user.username} - (${user.koreanName || user.name})`, - })); - callback (options); - }, [members]); + const loadOptions = useCallback( + async (query, callback) => { + const users = await debouncedSearchAPI(query); + const outUsers = users.filter((user) => !members.find((member) => member._id === user._id)); + const options = outUsers.map((user) => ({ + ...user, + value: user._id, + label: `${user.username} - (${user.koreanName || user.name})`, + })); + callback(options); + }, + [members], + ); - const addMember = useCallback (() => { - const { userOption: { value: userId }, roleOption: { value: role } } = state; - if (!window.confirm (alerts.addMember)) return; - dispatch (profileActions.addGroupMember ({ groupName: name, userId, role })) - .catch (error => alert (error.error)); + const addMember = useCallback(() => { + const { + userOption: { value: userId }, + roleOption: { value: role }, + } = state; + if (!window.confirm(alerts.addMember)) return; + dispatch(profileActions.addGroupMember({ groupName: name, userId, role })).catch((error) => + alert(error.error), + ); }, [state, dispatch]); - const updateMember = useCallback ((userId, role) => { - if (!window.confirm (alerts.updateMember)) return; - dispatch (profileActions.updateGroupMember ({ groupName: name, userId, role })) - .catch (error => alert (error.error)); - }, [dispatch]); - const removeMember = useCallback (userId => { - if (!window.confirm (alerts.deleteMember)) return; - dispatch (profileActions.removeGroupMember ({ groupName: name, userId })) - .catch (error => alert (error.error)); - }, [dispatch]); + const updateMember = useCallback( + (userId, role) => { + if (!window.confirm(alerts.updateMember)) return; + dispatch(profileActions.updateGroupMember({ groupName: name, userId, role })).catch((error) => + alert(error.error), + ); + }, + [dispatch], + ); + const removeMember = useCallback( + (userId) => { + if (!window.confirm(alerts.deleteMember)) return; + dispatch(profileActions.removeGroupMember({ groupName: name, userId })).catch((error) => + alert(error.error), + ); + }, + [dispatch], + ); const { userOption, roleOption } = state; return ( @@ -67,7 +82,10 @@ const GroupMembersSetting = ({ profile }) => {

{name} 멤버 관리

-

관리자는 그룹의 멤버와 자보를 관리할 수 있으며, 편집자는 자보를 업로드 및 수정할 수 있습니다.

+

+ 관리자는 그룹의 멤버와 자보를 관리할 수 있으며, 편집자는 자보를 업로드 및 수정할 수 + 있습니다. +

{ value={userOption} cacheOptions loadOptions={loadOptions} - onInputChange={newValue => setState ({ query: newValue })} - onChange={newOption => setState ({ userOption: newOption })} + onInputChange={(newValue) => setState({ query: newValue })} + onChange={(newOption) => setState({ userOption: newOption })} /> setState ({ roleOption: newOption })} + onChange={(newOption) => setState({ roleOption: newOption })} isClearable={false} width={100} /> @@ -90,16 +108,14 @@ const GroupMembersSetting = ({ profile }) => { ( - - ) - } + renderItem={({ role, user }) => ( + + )} />
@@ -110,4 +126,4 @@ GroupMembersSetting.propTypes = { profile: GroupType.isRequired, }; -export default withGroupProfile (GroupMembersSetting, true); +export default withGroupProfile(GroupMembersSetting, true); diff --git a/src/components/pages/SettingsPage/GroupProfileSetting.js b/src/components/pages/SettingsPage/GroupProfileSetting.js index bc760fb9..92a91c41 100644 --- a/src/components/pages/SettingsPage/GroupProfileSetting.js +++ b/src/components/pages/SettingsPage/GroupProfileSetting.js @@ -1,81 +1,100 @@ -import React, { - useCallback, useEffect, useState, -} from 'react'; -import PropTypes from 'prop-types'; -import { useHistory } from 'react-router-dom'; -import { useDispatch } from 'react-redux'; - -import SimpleSelect from 'molecules/SimpleSelect'; -import StyledQuill from 'organisms/StyledQuill'; -import Footer from 'templates/Footer'; -import Header from 'templates/Header'; - -import { updateGroupInfo, updateGroupInfoWithImage } from 'store/reducers/auth'; -import useSetState from 'hooks/useSetState'; -import { GroupType } from 'lib/propTypes'; -import { cropImage, dataURLToBlob } from 'lib/utils'; -import { GROUP_CATEGORIES, GROUP_CATEGORIES_2, GROUP_CATEGORY_HIERARCHIY } from 'lib/variables'; - -import groupDefaultProfile from 'static/images/groupDefaultProfile.png'; +import React, { useCallback, useEffect, useState } from "react"; +import PropTypes from "prop-types"; +import { useHistory } from "react-router-dom"; +import { useDispatch } from "react-redux"; + +import SimpleSelect from "components/molecules/SimpleSelect"; +import StyledQuill from "components/organisms/StyledQuill"; +import Footer from "components/templates/Footer"; +import Header from "components/templates/Header"; + +import { updateGroupInfo, updateGroupInfoWithImage } from "store/reducers/auth"; +import useSetState from "hooks/useSetState"; +import { GroupType } from "lib/propTypes"; +import { cropImage, dataURLToBlob } from "lib/utils"; +import { GROUP_CATEGORIES, GROUP_CATEGORIES_2, GROUP_CATEGORY_HIERARCHIY } from "lib/variables"; + +import groupDefaultProfile from "static/images/groupDefaultProfile.png"; import { - AddCategoryW, ErrorComponent, - FooterStyle, FormGroup, Page, Submit, -} from './Setting.styled'; -import withGroupProfile from './withGroupProfile'; + AddCategoryW, + ErrorComponent, + FooterStyle, + FormGroup, + Page, + Submit, +} from "./Setting.styled"; +import withGroupProfile from "./withGroupProfile"; -const categoryOptions = GROUP_CATEGORIES.map (category => ( - { value: category, label: category } -)); +const categoryOptions = GROUP_CATEGORIES.map((category) => ({ value: category, label: category })); -const selectForm = category => ({ value: category, label: category }); +const selectForm = (category) => ({ value: category, label: category }); const ProfileForm = ({ initialValue, category, newProfilePhoto }) => { - const dispatch = useDispatch (); - const history = useHistory (); - const [state, setState, onChange] = useSetState (initialValue); - const [categoryOption, setCategoryOption] = useState (selectForm (category[0])); - const [categoryOption2, setCategoryOption2] = useState (category.length > 1 ? selectForm (category[1]) : ''); - useEffect (() => setState (initialValue), [initialValue]); - const [error, setError] = useState (); + const dispatch = useDispatch(); + const history = useHistory(); + const [state, setState, onChange] = useSetState(initialValue); + const [categoryOption, setCategoryOption] = useState(selectForm(category[0])); + const [categoryOption2, setCategoryOption2] = useState( + category.length > 1 ? selectForm(category[1]) : "", + ); + useEffect(() => setState(initialValue), [initialValue]); + const [error, setError] = useState(); const { name, description, subtitle } = state; const hasHierarchy = categoryOption.value in GROUP_CATEGORY_HIERARCHIY; const categoryOptions2 = hasHierarchy - ? GROUP_CATEGORY_HIERARCHIY[categoryOption.value].map (category => ( - { value: category, label: category } - )) : []; - - const handleSubmit = useCallback (e => { - e.preventDefault (); - const category = categoryOption2 ? [categoryOption.value, categoryOption2.value] : [categoryOption.value]; - let updateCall = () => dispatch (updateGroupInfo ({ - curName: initialValue.name, name, description, subtitle, category: JSON.stringify (category), - })); - if (newProfilePhoto) { - const category = categoryOption2 ? [categoryOption.value, categoryOption2.value] : [categoryOption.value]; - const formData = new FormData (); - formData.append ('name', name); - formData.append ('description', description); - formData.append ('subtitle', subtitle); - formData.append ('category', JSON.stringify (category)); - formData.append ('img', newProfilePhoto); - updateCall = () => dispatch (updateGroupInfoWithImage ({ curName: initialValue.name, formData })); - } - - updateCall () - .then (() => { - history.replace (`/settings/group/${name}/profile`); - history.push (`/${name}`); - }) - .catch (err => { - setError (err); - alert (err.error); - }); - }, [state, categoryOption, categoryOption2]); - - const onChangeDescription = e => { - setState ({ description: e }); + ? GROUP_CATEGORY_HIERARCHIY[categoryOption.value].map((category) => ({ + value: category, + label: category, + })) + : []; + + const handleSubmit = useCallback( + (e) => { + e.preventDefault(); + const category = categoryOption2 + ? [categoryOption.value, categoryOption2.value] + : [categoryOption.value]; + let updateCall = () => + dispatch( + updateGroupInfo({ + curName: initialValue.name, + name, + description, + subtitle, + category: JSON.stringify(category), + }), + ); + if (newProfilePhoto) { + const category = categoryOption2 + ? [categoryOption.value, categoryOption2.value] + : [categoryOption.value]; + const formData = new FormData(); + formData.append("name", name); + formData.append("description", description); + formData.append("subtitle", subtitle); + formData.append("category", JSON.stringify(category)); + formData.append("img", newProfilePhoto); + updateCall = () => + dispatch(updateGroupInfoWithImage({ curName: initialValue.name, formData })); + } + + updateCall() + .then(() => { + history.replace(`/settings/group/${name}/profile`); + history.push(`/${name}`); + }) + .catch((err) => { + setError(err); + alert(err.error); + }); + }, + [state, categoryOption, categoryOption2], + ); + + const onChangeDescription = (e) => { + setState({ description: e }); }; return ( @@ -101,30 +120,30 @@ const ProfileForm = ({ initialValue, category, newProfilePhoto }) => { { - setCategoryOption (newOption); + onChange={(newOption) => { + setCategoryOption(newOption); // newOption.value const hasHierarchy = newOption.value in GROUP_CATEGORY_HIERARCHIY; const categoryOptions2 = hasHierarchy - ? GROUP_CATEGORY_HIERARCHIY[newOption.value].map (category => ( - { value: category, label: category } - )) : []; - setCategoryOption2 (categoryOptions2[0]); + ? GROUP_CATEGORY_HIERARCHIY[newOption.value].map((category) => ({ + value: category, + label: category, + })) + : []; + setCategoryOption2(categoryOptions2[0]); }} isClearable={false} width="100%" /> - { - hasHierarchy && ( - setCategoryOption2 (newOption)} - isClearable={false} - width="100%" - /> - ) - } + {hasHierarchy && ( + setCategoryOption2(newOption)} + isClearable={false} + width="100%" + /> + )} @@ -149,9 +168,9 @@ const ProfileForm = ({ initialValue, category, newProfilePhoto }) => { theme="bubble" modules={{ toolbar: [ - ['bold', 'underline', 'strike'], - [{ list: 'ordered' }, { list: 'bullet' }, { indent: '+1' }, { indent: '-1' }], - ['link'], + ["bold", "underline", "strike"], + [{ list: "ordered" }, { list: "bullet" }, { indent: "+1" }, { indent: "-1" }], + ["link"], ], }} groupSetting @@ -168,7 +187,7 @@ const ProfileForm = ({ initialValue, category, newProfilePhoto }) => { }; ProfileForm.propTypes = { - initialValue: PropTypes.shape ({ + initialValue: PropTypes.shape({ name: PropTypes.string.isRequired, description: PropTypes.string.isRequired, }).isRequired, @@ -177,19 +196,17 @@ ProfileForm.propTypes = { }; const GroupProfileSetting = ({ profile }) => { - const { - name = '', profilePhoto, description = '', subtitle = '', category = [], - } = profile; + const { name = "", profilePhoto, description = "", subtitle = "", category = [] } = profile; - const [profilePreview, setProfilePreview] = useState (profilePhoto); - const [newProfilePhoto, setNewProfilePhoto] = useState (null); + const [profilePreview, setProfilePreview] = useState(profilePhoto); + const [newProfilePhoto, setNewProfilePhoto] = useState(null); - const handlePhotoChange = async e => { + const handlePhotoChange = async (e) => { const file = e.target.files[0]; - const imageSrc = await cropImage (file, 1); - const blob = dataURLToBlob (imageSrc); - setNewProfilePhoto (blob); - setProfilePreview (imageSrc); + const imageSrc = await cropImage(file, 1); + const blob = dataURLToBlob(imageSrc); + setNewProfilePhoto(blob); + setProfilePreview(imageSrc); }; return ( @@ -199,22 +216,20 @@ const GroupProfileSetting = ({ profile }) => {

그룹 프로필 편집

그룹 프로필을 수정할 수 있습니다.

- { - profilePreview - ? profile photo - : default profile img - } + {profilePreview ? ( + profile photo + ) : ( + default profile img + )} - @@ -232,4 +247,4 @@ GroupProfileSetting.propTypes = { profile: GroupType.isRequired, }; -export default withGroupProfile (GroupProfileSetting, true); +export default withGroupProfile(GroupProfileSetting, true); diff --git a/src/components/pages/SettingsPage/Main.js b/src/components/pages/SettingsPage/Main.js index b9f23371..1b483247 100644 --- a/src/components/pages/SettingsPage/Main.js +++ b/src/components/pages/SettingsPage/Main.js @@ -1,29 +1,26 @@ -import React from 'react'; -import { - Redirect, - Route, Switch, useRouteMatch, -} from 'react-router-dom'; -import styled from 'styled-components'; +import React from "react"; +import { Redirect, Route, Switch, useRouteMatch } from "react-router-dom"; +import styled from "styled-components"; -import { NotFound } from 'pages'; +import { NotFound } from "components/pages"; -import pToP from '../../../hoc/paramsToProps'; -import GroupApply from './GroupApply'; -import GroupMembersSetting from './GroupMembersSetting'; -import GroupProfileSetting from './GroupProfileSetting'; -import ProfileSetting from './ProfileSetting'; +import pToP from "../../../hoc/paramsToProps"; +import GroupApply from "./GroupApply"; +import GroupMembersSetting from "./GroupMembersSetting"; +import GroupProfileSetting from "./GroupProfileSetting"; +import ProfileSetting from "./ProfileSetting"; const SettingsWrapper = styled.section``; const Main = () => { - const { path } = useRouteMatch (); + const { path } = useRouteMatch(); return ( - - + + diff --git a/src/components/pages/SettingsPage/ProfileSetting.js b/src/components/pages/SettingsPage/ProfileSetting.js index 1407183b..495edb01 100644 --- a/src/components/pages/SettingsPage/ProfileSetting.js +++ b/src/components/pages/SettingsPage/ProfileSetting.js @@ -1,88 +1,82 @@ -import React, { - useCallback, useMemo, - useState, -} from 'react'; -import PropTypes from 'prop-types'; -import { useHistory } from 'react-router-dom'; -import { useDispatch, useSelector } from 'react-redux'; -import FormControl from '@material-ui/core/FormControl'; -import FormHelperText from '@material-ui/core/FormHelperText'; -import AwesomeDebouncePromise from 'awesome-debounce-promise'; -import get from 'lodash.get'; - -import Footer from 'templates/Footer'; -import Header from 'templates/Header'; - -import { updateUserInfo, updateUserInfoWithImage } from 'store/reducers/auth'; -import useSetState from 'hooks/useSetState'; -import { validateName as validateNameAPI } from 'lib/api/profile'; -import { cropImage, dataURLToBlob, validateName } from 'lib/utils'; - -import defaultProfile from 'static/images/defaultProfile.png'; - -import { - ErrorComponent, - FooterStyle, FormGroup, Page, Submit, Success, -} from './Setting.styled'; +import React, { useCallback, useMemo, useState } from "react"; +import PropTypes from "prop-types"; +import { useHistory } from "react-router-dom"; +import { useDispatch, useSelector } from "react-redux"; +import FormControl from "@material-ui/core/FormControl"; +import FormHelperText from "@material-ui/core/FormHelperText"; +import AwesomeDebouncePromise from "awesome-debounce-promise"; +import get from "lodash.get"; +import Footer from "components/templates/Footer"; +import Header from "components/templates/Header"; + +import { updateUserInfo, updateUserInfoWithImage } from "store/reducers/auth"; +import useSetState from "hooks/useSetState"; +import { validateName as validateNameAPI } from "lib/api/profile"; +import { cropImage, dataURLToBlob, validateName } from "lib/utils"; + +import defaultProfile from "static/images/defaultProfile.png"; + +import { ErrorComponent, FooterStyle, FormGroup, Page, Submit, Success } from "./Setting.styled"; const ProfileForm = ({ initialValue, newProfilePhoto }) => { - const dispatch = useDispatch (); - const history = useHistory (); + const dispatch = useDispatch(); + const history = useHistory(); - const debouncedValidateName = useMemo (() => { + const debouncedValidateName = useMemo(() => { const effectiveValidateName = ({ name }) => { if (name === initialValue.username) { - return Promise.resolve (true); + return Promise.resolve(true); } - if (!validateName (name)) { - return Promise.reject (new Error ('invalid')); + if (!validateName(name)) { + return Promise.reject(new Error("invalid")); } - return validateNameAPI ({ name }); + return validateNameAPI({ name }); }; - return AwesomeDebouncePromise (effectiveValidateName, 800); + return AwesomeDebouncePromise(effectiveValidateName, 800); }, [initialValue]); - const [state, setState, onChangeHandler] = useSetState ({ + const [state, setState, onChangeHandler] = useSetState({ ...initialValue, success: false, error: null, }); - const [nameInvalidError, setNameInvalid] = useState (false); - const { - username, description, error, success, - } = state; - - const handleSubmit = useCallback (e => { - e.preventDefault (); - const update = { username, description }; - let updateCall = () => dispatch (updateUserInfo (update)); - if (newProfilePhoto) { - const formData = new FormData (); - formData.append ('img', newProfilePhoto); - formData.append ('username', username); - formData.append ('description', description); - updateCall = () => dispatch (updateUserInfoWithImage (formData)); - } - updateCall () - .then (() => history.push (`/${username}`)) - .catch (error => { - setState ({ ...update, success: false, error }); - alert (error.error); - }); - }, [username, description, newProfilePhoto]); - - const onChange = e => { - setState ({ success: false, error: null }); - onChangeHandler (e); + const [nameInvalidError, setNameInvalid] = useState(false); + const { username, description, error, success } = state; + + const handleSubmit = useCallback( + (e) => { + e.preventDefault(); + const update = { username, description }; + let updateCall = () => dispatch(updateUserInfo(update)); + if (newProfilePhoto) { + const formData = new FormData(); + formData.append("img", newProfilePhoto); + formData.append("username", username); + formData.append("description", description); + updateCall = () => dispatch(updateUserInfoWithImage(formData)); + } + updateCall() + .then(() => history.push(`/${username}`)) + .catch((error) => { + setState({ ...update, success: false, error }); + alert(error.error); + }); + }, + [username, description, newProfilePhoto], + ); + + const onChange = (e) => { + setState({ success: false, error: null }); + onChangeHandler(e); }; - const onChangeName = e => { - onChange (e); - debouncedValidateName ({ name: e.target.value }) // TODO: Unsubscribe on unmount - .then (() => setNameInvalid (false)) - .catch (setNameInvalid); + const onChangeName = (e) => { + onChange(e); + debouncedValidateName({ name: e.target.value }) // TODO: Unsubscribe on unmount + .then(() => setNameInvalid(false)) + .catch(setNameInvalid); }; return ( @@ -91,7 +85,7 @@ const ProfileForm = ({ initialValue, newProfilePhoto }) => { - + { value={username} onChange={onChangeName} /> - { - nameInvalidError - ? {nameInvalidError.message} - : '' - } + {nameInvalidError ? ( + {nameInvalidError.message} + ) : ( + "" + )}
@@ -130,7 +124,7 @@ const ProfileForm = ({ initialValue, newProfilePhoto }) => { }; ProfileForm.propTypes = { - initialValue: PropTypes.shape ({ + initialValue: PropTypes.shape({ username: PropTypes.string, description: PropTypes.string, }).isRequired, @@ -138,19 +132,19 @@ ProfileForm.propTypes = { newProfilePhoto: PropTypes.object, }; -const UserProfileSetting = props => { - const info = useSelector (state => get (state, ['auth', 'info'])); - const { username = '', profilePhoto, description = '' } = info; +const UserProfileSetting = (props) => { + const info = useSelector((state) => get(state, ["auth", "info"])); + const { username = "", profilePhoto, description = "" } = info; - const [profilePreview, setProfilePreview] = useState (profilePhoto); - const [newProfilePhoto, setNewProfilePhoto] = useState (null); + const [profilePreview, setProfilePreview] = useState(profilePhoto); + const [newProfilePhoto, setNewProfilePhoto] = useState(null); - const handlePhotoChange = async e => { + const handlePhotoChange = async (e) => { const file = e.target.files[0]; - const imageSrc = await cropImage (file, 1); - const blob = dataURLToBlob (imageSrc); - setNewProfilePhoto (blob); - setProfilePreview (imageSrc); + const imageSrc = await cropImage(file, 1); + const blob = dataURLToBlob(imageSrc); + setNewProfilePhoto(blob); + setProfilePreview(imageSrc); }; return ( @@ -160,22 +154,20 @@ const UserProfileSetting = props => {

프로필 편집

프로필을 수정할 수 있습니다.

- { - profilePreview - ? profile photo - : default profile img - } + {profilePreview ? ( + profile photo + ) : ( + default profile img + )} - diff --git a/src/components/pages/SettingsPage/Setting.styled.js b/src/components/pages/SettingsPage/Setting.styled.js index 14e07afd..212f8945 100644 --- a/src/components/pages/SettingsPage/Setting.styled.js +++ b/src/components/pages/SettingsPage/Setting.styled.js @@ -1,4 +1,4 @@ -import styled, { css } from 'styled-components'; +import styled, { css } from "styled-components"; export const Page = styled.section` padding: 64px 0 74px 0; @@ -36,7 +36,9 @@ Page.Body = styled.div` font-size: 24px; line-height: 27px; } - p { padding-bottom: 32px } + p { + padding-bottom: 32px; + } } `; @@ -52,7 +54,8 @@ Page.Body.ProfileInfo = styled.div` label { display: inline-block; } - button, .button { + button, + .button { height: 30px; font-size: 12px; font-weight: bold; @@ -61,7 +64,7 @@ Page.Body.ProfileInfo = styled.div` padding: 8px 12px; border-radius: 15px; border: 1px solid #143441; - background-color: #F8F8F8; + background-color: #f8f8f8; cursor: pointer; /* &:hover { background-color: #143441; @@ -73,7 +76,8 @@ Page.Body.ProfileInfo = styled.div` width: 105px; height: 105px; } - button, .button { + button, + .button { margin: 12px 0 32px 0; } } @@ -90,7 +94,7 @@ export const FormGroup = styled.div` border: none; outline: none; border-radius: 4px; - background-color: #F4F4F4; + background-color: #f4f4f4; font-size: 16px; line-height: 16px; font-weight: 500; @@ -114,15 +118,18 @@ FormGroup.Label = styled.div` font-size: 16px; line-height: 20px; margin: 0; - ${props => (props.required ? css` - &::after { - display: inline-block; - margin-left: 4px; - color: #f66; - font-weight: 300; - content: "*"; - } - ` : css``)}; + ${(props) => + props.required + ? css` + &::after { + display: inline-block; + margin-left: 4px; + color: #f66; + font-weight: 300; + content: "*"; + } + ` + : css``}; `; export const FooterStyle = styled.div` @@ -139,11 +146,11 @@ export const Submit = styled.button` font-size: 16px; line-height: 18px; color: white; - background-color: #FF5D5D; + background-color: #ff5d5d; border: 0; &:disabled { - background: #F8F8F8; - color: #8F8F8F; + background: #f8f8f8; + color: #8f8f8f; cursor: not-allowed; } `; @@ -157,21 +164,21 @@ export const ErrorComponent = styled.div` export const AddMember = styled.section` display: flex; - >div { + > div { margin-right: 8px; } - >button { + > button { width: 78px; height: 38px; background: #143441; border: 1px solid #143441; box-sizing: border-box; border-radius: 4px; - + font-weight: bold; font-size: 16px; line-height: 18px; - color: #FFFFFF; + color: #ffffff; } `; @@ -179,11 +186,17 @@ export const AddCategoryW = styled.section` display: flex; margin: 8px 0 48px 0; - >div { max-width: 50% } - >div:first-child { margin-right: 14px } + > div { + max-width: 50%; + } + > div:first-child { + margin-right: 14px; + } @media (max-width: 640px) { - >div:first-child { margin-right: 15px } + > div:first-child { + margin-right: 15px; + } } `; @@ -214,7 +227,7 @@ export const BusinessW = styled.section` padding: 0; } p { - color: #8F8F8F; + color: #8f8f8f; font-size: 12px; padding: 0; } @@ -228,9 +241,9 @@ export const BusinessW = styled.section` justify-content: flex-end; width: 144px; height: 38px; - background-color: #F4F4F4; + background-color: #f4f4f4; border-radius: 4px; - color: #8F8F8F; + color: #8f8f8f; font-size: 16px; font-weight: bold; border: 0; @@ -249,8 +262,12 @@ export const BusinessW = styled.section` flex-direction: column; align-items: flex-start; justify-content: center; - p { margin-bottom: 36px } - .business-btn { flex: none } + p { + margin-bottom: 36px; + } + .business-btn { + flex: none; + } } } `; diff --git a/src/components/pages/SettingsPage/index.js b/src/components/pages/SettingsPage/index.js index 47dec621..0fdf55f5 100644 --- a/src/components/pages/SettingsPage/index.js +++ b/src/components/pages/SettingsPage/index.js @@ -1 +1 @@ -export { default } from './Main'; +export { default } from "./Main"; diff --git a/src/components/pages/SettingsPage/withGroupProfile.js b/src/components/pages/SettingsPage/withGroupProfile.js deleted file mode 100644 index 74917f02..00000000 --- a/src/components/pages/SettingsPage/withGroupProfile.js +++ /dev/null @@ -1,24 +0,0 @@ -import React, { useEffect, useMemo } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; -import get from 'lodash.get'; - -import { NotFound } from 'pages'; - -import { getProfile } from 'store/reducers/profile'; - -const withGroupProfile = (WrappedComponent, isPrivate = false) => props => { - const dispatch = useDispatch (); - const { groupName } = props; - - useEffect (() => { - dispatch (getProfile (groupName)); - }, [groupName]); - - const profile = useSelector (state => get (state, ['profile', 'profiles', groupName])); - if (!profile) return null; - if (profile.error) return ; - if (isPrivate && !profile.myRole) return ; - return ; -}; - -export default withGroupProfile; diff --git a/src/components/pages/SettingsPage/withGroupProfile.tsx b/src/components/pages/SettingsPage/withGroupProfile.tsx new file mode 100644 index 00000000..9ab3fe13 --- /dev/null +++ b/src/components/pages/SettingsPage/withGroupProfile.tsx @@ -0,0 +1,32 @@ +import React, { useEffect } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import get from "lodash.get"; + +import { NotFound } from "components/pages"; + +import { getProfile } from "store/reducers/profile"; + +const withGroupProfile = ( + // TODO: add profile types + // eslint-disable-next-line @typescript-eslint/no-explicit-any + WrappedComponent: React.FC

, + isPrivate = false, +) => { + const ComponentWithGroupProfile: React.FC

= (props) => { + const dispatch = useDispatch(); + + useEffect(() => { + dispatch(getProfile(props.groupName)); + }, [props.groupName, dispatch]); + + const profile = useSelector((state) => get(state, ["profile", "profiles", props.groupName])); + if (!profile) return null; + if (profile.error) return ; + if (isPrivate && !profile.myRole) return ; + return ; + }; + + return ComponentWithGroupProfile; +}; + +export default withGroupProfile; diff --git a/src/components/pages/ZaboPage/Main.js b/src/components/pages/ZaboPage/Main.js index 088d2bd0..a66a977e 100644 --- a/src/components/pages/ZaboPage/Main.js +++ b/src/components/pages/ZaboPage/Main.js @@ -1,20 +1,20 @@ -import React from 'react'; -import { Route, Switch, useRouteMatch } from 'react-router-dom'; +import React from "react"; +import { Route, Switch, useRouteMatch } from "react-router-dom"; -import Header from 'templates/Header'; -import { NotFound, ZaboDetailPage, ZaboEditPage } from 'pages'; +import { NotFound, ZaboDetailPage, ZaboEditPage } from "components/pages"; +import Header from "components/templates/Header"; -import paramsToProps from '../../../hoc/paramsToProps'; -import { ZaboPageWrapper } from './ZaboPage.styled'; +import paramsToProps from "../../../hoc/paramsToProps"; +import { ZaboPageWrapper } from "./ZaboPage.styled"; const Main = () => { - const { path } = useRouteMatch (); + const { path } = useRouteMatch(); return (

- - + + diff --git a/src/components/pages/ZaboPage/ZaboDetailPage.js b/src/components/pages/ZaboPage/ZaboDetailPage.js index 5fedb281..29407096 100644 --- a/src/components/pages/ZaboPage/ZaboDetailPage.js +++ b/src/components/pages/ZaboPage/ZaboDetailPage.js @@ -1,91 +1,85 @@ -import React, { useCallback, useEffect } from 'react'; -import PropTypes from 'prop-types'; -import { Link, useHistory, useRouteMatch } from 'react-router-dom'; -import { useDispatch, useSelector } from 'react-redux'; -import Carousel from 'react-airbnb-carousel'; -import { Helmet } from 'react-helmet'; -import Tooltip from '@material-ui/core/Tooltip'; -import get from 'lodash.get'; -import moment from 'moment'; +import React, { useCallback, useEffect } from "react"; +import PropTypes from "prop-types"; +import { Link, useHistory, useRouteMatch } from "react-router-dom"; +import { useDispatch, useSelector } from "react-redux"; +import Carousel from "react-airbnb-carousel"; +import { Helmet } from "react-helmet"; +import Tooltip from "@material-ui/core/Tooltip"; +import get from "lodash.get"; +import moment from "moment"; -import Button from 'atoms/Button'; -import DueDate from 'atoms/DueDate'; -import StatBox from 'molecules/StatBox'; -import StyledQuill from 'organisms/StyledQuill'; -import ZaboList from 'templates/ZaboList'; +import Button from "components/atoms/Button"; +import DueDate from "components/atoms/DueDate"; +import StatBox from "components/molecules/StatBox"; +import StyledQuill from "components/organisms/StyledQuill"; +import ZaboList from "components/templates/ZaboList"; -import { followProfile, getProfile } from 'store/reducers/profile'; -import { deleteZabo as deleteZaboAction } from 'store/reducers/zabo'; -import withZabo from 'hoc/withZabo'; -import { ZaboType } from 'lib/propTypes'; -import { - getLabeledTimeDiff, isAuthedSelector, to2Digits, withAuth, -} from 'lib/utils'; +import { followProfile, getProfile } from "store/reducers/profile"; +import { deleteZabo as deleteZaboAction } from "store/reducers/zabo"; +import withZabo from "hoc/withZabo"; +import { ZaboType } from "lib/propTypes"; +import { getLabeledTimeDiff, isAuthedSelector, to2Digits, withAuth } from "lib/utils"; -import groupDefaultProfile from 'static/images/groupDefaultProfile.png'; +import groupDefaultProfile from "static/images/groupDefaultProfile.png"; -import { alerts } from '../../../lib/variables'; -import { PosterW } from '../../organisms/ZaboCard/ZaboCard.styled'; -import { CategoryW, ZaboPageWrapper } from './ZaboPage.styled'; +import { alerts } from "../../../lib/variables"; +import { PosterW } from "../../organisms/ZaboCard/ZaboCard.styled"; +import { CategoryW, ZaboPageWrapper } from "./ZaboPage.styled"; -const OwnerInfo = ({ - zabo: { - owner, isMyZabo, createdBy = {}, _id, - }, -}) => { - const { url } = useRouteMatch (); - const isAuthed = useSelector (isAuthedSelector); - const history = useHistory (); +const OwnerInfo = ({ zabo: { owner, isMyZabo, createdBy = {}, _id } }) => { + const { url } = useRouteMatch(); + const isAuthed = useSelector(isAuthedSelector); + const history = useHistory(); const { name, profilePhoto } = owner; - const dispatch = useDispatch (); - useEffect (() => { + const dispatch = useDispatch(); + useEffect(() => { if (!name) return; - dispatch (getProfile (name)); + dispatch(getProfile(name)); }, [name]); - const follow = useCallback (() => { + const follow = useCallback(() => { if (!name) return; - if (withAuth (history, isAuthed)) dispatch (followProfile ({ name })); + if (withAuth(history, isAuthed)) dispatch(followProfile({ name })); }, [name]); - const deleteZabo = useCallback (() => { - dispatch (deleteZaboAction ({ zaboId: _id })) - .then (res => { + const deleteZabo = useCallback(() => { + dispatch(deleteZaboAction({ zaboId: _id })) + .then((res) => { window.location.href = `/${owner.name}`; }) - .catch (error => { - alert ('Error'); + .catch((error) => { + alert("Error"); }); }); - const following = useSelector (state => get (state, ['profile', 'profiles', name, 'following'])); + const following = useSelector((state) => get(state, ["profile", "profiles", name, "following"])); return (
- { - ('profilePhoto' in owner) - ? group profile photo - : default profile img - } + {"profilePhoto" in owner ? ( + group profile photo + ) : ( + default profile img + )}
-
{name || 'anonymous'}
+
{name || "anonymous"}
{isMyZabo &&
게시자 {createdBy.username}
}
- { - typeof following !== 'undefined' - && ( - <> -
·
- { - following - ?

팔로우 취소

- :

팔로우

- } - - ) - } - {isMyZabo - && ( - + {typeof following !== "undefined" && ( + <> +
·
+ {following ? ( +

+ 팔로우 취소 +

+ ) : ( +

+ 팔로우 +

+ )} + + )} + {isMyZabo && ( + @@ -94,9 +88,10 @@ const OwnerInfo = ({ border="none" color="white" onClick={() => { - if (window.confirm (alerts.del)) deleteZabo (); + if (window.confirm(alerts.del)) deleteZabo(); }} - >게시물 삭제 + > + 게시물 삭제 )} @@ -110,27 +105,43 @@ OwnerInfo.propTypes = { OwnerInfo.defaultProps = {}; -const ZaboDetailPage = props => { +const ZaboDetailPage = (props) => { const { zabo, zaboId } = props; const { - title, owner = {}, schedules, createdAt, description, category = [], photos = [{}], - isLiked, likesCount, isPinned, pinsCount, views, effectiveViews, isMyZabo, createdBy, + title, + owner = {}, + schedules, + createdAt, + description, + category = [], + photos = [{}], + isLiked, + likesCount, + isPinned, + pinsCount, + views, + effectiveViews, + isMyZabo, + createdBy, } = zabo; const schedule = schedules[0]; - const timePast = getLabeledTimeDiff (createdAt, 60, 60, 6, 0); - const due = schedule ? moment (schedule.startAt).diff (moment (), 'days') : 0; - const dueFormat = schedule && moment (schedule.startAt).format ('MM/DD h:mm'); - const stats = [{ - type: 'like', - count: likesCount, - zaboId, - active: isLiked, - }, { - type: 'pin', - count: pinsCount, - zaboId, - active: isPinned, - }]; + const timePast = getLabeledTimeDiff(createdAt, 60, 60, 6, 0); + const due = schedule ? moment(schedule.startAt).diff(moment(), "days") : 0; + const dueFormat = schedule && moment(schedule.startAt).format("MM/DD h:mm"); + const stats = [ + { + type: "like", + count: likesCount, + zaboId, + active: isLiked, + }, + { + type: "pin", + count: pinsCount, + zaboId, + active: isPinned, + }, + ]; return ( <> @@ -144,7 +155,7 @@ const ZaboDetailPage = props => { url)} + imageUrls={photos.map(({ url }) => url)} ratio={photos[0].width / photos[0].height} overlay /> @@ -153,7 +164,7 @@ const ZaboDetailPage = props => {
    - {category.map (cat => ( + {category.map((cat) => (
  • #{cat}
  • ))}
@@ -163,18 +174,16 @@ const ZaboDetailPage = props => {
-
- {timePast} -
+
{timePast}
·
-
- 조회수 {views.toLocaleString ()} -
+
조회수 {views.toLocaleString()}
- {stats.map (stat => )} + {stats.map((stat) => ( + + ))}
@@ -187,17 +196,11 @@ const ZaboDetailPage = props => {

{schedule.title}

-
- {dueFormat} -
+
{dueFormat}
)}
- +
@@ -216,4 +219,4 @@ ZaboDetailPage.propTypes = { zaboId: PropTypes.string.isRequired, }; -export default withZabo (ZaboDetailPage); +export default withZabo(ZaboDetailPage); diff --git a/src/components/pages/ZaboPage/ZaboEditPage.js b/src/components/pages/ZaboPage/ZaboEditPage.js index a196b368..4ff66dc2 100644 --- a/src/components/pages/ZaboPage/ZaboEditPage.js +++ b/src/components/pages/ZaboPage/ZaboEditPage.js @@ -1,21 +1,19 @@ -import React, { - useEffect, useMemo, useState, -} from 'react'; -import PropTypes from 'prop-types'; -import { Prompt, useHistory } from 'react-router-dom'; -import { useDispatch } from 'react-redux'; -import isEqual from 'lodash.isequal'; +import React, { useEffect, useMemo, useState } from "react"; +import PropTypes from "prop-types"; +import { Prompt, useHistory } from "react-router-dom"; +import { useDispatch } from "react-redux"; +import isEqual from "lodash.isequal"; -import Footer from 'templates/Footer'; -import ZaboUpload from 'templates/ZaboUpload'; -import { FooterStyle, PageWrapper } from 'pages/ZaboUploadPage/ZaboUploadPage.styled'; +import { FooterStyle, PageWrapper } from "components/pages/ZaboUploadPage/ZaboUploadPage.styled"; +import Footer from "components/templates/Footer"; +import ZaboUpload from "components/templates/ZaboUpload"; -import { defaultSchedule } from 'store/reducers/upload'; -import { patchZabo } from 'store/reducers/zabo'; -import withZabo from 'hoc/withZabo'; -import useSetState from 'hooks/useSetState'; -import { ZaboType } from 'lib/propTypes'; -import { alerts, ZABO_CATEGORIES } from 'lib/variables'; +import { defaultSchedule } from "store/reducers/upload"; +import { patchZabo } from "store/reducers/zabo"; +import withZabo from "hoc/withZabo"; +import useSetState from "hooks/useSetState"; +import { ZaboType } from "lib/propTypes"; +import { alerts, ZABO_CATEGORIES } from "lib/variables"; const FooterChild = ({ isValid, submit }) => ( @@ -24,12 +22,12 @@ const FooterChild = ({ isValid, submit }) => (
@@ -42,62 +40,67 @@ FooterChild.propTypes = { }; const ZaboEditPage = ({ zaboId, zabo }) => { - const dispatch = useDispatch (); - const history = useHistory (); - const [changed, setChanged] = useState (false); - const [submit, setSubmit] = useState (false); - useEffect (() => { + const dispatch = useDispatch(); + const history = useHistory(); + const [changed, setChanged] = useState(false); + const [submit, setSubmit] = useState(false); + useEffect(() => { window.onbeforeunload = () => (changed ? true : undefined); }, [changed]); - const { photos: [{ url: preview }] } = zabo; - const newCat = ZABO_CATEGORIES.map (tag => ({ name: tag, clicked: zabo.category.indexOf (tag) >= 0 })); + const { + photos: [{ url: preview }], + } = zabo; + const newCat = ZABO_CATEGORIES.map((tag) => ({ + name: tag, + clicked: zabo.category.indexOf(tag) >= 0, + })); const prevSchedules = zabo.schedules.length ? zabo.schedules : [defaultSchedule]; const prevHasSchedule = !!zabo.schedules.length; - const [state, setState] = useSetState ({ + const [state, setState] = useSetState({ title: zabo.title, description: zabo.description, schedules: prevSchedules, category: newCat, hasSchedule: prevHasSchedule, }); - const { - title, description, schedules, hasSchedule, - } = state; + const { title, description, schedules, hasSchedule } = state; - useEffect (() => { + useEffect(() => { if (!submit) return; if (changed) { - setChanged (false); + setChanged(false); return; } const data = { ...state }; if (!hasSchedule) delete data.schedules; - data.category = data.category.filter (t => t.clicked).map (t => t.name).join ('#'); - dispatch (patchZabo ({ zaboId, data })) - .then (() => { - history.push (`/zabo/${zaboId}`); - }); + data.category = data.category + .filter((t) => t.clicked) + .map((t) => t.name) + .join("#"); + dispatch(patchZabo({ zaboId, data })).then(() => { + history.push(`/zabo/${zaboId}`); + }); }, [state, submit, changed]); - const isValid = useMemo (() => { - const zaboValid = (title && description); + const isValid = useMemo(() => { + const zaboValid = title && description; if (!hasSchedule) return zaboValid; const schedule = schedules[0]; const { title: scheduleTitle, startAt, eventType } = schedule; - const scheduleValid = (scheduleTitle && startAt && eventType); + const scheduleValid = scheduleTitle && startAt && eventType; return zaboValid && scheduleValid; }, [state]); - useEffect (() => { + useEffect(() => { if ( - zabo.title !== title - || zabo.description !== description - || !isEqual (prevSchedules, schedules) + zabo.title !== title || + zabo.description !== description || + !isEqual(prevSchedules, schedules) ) { - setChanged (true); + setChanged(true); } else { - setChanged (false); + setChanged(false); } }, [state]); @@ -108,14 +111,10 @@ const ZaboEditPage = ({ zaboId, zabo }) => { message="저장되지 않은 변경 사항이 있습니다. 페이지를 떠나시겠습니까?" /> - +
- setSubmit (true)} /> + setSubmit(true)} />
); @@ -126,4 +125,4 @@ ZaboEditPage.propTypes = { zabo: ZaboType.isRequired, }; -export default withZabo (ZaboEditPage, true); +export default withZabo(ZaboEditPage, true); diff --git a/src/components/pages/ZaboPage/ZaboPage.styled.js b/src/components/pages/ZaboPage/ZaboPage.styled.js index 99a590b3..88dbf39b 100644 --- a/src/components/pages/ZaboPage/ZaboPage.styled.js +++ b/src/components/pages/ZaboPage/ZaboPage.styled.js @@ -1,4 +1,4 @@ -import styled from 'styled-components'; +import styled from "styled-components"; export const ZaboPageWrapper = styled.div` width: 100%; @@ -23,7 +23,6 @@ ZaboPageWrapper.Detail = styled.div` } `; - ZaboPageWrapper.TwoCol = styled.section` display: flex; flex-direction: row; @@ -75,13 +74,13 @@ ZaboPageWrapper.Info.Header = styled.section` border-radius: 2px; padding: 4px 5px; margin: 0 8px 12px 0; - background: #EEEEEE; - color: #5C5C5C; + background: #eeeeee; + color: #5c5c5c; font-size: 14px; line-height: 16px; } } - + .zabo-page-header-title-group { display: flex; width: 100%; @@ -101,20 +100,24 @@ ZaboPageWrapper.Info.Header = styled.section` } } - .details{ + .details { display: inline-block; font-size: 14px; line-height: 14px; color: #666666; - &:nth-child(1) { padding-right: 8px } - &:nth-child(3) { padding-left: 8px } + &:nth-child(1) { + padding-right: 8px; + } + &:nth-child(3) { + padding-left: 8px; + } @media (max-width: 640px) { font-size: 12px; } } .specialChar { display: inline-block; - color: #8F8F8F; + color: #8f8f8f; vertical-align: middle; } @@ -126,9 +129,9 @@ ZaboPageWrapper.Info.Header = styled.section` ZaboPageWrapper.Info.Body = styled.section` color: #202020; .borderLine { - border: 0.5px solid #E9E9E9; + border: 0.5px solid #e9e9e9; } - + .owner { display: flex; align-items: center; @@ -148,16 +151,18 @@ ZaboPageWrapper.Info.Body = styled.section` border-radius: 50%; margin-right: 10px; } - + .owner-label { display: flex; flex-direction: column; justify-content: center; - .owner-group { + .owner-group { font-size: 16px; line-height: 18px; color: #202020; - &.follow { font-size: 14px; } + &.follow { + font-size: 14px; + } } .owner-creator { margin-top: 2px; @@ -169,7 +174,7 @@ ZaboPageWrapper.Info.Body = styled.section` } .specialChar { display: inline-block; - color: #8F8F8F; + color: #8f8f8f; vertical-align: middle; margin: 0 8px; } @@ -182,7 +187,7 @@ ZaboPageWrapper.Info.Body = styled.section` .unfollow { font-size: 14px; line-height: 16px; - color: #BCBCBC; + color: #bcbcbc; cursor: pointer; } .contents { @@ -231,7 +236,7 @@ export const CategoryW = styled.section` height: 20px; font-size: 12px; color: #797979; - background: #F4F4F4; + background: #f4f4f4; border-radius: 3px; border: 0; margin-right: 8px; @@ -255,6 +260,9 @@ export const CategoryW = styled.section` align-items: flex-start; height: 100%; padding: 14px 20px; - button, h3 { margin-bottom: 5px } + button, + h3 { + margin-bottom: 5px; + } } `; diff --git a/src/components/pages/ZaboPage/index.js b/src/components/pages/ZaboPage/index.js index 47dec621..0fdf55f5 100644 --- a/src/components/pages/ZaboPage/index.js +++ b/src/components/pages/ZaboPage/index.js @@ -1 +1 @@ -export { default } from './Main'; +export { default } from "./Main"; diff --git a/src/components/pages/ZaboUploadPage/ZaboUploadPage.js b/src/components/pages/ZaboUploadPage/ZaboUploadPage.js index a6aa6b74..cb243769 100644 --- a/src/components/pages/ZaboUploadPage/ZaboUploadPage.js +++ b/src/components/pages/ZaboUploadPage/ZaboUploadPage.js @@ -1,48 +1,41 @@ -import React, { - useCallback, useEffect, useMemo, -} from 'react'; -import PropTypes from 'prop-types'; -import { - Prompt, -} from 'react-router-dom'; -import { useDispatch, useSelector } from 'react-redux'; -import SwipeableViews from 'react-swipeable-views'; -import styled from 'styled-components'; -import get from 'lodash.get'; - -import Footer from 'templates/Footer'; -import Header from 'templates/Header'; -import ZaboUpload from 'templates/ZaboUpload'; +import React, { useCallback, useEffect, useMemo } from "react"; +import PropTypes from "prop-types"; +import { Prompt } from "react-router-dom"; +import { useDispatch, useSelector } from "react-redux"; +import SwipeableViews from "react-swipeable-views"; +import styled from "styled-components"; +import get from "lodash.get"; + +import Footer from "components/templates/Footer"; +import Header from "components/templates/Header"; +import ZaboUpload from "components/templates/ZaboUpload"; import { reset, - setGroupSelected, setImagesSeleted, setStep as setReduxStep, + setGroupSelected, + setImagesSeleted, + setStep as setReduxStep, submit, -} from 'store/reducers/upload'; -import { alerts } from 'lib/variables'; +} from "store/reducers/upload"; +import { alerts } from "lib/variables"; -import rightArrow from 'static/images/rightArrow.png'; -import rightGrayArrow from 'static/images/rightGrayArrow.png'; +import rightArrow from "static/images/rightArrow.png"; +import rightGrayArrow from "static/images/rightGrayArrow.png"; -import { - FooterStyle, - PageWrapper, TitleStyle, -} from './ZaboUploadPage.styled'; +import { FooterStyle, PageWrapper, TitleStyle } from "./ZaboUploadPage.styled"; const SlideTitle = ({ step }) => { - const titleList = ['그룹 선택하기', '자보올리기', '정보 입력하기']; + const titleList = ["그룹 선택하기", "자보올리기", "정보 입력하기"]; - const titleTemplate = titleList.map ((elem, idx) => ( + const titleTemplate = titleList.map((elem, idx) => ( -

{ idx + 1 }. { elem }

- { idx !== 2 ? right arrow : '' } +

+ {idx + 1}. {elem} +

+ {idx !== 2 ? right arrow : ""}
)); - return ( - - { titleTemplate } - - ); + return {titleTemplate}; }; const SlideView = ({ step }) => ( @@ -70,45 +63,45 @@ Loading.Inactive = styled.div` border-top: 10px solid gainsboro; `; -const UploadFooter = props => { +const UploadFooter = (props) => { const { prev, next, step } = props; - const dispatch = useDispatch (); - const currentGroup = useSelector (state => get (state, ['auth', 'info', 'currentGroup'])); - const files = useSelector (state => get (state, ['upload', 'images'])); - const info = useSelector (state => get (state, ['upload', 'info'])); - const submitted = useSelector (state => get (state, ['upload', 'submitted'])); + const dispatch = useDispatch(); + const currentGroup = useSelector((state) => get(state, ["auth", "info", "currentGroup"])); + const files = useSelector((state) => get(state, ["upload", "images"])); + const info = useSelector((state) => get(state, ["upload", "info"])); + const submitted = useSelector((state) => get(state, ["upload", "submitted"])); - const validatedNext = useCallback (() => { + const validatedNext = useCallback(() => { // xxSelected : Currently Not Being Used if (step === 0) { - dispatch (setGroupSelected (true)); + dispatch(setGroupSelected(true)); } else if (step === 1) { - dispatch (setImagesSeleted (true)); + dispatch(setImagesSeleted(true)); } else if (step === 2) { - if (window.confirm (alerts.upload)) dispatch (submit (true)); + if (window.confirm(alerts.upload)) dispatch(submit(true)); return; } - next (); + next(); }, [step, currentGroup, files, info]); - const step2Valid = useMemo (() => { - const { - title, description, hasSchedule, schedules, - } = info; - const zaboValid = (title && description); + const step2Valid = useMemo(() => { + const { title, description, hasSchedule, schedules } = info; + const zaboValid = title && description; if (!hasSchedule) return zaboValid; const schedule = schedules[0]; const { title: scheduleTitle, startAt, eventType } = schedule; - const scheduleValid = (scheduleTitle && startAt && eventType); + const scheduleValid = scheduleTitle && startAt && eventType; return zaboValid && scheduleValid; }, [info]); - const isValid = useMemo (() => { + const isValid = useMemo(() => { if (step === 0) { return !!currentGroup; - } if (step === 1) { + } + if (step === 1) { return !!files.length; - } if (step === 2) { + } + if (step === 2) { return step2Valid; } return false; @@ -131,7 +124,7 @@ const UploadFooter = props => {
@@ -145,9 +138,18 @@ const UploadFooter = props => {
- {step > 0 && } - + )} +
@@ -163,11 +165,11 @@ UploadFooter.propTypes = { }; const ZaboUploadPage = () => { - const dispatch = useDispatch (); - const step = useSelector (state => get (state, ['upload', 'step'])); - const setStep = (newStep => dispatch (setReduxStep (newStep))); - const next = useCallback (() => setStep (step + 1), [step]); - const prev = useCallback (() => setStep (step - 1), [step]); + const dispatch = useDispatch(); + const step = useSelector((state) => get(state, ["upload", "step"])); + const setStep = (newStep) => dispatch(setReduxStep(newStep)); + const next = useCallback(() => setStep(step + 1), [step]); + const prev = useCallback(() => setStep(step - 1), [step]); const slideActions = { next, prev }; // useEffect (() => { diff --git a/src/components/pages/ZaboUploadPage/ZaboUploadPage.styled.js b/src/components/pages/ZaboUploadPage/ZaboUploadPage.styled.js index f608c299..c111112d 100644 --- a/src/components/pages/ZaboUploadPage/ZaboUploadPage.styled.js +++ b/src/components/pages/ZaboUploadPage/ZaboUploadPage.styled.js @@ -1,4 +1,4 @@ -import styled, { css } from 'styled-components'; +import styled, { css } from "styled-components"; export const PageWrapper = styled.div` padding-top: 48px; @@ -35,12 +35,15 @@ TitleStyle.elem = styled.div` vertical-align: middle; font-size: 16px; transition: color 0.3s; - ${props => (props.step ? css` - color: #143441; - font-weight: bold; - ` : css` - color: #BCBCBC; - `)} + ${(props) => + props.step + ? css` + color: #143441; + font-weight: bold; + ` + : css` + color: #bcbcbc; + `} } img { width: 24px; @@ -49,7 +52,7 @@ TitleStyle.elem = styled.div` margin: 0 8px; } @media (max-width: 640px) { - p { + p { font-size: 14px; margin: 0; } @@ -66,7 +69,7 @@ export const FooterStyle = styled.div` width: 100%; align-items: center; background: white; - + .container { width: 100%; max-width: 1080px; @@ -74,21 +77,21 @@ export const FooterStyle = styled.div` flex-direction: row; justify-content: flex-end; } - + .slide-action-group { flex: auto 0 0; } - + button { width: 140px; height: 44px; border-radius: 4px; font-size: 16px; line-height: 18px; - + &.prev { border: none; - color: #9C9C9C; + color: #9c9c9c; margin-right: 24px; } &.next { @@ -97,8 +100,8 @@ export const FooterStyle = styled.div` background: #143441; color: white; &:disabled { - background: #F8F8F8; - color: #8F8F8F; + background: #f8f8f8; + color: #8f8f8f; cursor: not-allowed; } } @@ -106,11 +109,11 @@ export const FooterStyle = styled.div` cursor: progress; } &.submit { - background: #FF5D5D; + background: #ff5d5d; } &.submit:disabled { background: #cccccc; - color: #8F8F8F; + color: #8f8f8f; } } diff --git a/src/components/pages/ZaboUploadPage/index.js b/src/components/pages/ZaboUploadPage/index.js index c2a0ddca..bb7a9e2f 100644 --- a/src/components/pages/ZaboUploadPage/index.js +++ b/src/components/pages/ZaboUploadPage/index.js @@ -1 +1 @@ -export { default } from './ZaboUploadPage'; +export { default } from "./ZaboUploadPage"; diff --git a/src/components/pages/index.js b/src/components/pages/index.js deleted file mode 100644 index 53a37a93..00000000 --- a/src/components/pages/index.js +++ /dev/null @@ -1,22 +0,0 @@ -import loadable from '@loadable/component'; -/* - Migrated from react-loadable to loadable-component. - Check out these to find out more - https://loadable-components.com/docs/loadable-vs-react-lazy/#note-about-react-loadable - https://velog.io/@velopert/nomore-react-loadable -*/ - -export const HomePage = loadable (/* webpackPrefetch: true */ () => import ('./HomePage')); -export const LandingPage = loadable (/* webpackPrefetch: true */ () => import ('./LandingPage')); -export const ZaboPage = loadable (/* webpackPrefetch: true */ () => import ('./ZaboPage')); -export const ZaboDetailPage = loadable (/* webpackPrefetch: true */ () => import ('./ZaboPage/ZaboDetailPage')); -export const ZaboEditPage = loadable (/* webpackPrefetch: true */ () => import ('./ZaboPage/ZaboEditPage')); -export const ZaboUploadPage = loadable (/* webpackPrefetch: true */ () => import ('./ZaboUploadPage')); -export const SettingsPage = loadable (/* webpackPrefetch: true */ () => import ('./SettingsPage')); -export const AuthPage = loadable (/* webpackPrefetch: true */ () => import ('./AuthPage')); -export const LoginPage = loadable (/* webpackPrefetch: true */ () => import ('./LoginPage')); -export const ProfilePage = loadable (/* webpackPrefetch: true */ () => import ('./ProfilePage')); -export const NotFound = loadable (/* webpackPrefetch: true */ () => import ('./NotFound')); -export const AdminPage = loadable (/* webpackPrefetch: true */ () => import ('./AdminPage')); -export const SearchPage = loadable (/* webpackPrefetch: true */ () => import ('./SearchPage')); -export const ApiPage = loadable (/* webpackPrefetch: true */ () => import ('./ApiPage')); diff --git a/src/components/pages/index.ts b/src/components/pages/index.ts new file mode 100644 index 00000000..351637ed --- /dev/null +++ b/src/components/pages/index.ts @@ -0,0 +1,28 @@ +import loadable from "@loadable/component"; +/* + Migrated from react-loadable to loadable-component. + Check out these to find out more + https://loadable-components.com/docs/loadable-vs-react-lazy/#note-about-react-loadable + https://velog.io/@velopert/nomore-react-loadable +*/ + +export const HomePage = loadable(/* webpackPrefetch: true */ () => import("./HomePage")); +export const LandingPage = loadable(/* webpackPrefetch: true */ () => import("./LandingPage")); +export const ZaboPage = loadable(/* webpackPrefetch: true */ () => import("./ZaboPage")); +export const ZaboDetailPage = loadable( + /* webpackPrefetch: true */ () => import("./ZaboPage/ZaboDetailPage"), +); +export const ZaboEditPage = loadable( + /* webpackPrefetch: true */ () => import("./ZaboPage/ZaboEditPage"), +); +export const ZaboUploadPage = loadable( + /* webpackPrefetch: true */ () => import("./ZaboUploadPage"), +); +export const SettingsPage = loadable(/* webpackPrefetch: true */ () => import("./SettingsPage")); +export const AuthPage = loadable(/* webpackPrefetch: true */ () => import("./AuthPage")); +export const LoginPage = loadable(/* webpackPrefetch: true */ () => import("./LoginPage")); +export const ProfilePage = loadable(/* webpackPrefetch: true */ () => import("./ProfilePage")); +export const NotFound = loadable(/* webpackPrefetch: true */ () => import("./NotFound")); +// export const AdminPage = loadable(/* webpackPrefetch: true */ () => import("./AdminPage")); +export const SearchPage = loadable(/* webpackPrefetch: true */ () => import("./SearchPage")); +export const ApiPage = loadable(/* webpackPrefetch: true */ () => import("./ApiPage")); diff --git a/src/components/templates/FloatingNavigator/FloatingNavigator.js b/src/components/templates/FloatingNavigator/FloatingNavigator.js index 2c6b6cf6..1fe6ba94 100644 --- a/src/components/templates/FloatingNavigator/FloatingNavigator.js +++ b/src/components/templates/FloatingNavigator/FloatingNavigator.js @@ -1,31 +1,31 @@ -import React, { PureComponent } from 'react'; +import React, { PureComponent } from "react"; -import add from 'static/images/add.svg'; -import calendar from 'static/images/calendar.svg'; -import search from 'static/images/search-icon-navy.png'; -import user from 'static/images/user.svg'; +import add from "static/images/add.svg"; +import calendar from "static/images/calendar.svg"; +import search from "static/images/search-icon-navy.png"; +import user from "static/images/user.svg"; -import FloatingNavigatorWrapper, { NavItem } from './FloatingNavigator.styled'; +import FloatingNavigatorWrapper, { NavItem } from "./FloatingNavigator.styled"; class FloatingNavigator extends PureComponent { -state = { scrollY: window.scrollY, show: true } + state = { scrollY: window.scrollY, show: true }; -componentDidMount () { - window.addEventListener ('optimizedScroll', this.handleScroll); -} + componentDidMount() { + window.addEventListener("optimizedScroll", this.handleScroll); + } -componentWillUnmount () { - window.removeEventListener ('optimizedScroll', this.handleScroll); -} + componentWillUnmount() { + window.removeEventListener("optimizedScroll", this.handleScroll); + } handleScroll = () => { - this.setState (prevState => ({ + this.setState((prevState) => ({ scrollY: window.scrollY, show: prevState.scrollY > window.scrollY, })); - } + }; - render () { + render() { const { show } = this.state; return ( @@ -35,15 +35,15 @@ componentWillUnmount () { -검색 + 검색 -업로드 + 업로드 -프로필 + 프로필 ); diff --git a/src/components/templates/FloatingNavigator/FloatingNavigator.stories.js b/src/components/templates/FloatingNavigator/FloatingNavigator.stories.js index d789ba8c..5d6983ca 100644 --- a/src/components/templates/FloatingNavigator/FloatingNavigator.stories.js +++ b/src/components/templates/FloatingNavigator/FloatingNavigator.stories.js @@ -1,8 +1,8 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; +import React from "react"; +import { storiesOf } from "@storybook/react"; -import FloatingNavigator from './index'; +import FloatingNavigator from "./index"; -storiesOf ('templates/FloatingNavigator', module).add ('Default', () => , { - notes: '', +storiesOf("templates/FloatingNavigator", module).add("Default", () => , { + notes: "", }); diff --git a/src/components/templates/FloatingNavigator/FloatingNavigator.styled.js b/src/components/templates/FloatingNavigator/FloatingNavigator.styled.js index 49e587ac..432ac362 100644 --- a/src/components/templates/FloatingNavigator/FloatingNavigator.styled.js +++ b/src/components/templates/FloatingNavigator/FloatingNavigator.styled.js @@ -1,7 +1,7 @@ -import { NavLink } from 'react-router-dom'; -import styled, { css } from 'styled-components'; +import { NavLink } from "react-router-dom"; +import styled, { css } from "styled-components"; -export const NavItem = styled (NavLink)` +export const NavItem = styled(NavLink)` flex: 1 0 20%; margin: 0 2.5%; display: flex; @@ -30,24 +30,25 @@ const FloatingNavigatorWrapper = styled.div` left: 0; width: 100%; height: 60px; - max-height: ${props => (props.show ? '60px' : 0)}; + max-height: ${(props) => (props.show ? "60px" : 0)}; overflow: hidden; border-top: 1px solid black; background-color: white; z-index: 1000; display: flex; justify-content: space-between; - + ${NavItem} { - ${props => (props.show - ? css`` - : css` + ${(props) => + props.show + ? css`` + : css` img { width: 0; height: 0; } font-size: 0; - `)}; + `}; @media (min-width: 560px) { display: none; } diff --git a/src/components/templates/FloatingNavigator/index.js b/src/components/templates/FloatingNavigator/index.js index 8e725566..dd92fa10 100644 --- a/src/components/templates/FloatingNavigator/index.js +++ b/src/components/templates/FloatingNavigator/index.js @@ -1 +1 @@ -export { default } from './FloatingNavigator'; +export { default } from "./FloatingNavigator"; diff --git a/src/components/templates/Footer/Footer.js b/src/components/templates/Footer/Footer.js deleted file mode 100644 index 5667169a..00000000 --- a/src/components/templates/Footer/Footer.js +++ /dev/null @@ -1,45 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import PropTypes from 'prop-types'; -import { css } from 'styled-components'; - -import Container from 'atoms/Container'; - -import FooterWrapper from './Footer.styled'; - -const containerStyle = css` - position: absolute; - justify-content: space-between; - align-items: center; - - ${props => (props.horizontalScroll ? css` - @media (min-width: 640px) { - min-width: 1072px; - } - ` : css` - `)} -`; - -const Footer = ({ ownStyle, scrollFooter, children }) => { - const [left, setLeft] = useState (0); - useEffect (() => { - const listener = () => setLeft (-window.pageXOffset); - window.addEventListener ('optimizedScroll', listener); - return () => window.removeEventListener ('optimizedScroll', listener); - }, []); - const style = { left }; - - return ( - - - {children} - - - ); -}; - -Footer.propTypes = { - scrollFooter: PropTypes.bool, - children: PropTypes.element, -}; - -export default Footer; diff --git a/src/components/templates/Footer/Footer.styled.js b/src/components/templates/Footer/Footer.styled.tsx similarity index 55% rename from src/components/templates/Footer/Footer.styled.js rename to src/components/templates/Footer/Footer.styled.tsx index c3eca867..815b490d 100644 --- a/src/components/templates/Footer/Footer.styled.js +++ b/src/components/templates/Footer/Footer.styled.tsx @@ -1,6 +1,8 @@ -import styled from 'styled-components'; +import styled, { type css } from "styled-components"; -const FooterWrapper = styled.footer` +const FooterWrapper = styled.footer<{ + ownStyle?: ReturnType; +}>` position: fixed; bottom: 0; left: 0; @@ -8,15 +10,15 @@ const FooterWrapper = styled.footer` height: 74px; background: white; z-index: 1000; - + display: flex; flex-direction: column; justify-content: center; - box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.4); + box-shadow: 0 0 8px rgba(0, 0, 0, 0.4); @media (max-width: 640px) { height: 60px; } - ${props => props.ownStyle || ''}; + ${(props) => props.ownStyle || ""}; `; export default FooterWrapper; diff --git a/src/components/templates/Footer/Footer.tsx b/src/components/templates/Footer/Footer.tsx new file mode 100644 index 00000000..b8cdf283 --- /dev/null +++ b/src/components/templates/Footer/Footer.tsx @@ -0,0 +1,44 @@ +import React, { type PropsWithChildren, useEffect, useState } from "react"; +import { css } from "styled-components"; + +import Container from "components/atoms/Container"; + +import FooterWrapper from "./Footer.styled"; + +const containerStyle = (props: { horizontalScroll?: boolean }) => css` + position: absolute; + justify-content: space-between; + align-items: center; + + ${props.horizontalScroll && + css` + @media (min-width: 640px) { + min-width: 1072px; + } + `} +`; + +interface Props extends PropsWithChildren { + ownStyle?: ReturnType; + scrollFooter?: boolean; +} + +const Footer: React.FC = ({ ownStyle, scrollFooter, children }) => { + const [left, setLeft] = useState(0); + useEffect(() => { + const listener = () => setLeft(-window.pageXOffset); + window.addEventListener("optimizedScroll", listener); + return () => window.removeEventListener("optimizedScroll", listener); + }, []); + const style = { left }; + + return ( + + + {children} + + + ); +}; + +export default Footer; diff --git a/src/components/templates/Footer/index.js b/src/components/templates/Footer/index.js deleted file mode 100644 index be92134c..00000000 --- a/src/components/templates/Footer/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Footer'; diff --git a/src/components/templates/Footer/index.ts b/src/components/templates/Footer/index.ts new file mode 100644 index 00000000..3738288b --- /dev/null +++ b/src/components/templates/Footer/index.ts @@ -0,0 +1 @@ +export { default } from "./Footer"; diff --git a/src/components/templates/Header/Header.js b/src/components/templates/Header/Header.js deleted file mode 100644 index 6bbb7e8c..00000000 --- a/src/components/templates/Header/Header.js +++ /dev/null @@ -1,132 +0,0 @@ -import React, { useCallback, useEffect, useState } from 'react'; -import PropTypes from 'prop-types'; -import { Link, NavLink, useHistory } from 'react-router-dom'; -import { useDispatch, useSelector } from 'react-redux'; -import { css } from 'styled-components'; -import get from 'lodash.get'; - -import Container from 'atoms/Container'; -import SVG from 'atoms/SVG'; - -import { setCurrentGroup } from 'store/reducers/auth'; -import { isAuthedSelector } from 'lib/utils'; - -import whiteLogo from 'static/logo/logo_white.svg'; -import logo from 'static/logo/logo.svg'; - -import SearchBar from '../SearchBar'; -import { HeaderWrapper } from './Header.styled'; - -const logos = { - primary: logo, - white: whiteLogo, -}; - -const containerStyle = css` - position: absolute; - justify-content: space-between; - align-items: center; - overflow: visible; - >div { - display: flex; - flex-direction: row; - align-items: center; - } - ${props => (props.horizontalScroll ? css` - @media (min-width: 640px) { - min-width: 1072px; - } - ` : css` - `)} -`; - -const Header = ({ - scrollHeader, - transparent, - logoColor, - type, - groupName, -}) => { - const history = useHistory (); - const [left, setLeft] = useState (0); - useEffect (() => { - const listener = () => setLeft (-window.pageXOffset); - window.addEventListener ('optimizedScroll', listener); - return () => window.removeEventListener ('optimizedScroll', listener); - }, []); - const style = { left }; - - return ( - - -
- - logo - -
-
- -
- -
-
- ); -}; - -Header.propTypes = { - type: PropTypes.string, - groupName: PropTypes.string, - transparent: PropTypes.bool, - scrollHeader: PropTypes.bool, - logoColor: PropTypes.oneOf (['white', 'primary']), -}; - -Header.defaultProps = { - type: '', - groupName: '', - transparent: false, - scrollHeader: false, - logoColor: 'primary', -}; - -Header.AuthButton = ({ type, groupName, transparent }) => { - const dispatch = useDispatch (); - const isAuthenticated = useSelector (isAuthedSelector); - const username = useSelector (state => get (state, ['auth', 'info', 'username'])); - - const toUpload = useCallback (() => { - if (groupName) dispatch (setCurrentGroup (groupName)); - }, [groupName, dispatch]); - - return ( - - {isAuthenticated ? ( - !username ? null - : ( -
- - -

{username}

-
- {type === 'upload' && ( - - - - )} -
- ) - ) : ( -
- )} - - ); -}; - -export default Header; diff --git a/src/components/templates/Header/Header.stories.js b/src/components/templates/Header/Header.stories.js index 85a8d203..adc1f135 100644 --- a/src/components/templates/Header/Header.stories.js +++ b/src/components/templates/Header/Header.stories.js @@ -1,15 +1,9 @@ /* eslint-disable */ -import React from 'react'; -import { storiesOf } from '@storybook/react'; +import React from "react"; +import { storiesOf } from "@storybook/react"; -import Header from './index'; +import Header from "./index"; -storiesOf ('templates/Header', module).add ( - 'Default', - () => ( -
- ), - { - notes: '', - }, -); +storiesOf("templates/Header", module).add("Default", () =>
, { + notes: "", +}); diff --git a/src/components/templates/Header/Header.styled.js b/src/components/templates/Header/Header.styled.js deleted file mode 100644 index 7755ac2e..00000000 --- a/src/components/templates/Header/Header.styled.js +++ /dev/null @@ -1,85 +0,0 @@ -import styled, { css } from 'styled-components'; - -export const HeaderWrapper = styled.header` - ${props => (props.transparent ? css` - position: absolute; - border-top: 0; - ` : css` - position: fixed; - border-top: 6px solid rgb(27, 50, 65); - `)} - top: 0; - left: 0; - width: 100%; - height: 55px; - transition: 0.4s; - z-index: 1000; - display: flex; - flex-direction: column; - justify-content: center; - border-bottom: 1px solid #E9E9E9; - - a { - display: flex; - flex-direction: column; - justify-content: center; - font-size: 14px; - img { - margin-right: 24px; - } - } - - ${props => (props.transparent ? css` - background: transparent; - border-bottom: 0; - ` : css` - background: #fff; - `)}; -`; - -HeaderWrapper.Auth = styled.section` - color: ${props => (props.transparent ? 'white' : '#363636')}; - a { - display: inline-block; - &.upload { margin-left: 6px } - } - p { - display: inline-block; - margin: 0; - padding-left: 6px; - font-size: 14px; - } - button { - font-family: "NanumSquare", sans-serif; - height: 32px; - font-size: 14px; - font-weight: bold; - line-height: 12px; - padding: 8px 16px; - border-radius: 4px; - margin-left: 24px; - - ${props => (props.transparent ? css` - background: rgba(255, 255, 255, 0.15); - border: 1px solid #FFFFFF; - color: white; - &:hover { - background-color: white; - color: #143441; - } - ` : css` - background: white; - border: 1px solid #143441; - color: #143441; - &:hover { - background-color: #143441; - color: white; - } - `)} - } - - @media (max-width: 910px) { - p { display: none } - button { margin-left: 12px } - } -`; diff --git a/src/components/templates/Header/Header.styled.tsx b/src/components/templates/Header/Header.styled.tsx new file mode 100644 index 00000000..bfbc460a --- /dev/null +++ b/src/components/templates/Header/Header.styled.tsx @@ -0,0 +1,110 @@ +import styled, { css } from "styled-components"; + +const HeaderWrapperComponent = styled.header<{ transparent?: boolean }>` + ${(props) => + props.transparent + ? css` + position: absolute; + border-top: 0; + ` + : css` + position: fixed; + border-top: 6px solid rgb(27, 50, 65); + `} + top: 0; + left: 0; + width: 100%; + height: 55px; + transition: 0.4s; + z-index: 1000; + display: flex; + flex-direction: column; + justify-content: center; + border-bottom: 1px solid #e9e9e9; + + a { + display: flex; + flex-direction: column; + justify-content: center; + font-size: 14px; + + img { + margin-right: 24px; + } + } + + ${(props) => + props.transparent + ? css` + background: transparent; + border-bottom: 0; + ` + : css` + background: #fff; + `}; +`; + +const AuthComponent = styled.section<{ transparent?: boolean }>` + color: ${(props) => (props.transparent ? "white" : "#363636")}; + + a { + display: inline-block; + + &.upload { + margin-left: 6px; + } + } + + p { + display: inline-block; + margin: 0; + padding-left: 6px; + font-size: 14px; + } + + button { + font-family: "NanumSquare", sans-serif; + height: 32px; + font-size: 14px; + font-weight: bold; + line-height: 12px; + padding: 8px 16px; + border-radius: 4px; + margin-left: 24px; + + ${(props) => + props.transparent + ? css` + background: rgba(255, 255, 255, 0.15); + border: 1px solid #ffffff; + color: white; + + &:hover { + background-color: white; + color: #143441; + } + ` + : css` + background: white; + border: 1px solid #143441; + color: #143441; + + &:hover { + background-color: #143441; + color: white; + } + `} + } + + @media (max-width: 910px) { + p { + display: none; + } + + button { + margin-left: 12px; + } + } +`; + +export const HeaderWrapper = Object.assign(HeaderWrapperComponent, { Auth: AuthComponent }); diff --git a/src/components/templates/Header/Header.tsx b/src/components/templates/Header/Header.tsx new file mode 100644 index 00000000..8cbc68f9 --- /dev/null +++ b/src/components/templates/Header/Header.tsx @@ -0,0 +1,148 @@ +import React, { useCallback, useEffect, useState } from "react"; +import { Link, NavLink } from "react-router-dom"; +import { useDispatch, useSelector } from "react-redux"; +import { css } from "styled-components"; +import get from "lodash.get"; + +import Container from "components/atoms/Container"; +import SVG from "components/atoms/SVG"; + +import { setCurrentGroup } from "store/reducers/auth"; +import { isAuthedSelector } from "lib/utils"; + +import whiteLogo from "static/logo/logo_white.svg"; +import logo from "static/logo/logo.svg"; + +import SearchBar from "../SearchBar"; +import { HeaderWrapper } from "./Header.styled"; + +const logos = { + primary: logo, + white: whiteLogo, +}; + +const containerStyle = (props: { horizontalScroll?: boolean }) => css` + position: absolute; + justify-content: space-between; + align-items: center; + overflow: visible; + + > div { + display: flex; + flex-direction: row; + align-items: center; + } + + ${props.horizontalScroll && + css` + @media (min-width: 640px) { + min-width: 1072px; + } + `} +`; + +interface Props { + type?: "upload" | "search"; + groupName?: string; + transparent?: boolean; + scrollHeader?: boolean; + logoColor?: "white" | "primary"; +} + +const Header: React.FC = ({ + scrollHeader = false, + transparent = false, + logoColor = "primary", + type, + groupName = "", +}) => { + const [left, setLeft] = useState(0); + useEffect(() => { + const listener = () => setLeft(-window.pageXOffset); + window.addEventListener("optimizedScroll", listener); + return () => window.removeEventListener("optimizedScroll", listener); + }, []); + const style = { left }; + + return ( + + +
+ + logo + +
+
+ +
+ +
+
+ ); +}; + +interface AuthButtonProps { + type?: "upload" | "search"; + groupName?: string; + transparent?: boolean; +} + +const AuthButton: React.FC = ({ type, groupName, transparent }) => { + const dispatch = useDispatch(); + const isAuthenticated = useSelector(isAuthedSelector); + const username = useSelector((state) => get(state, ["auth", "info", "username"])); + + const toUpload = useCallback(() => { + // TODO: Fix when redux is fixed + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + if (groupName) dispatch(setCurrentGroup(groupName)); + }, [groupName, dispatch]); + + return ( + + {isAuthenticated ? ( + !username ? null : ( +
+ + +

{username}

+
+ {type === "upload" && ( + + + + )} +
+ ) + ) : ( + + )} +
+ ); +}; + +export default Header; diff --git a/src/components/templates/Header/index.js b/src/components/templates/Header/index.js deleted file mode 100644 index 579f1ac2..00000000 --- a/src/components/templates/Header/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Header'; diff --git a/src/components/templates/Header/index.ts b/src/components/templates/Header/index.ts new file mode 100644 index 00000000..2764567d --- /dev/null +++ b/src/components/templates/Header/index.ts @@ -0,0 +1 @@ +export { default } from "./Header"; diff --git a/src/components/templates/Loading/Loading.js b/src/components/templates/Loading/Loading.js index c3f35c4d..ed36854a 100644 --- a/src/components/templates/Loading/Loading.js +++ b/src/components/templates/Loading/Loading.js @@ -1,10 +1,10 @@ -import React, { PureComponent } from 'react'; -import PropTypes from 'prop-types'; +import React, { PureComponent } from "react"; +import PropTypes from "prop-types"; -import LoadingWrapper from './Loading.styled'; +import LoadingWrapper from "./Loading.styled"; class Loading extends PureComponent { - render () { + render() { return (
    @@ -20,11 +20,11 @@ class Loading extends PureComponent { } Loading.propTypes = { - height: PropTypes.oneOfType ([PropTypes.string, PropTypes.number]), + height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), }; Loading.defaultProps = { - height: '100vh', + height: "100vh", }; export default Loading; diff --git a/src/components/templates/Loading/Loading.stories.js b/src/components/templates/Loading/Loading.stories.js index 75fed75e..793b5a71 100644 --- a/src/components/templates/Loading/Loading.stories.js +++ b/src/components/templates/Loading/Loading.stories.js @@ -1,8 +1,8 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; +import React from "react"; +import { storiesOf } from "@storybook/react"; -import Loading from './index'; +import Loading from "./index"; -storiesOf ('templates/Loading', module).add ('Default', () => , { - notes: '', +storiesOf("templates/Loading", module).add("Default", () => , { + notes: "", }); diff --git a/src/components/templates/Loading/Loading.styled.js b/src/components/templates/Loading/Loading.styled.js index 583ac743..bd6deb1a 100644 --- a/src/components/templates/Loading/Loading.styled.js +++ b/src/components/templates/Loading/Loading.styled.js @@ -1,4 +1,4 @@ -import styled from 'styled-components'; +import styled from "styled-components"; const LoadingWrapper = styled.div` margin: 0; @@ -8,7 +8,7 @@ const LoadingWrapper = styled.div` align-items: center; font-family: "Just Another Hand", cursive; - height: ${props => props.height || '100vh'}; + height: ${(props) => props.height || "100vh"}; ul { margin: 0; diff --git a/src/components/templates/Loading/index.js b/src/components/templates/Loading/index.js index 62141369..61edb381 100644 --- a/src/components/templates/Loading/index.js +++ b/src/components/templates/Loading/index.js @@ -1 +1 @@ -export { default } from './Loading'; +export { default } from "./Loading"; diff --git a/src/components/templates/Modal/Modal.js b/src/components/templates/Modal/Modal.js index 8c4174e5..d41acaad 100644 --- a/src/components/templates/Modal/Modal.js +++ b/src/components/templates/Modal/Modal.js @@ -1,155 +1,153 @@ /* eslint-disable */ -import React, { PureComponent } from 'react'; -import ReactDOM from 'react-dom'; -import { CSSTransition } from 'react-transition-group'; +import React, { PureComponent } from "react"; +import ReactDOM from "react-dom"; +import { CSSTransition } from "react-transition-group"; -import ModalWrapper from './Modal.styled'; +import ModalWrapper from "./Modal.styled"; const { body } = document; class Modal extends PureComponent { - constructor (props) { - super (props); - this.el = document.createElement ('div'); + constructor(props) { + super(props); + this.el = document.createElement("div"); this.state = { isHidden: false, isLoading: false, }; } - componentDidMount () { - body.appendChild (this.el); + componentDidMount() { + body.appendChild(this.el); } - componentWillUnmount () { - body.removeChild (this.el); + componentWillUnmount() { + body.removeChild(this.el); } -hide = () => { - this.setState ({ - isHidden: true, - }); -} - -handleOnExited = () => { - this.props.onCanceled (); - this.hide (); -} - -handleCancel = () => { - this.props.onCancel (); -} - -handleSubmit = () => { - const { onOk, onCancel } = this.props; - const promise = onOk (); - if (promise instanceof Promise) { - this.setState ({ isLoading: true }); - promise.then (() => { - this.setState ({ isLoading: false }); - onCancel (); + hide = () => { + this.setState({ + isHidden: true, }); - } else { - onCancel (); - } -} + }; + + handleOnExited = () => { + this.props.onCanceled(); + this.hide(); + }; + + handleCancel = () => { + this.props.onCancel(); + }; + + handleSubmit = () => { + const { onOk, onCancel } = this.props; + const promise = onOk(); + if (promise instanceof Promise) { + this.setState({ isLoading: true }); + promise.then(() => { + this.setState({ isLoading: false }); + onCancel(); + }); + } else { + onCancel(); + } + }; + + renderMask() { + const { show, mask } = this.props; + if (!mask) return null; -renderMask () { - const { show, mask } = this.props; - if (!mask) return null; - - return ( - -
    - - ); -} - -renderFooter () { - const { - cancelText, okText, footer, cancelButton, okButton, - } = this.props; + > +
    + + ); + } - if (footer === undefined) { - return ( -
    - {cancelButton && ( -
    - {cancelText} -
    - )} - {okButton && ( -
    - {okText} + renderFooter() { + const { cancelText, okText, footer, cancelButton, okButton } = this.props; + + if (footer === undefined) { + return ( +
    + {cancelButton && ( +
    + {cancelText} +
    + )} + {okButton && ( +
    + {okText} +
    + )}
    - )} -
    - ); + ); + } + return footer; } - return footer; -} -renderContent () { - const { show, title, children } = this.props; - - return ( - -
    -
    - {title && (typeof title === 'string' ?
    {title}
    : title)} - {children -&& (typeof children === 'string' ?
    {children}
    : children)} - {this.renderFooter ()} -
    - - ); -} +
    +
    + {title && (typeof title === "string" ?
    {title}
    : title)} + {children && + (typeof children === "string" ?
    {children}
    : children)} + {this.renderFooter()} +
    + + ); + } -render () { - return ReactDOM.createPortal ( - - {this.renderMask ()} - {this.renderContent ()} - , - this.el, - ); -} + render() { + return ReactDOM.createPortal( + + {this.renderMask()} + {this.renderContent()} + , + this.el, + ); + } } Modal.propTyes = {}; diff --git a/src/components/templates/Modal/Modal.stories.js b/src/components/templates/Modal/Modal.stories.js index 32a57f64..53d12c73 100644 --- a/src/components/templates/Modal/Modal.stories.js +++ b/src/components/templates/Modal/Modal.stories.js @@ -1,8 +1,8 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; +import React from "react"; +import { storiesOf } from "@storybook/react"; -import Modal from './index'; +import Modal from "./index"; -storiesOf ('templates/Modal', module).add ('Default', () => , { - notes: '', +storiesOf("templates/Modal", module).add("Default", () => , { + notes: "", }); diff --git a/src/components/templates/Modal/Modal.styled.js b/src/components/templates/Modal/Modal.styled.js index 494c0fb5..b6798052 100644 --- a/src/components/templates/Modal/Modal.styled.js +++ b/src/components/templates/Modal/Modal.styled.js @@ -1,12 +1,11 @@ -import styled from 'styled-components'; +import styled from "styled-components"; const ModalWrapper = styled.div` - -font-size: 12px; + font-size: 12px; .mask { z-index: 9999; - background: rgba(0,0,0,0.2); + background: rgba(0, 0, 0, 0.2); position: fixed; width: 100vw; height: 100vh; @@ -15,12 +14,12 @@ font-size: 12px; right: 0; bottom: 0; } - + .header { - height: 3px; - background-color: #143441; + height: 3px; + background-color: #143441; } - + .modal { z-index: 9999; background: #fff; @@ -34,7 +33,7 @@ font-size: 12px; width: 240px; max-width: calc(100vw - 2rem); max-height: calc(100vh - 2rem); - + > .title { color: #2d3e51; text-align: center; @@ -43,82 +42,86 @@ font-size: 12px; margin-bottom: 30px; } } - + > .content { - margin : 20px; + margin: 20px; overflow: auto; color: #9b9b9b; text-align: center; } - + > .footer { display: flex; justify-content: center; margin: 20px 0; font-size: 14px; color: #143441; - + .button { min-width: 20px; padding: 4.5px 10px; border-radius: 3px; - + &:hover { background-color: #143441; color: white; } } } - } - - .fade-appear, .fade-enter, .fade-exit { - animation-duration: .2s; + + .fade-appear, + .fade-enter, + .fade-exit { + animation-duration: 0.2s; animation-fill-mode: both; animation-play-state: paused; animation-timing-function: linear; } - + .fade-appear.fade-appear-active, .fade-enter.fade-enter-active { animation-name: fadeIn; animation-play-state: running; } - + .fade-exit-active { - animation-name: fadeOut; - animation-play-state: running; - pointer-events: none; + animation-name: fadeOut; + animation-play-state: running; + pointer-events: none; } - - .zoom-appear, .zoom-enter, .zoom-exit { + + .zoom-appear, + .zoom-enter, + .zoom-exit { animation-fill-mode: both; animation-play-state: paused; } - - .zoom-appear, .zoom-enter { - animation-duration: .2s; - animation-timing-function: cubic-bezier(.08,.82,.17,1); + + .zoom-appear, + .zoom-enter { + animation-duration: 0.2s; + animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1); user-select: none; } - + .zoom-exit { - animation-duration: .2s; - animation-timing-function: cubic-bezier(.78,.14,.15,.86); + animation-duration: 0.2s; + animation-timing-function: cubic-bezier(0.78, 0.14, 0.15, 0.86); } - + .zoom-appear.zoom-appear-active, .zoom-enter.zoom-enter-active { animation-name: zoomIn; animation-play-state: running; } - + .zoom-exit.zoom-exit-active { animation-name: zoomOut; animation-play-state: running; pointer-events: none; } - + @keyframes fadeIn { 0% { opacity: 0; @@ -127,7 +130,7 @@ font-size: 12px; opacity: 1; } } - + @keyframes fadeOut { 0% { opacity: 1; @@ -136,28 +139,27 @@ font-size: 12px; opacity: 0; } } - + @keyframes zoomIn { 0% { opacity: 0; - transform: translate(-50%, -50%) scale(.2); + transform: translate(-50%, -50%) scale(0.2); } to { opacity: 1; transform: translate(-50%, -50%) scale(1); } } - + @keyframes zoomOut { 0% { transform: translate(-50%, -50%) scale(1); } to { opacity: 0; - transform: translate(-50%, -50%) scale(.2); + transform: translate(-50%, -50%) scale(0.2); } } - `; export default ModalWrapper; diff --git a/src/components/templates/Modal/index.js b/src/components/templates/Modal/index.js index 02bf9f54..958eb477 100644 --- a/src/components/templates/Modal/index.js +++ b/src/components/templates/Modal/index.js @@ -1,4 +1,4 @@ -import Modal from './Modal'; +import Modal from "./Modal"; -export * from './modalMethods'; +export * from "./modalMethods"; export default Modal; diff --git a/src/components/templates/Modal/modalMethods.js b/src/components/templates/Modal/modalMethods.js index dda2c1b9..53f32de4 100644 --- a/src/components/templates/Modal/modalMethods.js +++ b/src/components/templates/Modal/modalMethods.js @@ -1,16 +1,16 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; +import React from "react"; +import ReactDOM from "react-dom"; -import Modal from './Modal'; +import Modal from "./Modal"; const { body } = document; export const showInstanceModal = ({ content, onCancel, ...props }) => { - const container = document.createElement ('div'); - body.appendChild (container); + const container = document.createElement("div"); + body.appendChild(container); - const render = show => { - ReactDOM.render ( + const render = (show) => { + ReactDOM.render( // eslint-disable-next-line no-use-before-define {content} @@ -19,21 +19,21 @@ export const showInstanceModal = ({ content, onCancel, ...props }) => { ); }; - const show = () => render (true); + const show = () => render(true); - const hide = () => render (false); + const hide = () => render(false); const unmount = () => { - ReactDOM.unmountComponentAtNode (container); - body.removeChild (container); + ReactDOM.unmountComponentAtNode(container); + body.removeChild(container); }; const _onCancel = () => { - if (typeof onCancel === 'function') onCancel (); - hide (); + if (typeof onCancel === "function") onCancel(); + hide(); }; - show (); + show(); return hide; }; diff --git a/src/components/templates/PWAPrompt/PWAPrompt.js b/src/components/templates/PWAPrompt/PWAPrompt.js index 85948cde..ad98dffc 100644 --- a/src/components/templates/PWAPrompt/PWAPrompt.js +++ b/src/components/templates/PWAPrompt/PWAPrompt.js @@ -1,68 +1,57 @@ -import React, { PureComponent } from 'react'; +import React, { PureComponent } from "react"; -import appIcon from 'static/logo/sparcs.svg'; - -import PWAPromptWrapper from './PWAPrompt.styled'; +import appIcon from "static/logo/sparcs.svg"; +import PWAPromptWrapper from "./PWAPrompt.styled"; class PWAPrompt extends PureComponent { state = { active: false }; - handleScroll = e => { - if (window.scrollY < 10) { - document.body.classList.add ('pwa-prompt-active'); - this.setState ({ active: true }); - } else { - document.body.classList.remove ('pwa-prompt-active'); - setTimeout (() => this.setState ({ active: false })); - } - }; - - handleScroll = e => { + handleScroll = () => { if (window.scrollY < 10) { - document.body.classList.add ('pwa-prompt-active'); - this.setState ({ active: true }); + document.body.classList.add("pwa-prompt-active"); + this.setState({ active: true }); } else { - document.body.classList.remove ('pwa-prompt-active'); - setTimeout (() => this.setState ({ active: false })); + document.body.classList.remove("pwa-prompt-active"); + setTimeout(() => this.setState({ active: false })); } }; addListener = () => { - this.setState ({ active: true }); - window.addEventListener ('optimizedScroll', this.handleScroll); - } + this.setState({ active: true }); + window.addEventListener("optimizedScroll", this.handleScroll); + }; deleteListener = () => { - this.setState ({ active: false }); - window.removeEventListener ('optimizedScroll', this.handleScroll); - } + this.setState({ active: false }); + window.removeEventListener("optimizedScroll", this.handleScroll); + }; - componentDidMount () { + componentDidMount() { if (window.pwaPromptActive) { - this.addListener (); + this.addListener(); } else { window.onPWAPromptActive = this.addListener; } } handleOpenClick = () => { - this.deleteListener (); - document.body.classList.remove ('pwa-prompt-active'); + this.deleteListener(); + document.body.classList.remove("pwa-prompt-active"); - window.deferredPrompt.prompt (); + window.deferredPrompt.prompt(); // Wait for the user to respond to the prompt - window.deferredPrompt.userChoice.then (choiceResult => { - if (choiceResult.outcome === 'accepted') { - console.log ('User accepted the A2HS prompt'); // TODO: Statistics + window.deferredPrompt.userChoice.then((choiceResult) => { + if (choiceResult.outcome === "accepted") { + console.log("User accepted the A2HS prompt"); // TODO: Statistics } else { - console.log ('User dismissed the A2HS prompt'); + console.log("User dismissed the A2HS prompt"); } window.deferredPrompt = null; }); - } + }; - render () { + render() { const { active } = this.state; if (!active) return null; return ( diff --git a/src/components/templates/PWAPrompt/PWAPrompt.stories.js b/src/components/templates/PWAPrompt/PWAPrompt.stories.js index 15f570a1..0a1ecca9 100644 --- a/src/components/templates/PWAPrompt/PWAPrompt.stories.js +++ b/src/components/templates/PWAPrompt/PWAPrompt.stories.js @@ -1,8 +1,8 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; +import React from "react"; +import { storiesOf } from "@storybook/react"; -import PWAPrompt from './index'; +import PWAPrompt from "./index"; -storiesOf ('templates/PWAPrompt', module).add ('Default', () => , { - notes: '', +storiesOf("templates/PWAPrompt", module).add("Default", () => , { + notes: "", }); diff --git a/src/components/templates/PWAPrompt/PWAPrompt.styled.js b/src/components/templates/PWAPrompt/PWAPrompt.styled.js index 9258ec7c..3a9e973b 100644 --- a/src/components/templates/PWAPrompt/PWAPrompt.styled.js +++ b/src/components/templates/PWAPrompt/PWAPrompt.styled.js @@ -1,4 +1,4 @@ -import styled from 'styled-components'; +import styled from "styled-components"; const PWAPromptWrapper = styled.div` position: fixed; diff --git a/src/components/templates/PWAPrompt/index.js b/src/components/templates/PWAPrompt/index.js index 5b34a822..63be5444 100644 --- a/src/components/templates/PWAPrompt/index.js +++ b/src/components/templates/PWAPrompt/index.js @@ -1 +1 @@ -export { default } from './PWAPrompt'; +export { default } from "./PWAPrompt"; diff --git a/src/components/templates/SavedPosters/SavedPosters.container.js b/src/components/templates/SavedPosters/SavedPosters.container.js index 73215f3f..3a0acb69 100644 --- a/src/components/templates/SavedPosters/SavedPosters.container.js +++ b/src/components/templates/SavedPosters/SavedPosters.container.js @@ -1,16 +1,16 @@ -import React, { PureComponent } from 'react'; -import { connect } from 'react-redux'; +import React, { PureComponent } from "react"; +import { connect } from "react-redux"; -import SavedPosters from './SavedPosters'; +import SavedPosters from "./SavedPosters"; class SavedPostersContainer extends PureComponent { - render () { + render() { return ; } } -const mapStateToProps = state => ({}); +const mapStateToProps = (state) => ({}); -const mapDispatchToProps = dispatch => ({}); +const mapDispatchToProps = (dispatch) => ({}); -export default connect (mapStateToProps, mapDispatchToProps) (SavedPostersContainer); +export default connect(mapStateToProps, mapDispatchToProps)(SavedPostersContainer); diff --git a/src/components/templates/SavedPosters/SavedPosters.js b/src/components/templates/SavedPosters/SavedPosters.js index 4219d06b..4b7dae0a 100644 --- a/src/components/templates/SavedPosters/SavedPosters.js +++ b/src/components/templates/SavedPosters/SavedPosters.js @@ -1,10 +1,10 @@ -import React, { PureComponent } from 'react'; -import PropTypes from 'prop-types'; +import React, { PureComponent } from "react"; +import PropTypes from "prop-types"; -import SavedPostersWrapper from './SavedPosters.styled'; +import SavedPostersWrapper from "./SavedPosters.styled"; class SavedPosters extends PureComponent { - render () { + render() { return ( {this.props.children} diff --git a/src/components/templates/SavedPosters/SavedPosters.stories.js b/src/components/templates/SavedPosters/SavedPosters.stories.js index 95d4d5e0..8d5dc053 100644 --- a/src/components/templates/SavedPosters/SavedPosters.stories.js +++ b/src/components/templates/SavedPosters/SavedPosters.stories.js @@ -1,8 +1,8 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; +import React from "react"; +import { storiesOf } from "@storybook/react"; -import SavedPosters from './SavedPosters'; +import SavedPosters from "./SavedPosters"; -storiesOf ('templates/SavedPosters', module).add ('Default', () => , { - notes: '', +storiesOf("templates/SavedPosters", module).add("Default", () => , { + notes: "", }); diff --git a/src/components/templates/SavedPosters/SavedPosters.styled.js b/src/components/templates/SavedPosters/SavedPosters.styled.js index 5bfea848..de7b2dbe 100644 --- a/src/components/templates/SavedPosters/SavedPosters.styled.js +++ b/src/components/templates/SavedPosters/SavedPosters.styled.js @@ -1,4 +1,4 @@ -import styled from 'styled-components'; +import styled from "styled-components"; const SavedPostersWrapper = styled.div``; diff --git a/src/components/templates/SavedPosters/index.js b/src/components/templates/SavedPosters/index.js index ad271199..18588355 100644 --- a/src/components/templates/SavedPosters/index.js +++ b/src/components/templates/SavedPosters/index.js @@ -1 +1 @@ -export { default } from './SavedPosters.container'; +export { default } from "./SavedPosters.container"; diff --git a/src/components/templates/SearchBar/SearchBar.js b/src/components/templates/SearchBar/SearchBar.js deleted file mode 100644 index 6a85502c..00000000 --- a/src/components/templates/SearchBar/SearchBar.js +++ /dev/null @@ -1,202 +0,0 @@ -import React, { - useCallback, useEffect, useRef, useState, -} from 'react'; -import PropTypes from 'prop-types'; -import { Link, useHistory, useLocation } from 'react-router-dom'; -import AwesomeDebouncePromise from 'awesome-debounce-promise'; -import queryString from 'query-string'; - -import TagList from 'atoms/TagList'; - -import { searchSimpleAPI } from 'lib/api/search'; -import { parseQuery } from 'lib/utils'; - -import cancelIcon from 'static/images/cancel.png'; -import groupDefaultProfile from 'static/images/groupDefaultProfile.png'; - -import { SearchBarContainer, SearchBarWrapper } from './SearchBar.styled'; - -/* ==== search bar debounce ==== */ -const searchAPIDebounced = AwesomeDebouncePromise (searchSimpleAPI, 500); - -const searchResults = {}; - -const SearchBar = ({ - options, type, transparent, iconColor, -}) => { - const isMounted = useRef (true); - const inputRef = useRef (null); - useEffect (() => () => { isMounted.current = false; }, []); - const history = useHistory (); - const { search } = useLocation (); - const { safeQuery, safeCategory } = parseQuery (search); - const [query, setQuery] = useState (safeQuery); - const [category, setCategory] = useState (safeCategory); - const [result, setResult] = useState ({ - zabos: [], - groups: [], - }); - const [isFocused, setFocused] = useState (false); - const [error, setError] = useState (null); - - const { zabos, groups } = result; - - const _handleChange = useCallback (e => { - const { value: newQuery } = e.target; - setQuery (newQuery); - const key = `${newQuery}#`.concat (category); - if (searchResults[key]) { - setResult (searchResults[key]); - } - if (newQuery.trim ().length > 0) { - searchAPIDebounced ({ query: newQuery, category: [] }) - .then (data => { - if (!isMounted.current) return; - searchResults[key] = data; - setResult (data); - }) - .catch (error => { - setResult ({ zabos: [], groups: [] }); - setError (error); - }); - } - }, [setQuery, setResult, setError, category]); - - const _handleKeyPress = useCallback (e => { - // onKeyDown, onKeyUp : korean word call event twice... - // searchBar input can only accept 'query text' - // category search can be done only by clicking tag button - if (e.key === 'Enter') { - setFocused (false); - inputRef.current.blur (); - isMounted.current = false; - if (query.trim ().length > 0) { - const stringified = queryString.stringify ({ query, category: [] }); - history.push (`/search?${stringified}`); - } - } - }, [query, setFocused]); - - const _handleFocusChange = useCallback (e => { - e.stopPropagation (); - e.nativeEvent.stopImmediatePropagation (); - setFocused (prev => !prev); - }, [isFocused, setFocused]); - - const _handleInputFocusChange = useCallback (e => { - e.stopPropagation (); - e.nativeEvent.stopImmediatePropagation (); - setFocused (true); - }, [isFocused, setFocused]); - - const _handleBlur = useCallback (e => { - e.stopPropagation (); - e.nativeEvent.stopImmediatePropagation (); - setFocused (false); - }, [setFocused]); - - const onTagClick = useCallback (newCat => { - setFocused (false); - history.push (`/search?${queryString.stringify ({ category: newCat })}`); - }, [setFocused]); - - const onCancelClick = useCallback (e => { - setQuery (''); - }, [setQuery]); - - const isResultsEmpty = !zabos.length && !groups.length; - - const searchWithTagComponent = ( -
    -

    태그로 검색하기

    - -
    - ); - - const searchResultComponent = ( -
    - {!!zabos.length && ( -
    -

    자보

    -
      - {zabos.map (zabo => ( -
    • - {zabo.title} -
    • - ))} -
    -
    - )} - {!!groups.length && ( -
    -

    그룹

    -
      - {groups.map (group => ( -
    • - { - group.profilePhoto - ? group profile photo - : default group profile photo - } - {group.name} -
    • - ))} -
    -
    - )} -
    - ); - - return ( - - {isFocused ?
    : ''} - - - - - -
    - { query && isFocused ? cancel icon : '' } -
    - {isFocused ?
    : ''} - - { - !query - ? searchWithTagComponent - : searchResultComponent - } - -
    -
    - ); -}; - -SearchBar.propTypes = { - isOpen: PropTypes.bool.isRequired, - type: PropTypes.string, - transparent: PropTypes.bool, - iconColor: PropTypes.oneOf (['white', 'primary']), -}; - -SearchBar.defaultProps = { - type: '', - transparent: false, - iconColor: 'primary', -}; - -export default SearchBar; diff --git a/src/components/templates/SearchBar/SearchBar.stories.js b/src/components/templates/SearchBar/SearchBar.stories.js index 3af1acae..b9df8864 100644 --- a/src/components/templates/SearchBar/SearchBar.stories.js +++ b/src/components/templates/SearchBar/SearchBar.stories.js @@ -1,8 +1,8 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; +import React from "react"; +import { storiesOf } from "@storybook/react"; -import SearchBar from './index'; +import SearchBar from "./index"; -storiesOf ('templates/SearchBar', module).add ('Default', () => , { - notes: '', +storiesOf("templates/SearchBar", module).add("Default", () => , { + notes: "", }); diff --git a/src/components/templates/SearchBar/SearchBar.styled.js b/src/components/templates/SearchBar/SearchBar.styled.js deleted file mode 100644 index 2d04001a..00000000 --- a/src/components/templates/SearchBar/SearchBar.styled.js +++ /dev/null @@ -1,204 +0,0 @@ -import styled, { css } from 'styled-components'; - -import leftArrowNavy from 'static/images/leftArrow-navy.png'; -import searchIcon from 'static/images/search-icon-navy.png'; -import searchIconWhite from 'static/images/search-icon-white.png'; - -export const SearchBarContainer = styled.div` - max-width: 1032px; - width: 100%; - #dimmer { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - } -`; - -export const SearchBarWrapper = styled.div` - display: flex; - flex-direction: column; - z-index: 1; - width: 582px; - max-height: 439px; - overflow-y: scroll; - - /* hide scroll bar */ - /* -webkit- (Chrome, Safari, newer versions of Opera) */ - &::-webkit-scrollbar { width: 0 !important } - /* Firefox */ - scrollbar-width: none; - /* -ms- (Internet Explorer +10) */ - -ms-overflow-style: none; - - background-color: ${props => (props.transparent && !props.isFocused - ? 'transparent' : 'white')}; - /* background-color: white; */ - border-radius: 4px; - - .divider { - margin: 0 6px; - position: relative; - border: .5px solid #E9E9E9; - } - @media (max-width: 910px) { - width: 100%; - ${props => (props.type === 'search' && css` - width: 180px; - float: right; - margin-right: 12px; - `)} - } - ${props => (props.isFocused ? css` - box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.3); - - @media (max-width: 910px) { - position: fixed; - left: 0; - top: 0; - width: 100%; - height: 100%; - max-height: 100%; - border-radius: 0; - } - ` : css` - `)} -`; - -SearchBarWrapper.Header = styled.div` - height: 38px; - position: relative; - top: 0; - - img { - position: absolute; - display: block; - align-self: center; - &.cancel-icon { - top: 7px; - right: 12px; - height: 24px; - } - } - div.search-icon { - position: absolute; - display: block; - align-self: center; - top: 12px; - left: 16px; - height: 16px; - width: 16px; - background: url(${props => (!props.isFocused && props.transparent ? searchIconWhite : searchIcon)}) no-repeat; - background-size: contain; - } - @media (max-width: 910px) { - ${props => (props.isFocused ? css` - border-top: 6px solid rgb(27, 50, 65); - height: 55px; - ` : '')} - img.cancel-icon { top: 13px } - div.search-icon { - ${props => (!props.isFocused && props.type === 'search' ? css` - background: url(${props => (!props.isFocused && props.transparent ? searchIconWhite : searchIcon)}) no-repeat; - background-size: contain; - ` : props.isFocused || props.type === 'search' ? css` - background: url(${leftArrowNavy}) no-repeat; - background-size: contain; - top: 15px; - left: 16px; - right: auto; - width: 20px; - height: 20px; - ` : css` - top: 10px; - right: 12px; - left: auto; - `)} - } - } -`; - -SearchBarWrapper.Header.SearchBar = styled.div` - input { - display: inline-block; - width: 100%; - padding: 10px 48px; - font-size: 16px; - line-height: 18px; - color: #202020; - border: 0; - &:focus { - outline: none; - } - &::placeholder { - color: #BCBCBC; - } - ${props => (props.transparent && !props.isFocused ? css` - background: rgba(255, 255, 255, 0.15); - @media (max-width: 910px) { display: none } - ` : props.isFocused ? css` - border-radius: 0; - background-color: white; - @media (max-width: 910px) { height: 50px } - ` : css` - border-radius: 4px; - background-color: #F4F4F4; - @media (max-width: 910px) { display: none } - `)} - ${props => (props.type === 'search' && css` - @media (max-width: 910px) { display: inline-block } - `)} - } -`; - -SearchBarWrapper.Body = styled.div` - position: relative; - ${props => (props.isFocused ? css`` : css` - display: none; - `)} - ${props => ( - !props.search ? css` - padding: 36px 16px; - ` : props.isResultsEmpty ? css` - padding: 0 16px; - ` : css` - padding: 24px 16px; - ` - )} - - h3 { - margin: 0 0 8px 0; - font-size: 16px; - color: #8F8F8F; - } - ul { - list-style-type: none; - margin: 0; - padding: 0 0 24px 0; - li { - display: flex; - flex-direction: row; - align-items: center; - height: 40px; - margin: 0 -16px; - padding: 0 16px; - &:hover, &:focus { - background-color: #F4F4F4; - } - img { - width: 32px; - height: 32px; - margin-right: 10px; - border-radius: 50%; - } - a { - display: inline-block; - line-height: 40px; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - } - } -`; diff --git a/src/components/templates/SearchBar/SearchBar.styled.tsx b/src/components/templates/SearchBar/SearchBar.styled.tsx new file mode 100644 index 00000000..c2cc84b2 --- /dev/null +++ b/src/components/templates/SearchBar/SearchBar.styled.tsx @@ -0,0 +1,283 @@ +import styled, { css } from "styled-components"; + +import leftArrowNavy from "static/images/leftArrow-navy.png"; +import searchIcon from "static/images/search-icon-navy.png"; +import searchIconWhite from "static/images/search-icon-white.png"; + +export const SearchBarContainer = styled.div` + max-width: 1032px; + width: 100%; + + #dimmer { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + } +`; + +const WrapperComponent = styled.div<{ + type?: "search" | "upload"; + transparent?: boolean; + isFocused?: boolean; +}>` + display: flex; + flex-direction: column; + z-index: 1; + width: 582px; + max-height: 439px; + overflow-y: scroll; + + /* hide scroll bar */ + /* -webkit- (Chrome, Safari, newer versions of Opera) */ + + &::-webkit-scrollbar { + width: 0 !important; + } + + /* Firefox */ + scrollbar-width: none; + /* -ms- (Internet Explorer +10) */ + -ms-overflow-style: none; + + background-color: ${(props) => (props.transparent && !props.isFocused ? "transparent" : "white")}; + /* background-color: white; */ + border-radius: 4px; + + .divider { + margin: 0 6px; + position: relative; + border: 0.5px solid #e9e9e9; + } + + @media (max-width: 910px) { + width: 100%; + ${(props) => + props.type === "search" && + css` + width: 180px; + float: right; + margin-right: 12px; + `} + } + ${(props) => + props.isFocused + ? css` + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); + + @media (max-width: 910px) { + position: fixed; + left: 0; + top: 0; + width: 100%; + height: 100%; + max-height: 100%; + border-radius: 0; + } + ` + : css``} +`; + +const HeaderComponent = styled.div<{ + type?: "search" | "upload"; + transparent?: boolean; + isFocused?: boolean; +}>` + height: 38px; + position: relative; + top: 0; + + img { + position: absolute; + display: block; + align-self: center; + + &.cancel-icon { + top: 7px; + right: 12px; + height: 24px; + } + } + + div.search-icon { + position: absolute; + display: block; + align-self: center; + top: 12px; + left: 16px; + height: 16px; + width: 16px; + background: url(${(props) => + !props.isFocused && props.transparent ? searchIconWhite : searchIcon}) + no-repeat; + background-size: contain; + } + + @media (max-width: 910px) { + ${(props) => + props.isFocused + ? css` + border-top: 6px solid rgb(27, 50, 65); + height: 55px; + ` + : ""} + img.cancel-icon { + top: 13px; + } + + div.search-icon { + ${(props) => + !props.isFocused && props.type === "search" + ? css` + background: url(${!props.isFocused && props.transparent + ? searchIconWhite + : searchIcon}) + no-repeat; + background-size: contain; + ` + : props.isFocused || props.type === "search" + ? css` + background: url(${leftArrowNavy}) no-repeat; + background-size: contain; + top: 15px; + left: 16px; + right: auto; + width: 20px; + height: 20px; + ` + : css` + top: 10px; + right: 12px; + left: auto; + `} + } + } +`; + +const HeaderSearchBar = styled.div<{ + type?: "search" | "upload"; + transparent?: boolean; + isFocused?: boolean; +}>` + input { + display: inline-block; + width: 100%; + padding: 10px 48px; + font-size: 16px; + line-height: 18px; + color: #202020; + border: 0; + + &:focus { + outline: none; + } + + &::placeholder { + color: #bcbcbc; + } + + ${(props) => + props.transparent && !props.isFocused + ? css` + background: rgba(255, 255, 255, 0.15); + @media (max-width: 910px) { + display: none; + } + ` + : props.isFocused + ? css` + border-radius: 0; + background-color: white; + @media (max-width: 910px) { + height: 50px; + } + ` + : css` + border-radius: 4px; + background-color: #f4f4f4; + @media (max-width: 910px) { + display: none; + } + `} + ${(props) => + props.type === "search" && + css` + @media (max-width: 910px) { + display: inline-block; + } + `} + } +`; + +const BodyComponent = styled.div<{ + isFocused?: boolean; + search?: boolean; + isResultsEmpty?: boolean; +}>` + position: relative; + + ${(props) => + props.isFocused + ? css`` + : css` + display: none; + `} + ${(props) => + !props.search + ? css` + padding: 36px 16px; + ` + : props.isResultsEmpty + ? css` + padding: 0 16px; + ` + : css` + padding: 24px 16px; + `} + h3 { + margin: 0 0 8px 0; + font-size: 16px; + color: #8f8f8f; + } + + ul { + list-style-type: none; + margin: 0; + padding: 0 0 24px 0; + + li { + display: flex; + flex-direction: row; + align-items: center; + height: 40px; + margin: 0 -16px; + padding: 0 16px; + + &:hover, + &:focus { + background-color: #f4f4f4; + } + + img { + width: 32px; + height: 32px; + margin-right: 10px; + border-radius: 50%; + } + + a { + display: inline-block; + line-height: 40px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + } + } +`; + +export const SearchBarWrapper = Object.assign(WrapperComponent, { + Header: Object.assign(HeaderComponent, { SearchBar: HeaderSearchBar }), + Body: BodyComponent, +}); diff --git a/src/components/templates/SearchBar/SearchBar.tsx b/src/components/templates/SearchBar/SearchBar.tsx new file mode 100644 index 00000000..dbe86329 --- /dev/null +++ b/src/components/templates/SearchBar/SearchBar.tsx @@ -0,0 +1,256 @@ +import React, { + type InputHTMLAttributes, + type ChangeEvent, + type KeyboardEvent, + type MouseEvent, + useCallback, + useEffect, + useRef, + useState, +} from "react"; + +import type { Group, Zabo } from "lib/interface"; + +import { Link, useHistory, useLocation } from "react-router-dom"; +import AwesomeDebouncePromise from "awesome-debounce-promise"; +import queryString from "query-string"; + +import TagList from "components/atoms/TagList"; + +import { searchSimpleAPI } from "lib/api/search"; +import { parseQuery } from "lib/utils"; + +import cancelIcon from "static/images/cancel.png"; +import groupDefaultProfile from "static/images/groupDefaultProfile.png"; + +import { SearchBarContainer, SearchBarWrapper } from "./SearchBar.styled"; + +/* ==== search bar debounce ==== */ +const searchAPIDebounced = AwesomeDebouncePromise(searchSimpleAPI, 500); + +const searchResults: Record = {}; + +interface Props { + isOpen: boolean; + options?: InputHTMLAttributes; + type?: "upload" | "search"; + transparent?: boolean; + iconColor?: "white" | "primary"; +} + +const SearchBar: React.FC = ({ options, type, transparent, iconColor = "primary" }) => { + const isMounted = useRef(true); + const inputRef = useRef(null); + useEffect( + () => () => { + isMounted.current = false; + }, + [], + ); + const history = useHistory(); + const { search } = useLocation(); + const { safeQuery, safeCategory } = parseQuery(search); + const [query, setQuery] = useState(safeQuery); + const [category, setCategory] = useState(safeCategory); + const [result, setResult] = useState<{ + groups: Group[]; + zabos: Zabo[]; + }>({ + zabos: [], + groups: [], + }); + const [isFocused, setFocused] = useState(false); + const [error, setError] = useState(null); + + const { zabos, groups } = result; + + const _handleChange = useCallback( + (e: ChangeEvent) => { + const { value: newQuery } = e.target; + setQuery(newQuery); + const key = `${newQuery}#`.concat(category.join("#")); + if (key in searchResults) { + setResult(searchResults[key]); + } + if (newQuery.trim().length > 0) { + searchAPIDebounced({ + query: newQuery, + category: [], + }) + .then((data) => { + if (!isMounted.current) return; + searchResults[key] = data; + setResult(data); + }) + .catch((error) => { + setResult({ + zabos: [], + groups: [], + }); + setError(error); + }); + } + }, + [setQuery, setResult, setError, category], + ); + + const _handleKeyPress = useCallback( + (e: KeyboardEvent) => { + // onKeyDown, onKeyUp : korean word call event twice... + // searchBar input can only accept 'query text' + // category search can be done only by clicking tag button + if (e.key === "Enter") { + setFocused(false); + inputRef?.current?.blur(); + isMounted.current = false; + if (query.trim().length > 0) { + const stringified = queryString.stringify({ + query, + category: [], + }); + history.push(`/search?${stringified}`); + } + } + }, + [query, setFocused], + ); + + const _handleFocusChange = useCallback( + (e: MouseEvent) => { + e.stopPropagation(); + e.nativeEvent.stopImmediatePropagation(); + setFocused((prev) => !prev); + }, + [isFocused, setFocused], + ); + + const _handleInputFocusChange = useCallback( + (e: MouseEvent) => { + e.stopPropagation(); + e.nativeEvent.stopImmediatePropagation(); + setFocused(true); + }, + [isFocused, setFocused], + ); + + const _handleBlur = useCallback( + (e: MouseEvent) => { + e.stopPropagation(); + e.nativeEvent.stopImmediatePropagation(); + setFocused(false); + }, + [setFocused], + ); + + const onTagClick = useCallback( + (newCat: string) => { + setFocused(false); + history.push(`/search?${queryString.stringify({ category: newCat })}`); + }, + [setFocused], + ); + + const onCancelClick = useCallback(() => { + setQuery(""); + }, [setQuery]); + + const isResultsEmpty = !zabos.length && !groups.length; + + const searchWithTagComponent = ( +
    +

    태그로 검색하기

    + +
    + ); + + const searchResultComponent = ( +
    + {!!zabos.length && ( +
    +

    자보

    +
      + {zabos.map((zabo) => ( +
    • + {zabo.title} +
    • + ))} +
    +
    + )} + {!!groups.length && ( +
    +

    그룹

    +
      + {groups.map((group) => ( +
    • + {group.profilePhoto ? ( + group profile photo + ) : ( + default group profile photo + )} + {group.name} +
    • + ))} +
    +
    + )} +
    + ); + + return ( + + {isFocused ? ( +
    + {" "} +
    + ) : ( + "" + )} + + + + + +
    + {" "} +
    + {query && isFocused ? ( + cancel icon + ) : ( + "" + )} +
    + {isFocused ?
    : ""} + + {!query ? searchWithTagComponent : searchResultComponent} + +
    +
    + ); +}; + +export default SearchBar; diff --git a/src/components/templates/SearchBar/index.js b/src/components/templates/SearchBar/index.js index e1b1580f..f3cedd3e 100644 --- a/src/components/templates/SearchBar/index.js +++ b/src/components/templates/SearchBar/index.js @@ -1 +1 @@ -export { default } from './SearchBar'; +export { default } from "./SearchBar"; diff --git a/src/components/templates/ZaboList/ZaboList.container.js b/src/components/templates/ZaboList/ZaboList.container.js index 91236410..44d8d3ce 100644 --- a/src/components/templates/ZaboList/ZaboList.container.js +++ b/src/components/templates/ZaboList/ZaboList.container.js @@ -1,28 +1,25 @@ -import { connect } from 'react-redux'; -import { List } from 'immutable'; -import get from 'lodash.get'; +import { connect } from "react-redux"; +import { List } from "immutable"; +import get from "lodash.get"; -import { - getGroupZaboList, getPins, getSearchZaboList, - getZaboList, -} from 'store/reducers/zabo'; +import { getGroupZaboList, getPins, getSearchZaboList, getZaboList } from "store/reducers/zabo"; -import ZaboList from './ZaboList'; +import ZaboList from "./ZaboList"; const reduxKey = { - main: () => ['zabo', 'lists', 'main'], - related: id => ['zabo', 'lists', id], - pins: () => ['zabo', 'lists', 'pins'], - group: name => ['zabo', 'lists', name], - search: () => ['zabo', 'lists', 'search'], + main: () => ["zabo", "lists", "main"], + related: (id) => ["zabo", "lists", id], + pins: () => ["zabo", "lists", "pins"], + group: (name) => ["zabo", "lists", name], + search: () => ["zabo", "lists", "search"], }; -const emptyList = List ([]); +const emptyList = List([]); const mapStateToProps = (state, ownProps) => { const { type, query } = ownProps; - const zaboIdList = get (state, reduxKey[type] (query)) || emptyList; + const zaboIdList = get(state, reduxKey[type](query)) || emptyList; return { zaboIdList, - width: get (state, ['app', 'windowSize', 'width']), + width: get(state, ["app", "windowSize", "width"]), }; }; @@ -33,4 +30,4 @@ const mapDispatchToProps = { getSearchZaboList, }; -export default connect (mapStateToProps, mapDispatchToProps) (ZaboList); +export default connect(mapStateToProps, mapDispatchToProps)(ZaboList); diff --git a/src/components/templates/ZaboList/ZaboList.js b/src/components/templates/ZaboList/ZaboList.js index dd54cbef..429a5adf 100644 --- a/src/components/templates/ZaboList/ZaboList.js +++ b/src/components/templates/ZaboList/ZaboList.js @@ -1,13 +1,13 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import MasonryZaboList from 'react-masonry-infinite'; -import SquareLoader from 'react-spinners/SquareLoader'; -import styled from 'styled-components'; +import React from "react"; +import PropTypes from "prop-types"; +import MasonryZaboList from "react-masonry-infinite"; +import SquareLoader from "react-spinners/SquareLoader"; +import styled from "styled-components"; -import ZaboCard from 'organisms/ZaboCard'; +import ZaboCard from "components/organisms/ZaboCard"; -import withStackMaster from './withStackMaster'; -import ZaboListWrapper from './ZaboList.styled'; +import withStackMaster from "./withStackMaster"; +import ZaboListWrapper from "./ZaboList.styled"; const sizes = [ { columns: 2, gutter: 16 }, @@ -30,45 +30,43 @@ const loader = ( ); class ZaboList extends React.Component { - masonry = React.createRef () + masonry = React.createRef(); - state = { hasNext: true } + state = { hasNext: true }; - componentDidMount () { - this.fetch (); + componentDidMount() { + this.fetch(); } - componentDidUpdate (prevProps) { + componentDidUpdate(prevProps) { const { query } = this.props; if (query !== prevProps.query) { - this.fetch (); + this.fetch(); } } - fetch = next => { - const { - type, getZaboList, getPins, query, zaboIdList, getGroupZaboList, getSearchZaboList, - } = this.props; + fetch = (next) => { + const { type, getZaboList, getPins, query, zaboIdList, getGroupZaboList, getSearchZaboList } = + this.props; const lastSeen = next ? zaboIdList[zaboIdList.length - 1] : undefined; const fetches = { - main: () => getZaboList ({ lastSeen }), - related: () => getZaboList ({ lastSeen, relatedTo: query }), - pins: () => getPins ({ username: query, lastSeen }), - group: () => getGroupZaboList ({ groupName: query, lastSeen }), + main: () => getZaboList({ lastSeen }), + related: () => getZaboList({ lastSeen, relatedTo: query }), + pins: () => getPins({ username: query, lastSeen }), + group: () => getGroupZaboList({ groupName: query, lastSeen }), // search: () => (!lastSeen ? Promise.resolve (zaboIdList) : getSearchZaboList ({ text: query, lastSeen })), - search: () => Promise.resolve ([]), + search: () => Promise.resolve([]), }; - return fetches[type] () - .then (zaboList => { - if (zaboList.length === 0) this.setState ({ hasNext: false }); - }); - } + return fetches[type]().then((zaboList) => { + if (zaboList.length === 0) this.setState({ hasNext: false }); + }); + }; fetchNext = () => { - this.fetch (true); - } + this.fetch(true); + }; - render () { + render() { const { zaboIdList, type, width } = this.props; const { hasNext } = this.state; const { fetchNext } = this; @@ -86,7 +84,7 @@ class ZaboList extends React.Component { threshold={800} key={[zaboIdList, width]} > - {zaboIdList.map (zaboId => ( + {zaboIdList.map((zaboId) => ( ))} @@ -96,8 +94,8 @@ class ZaboList extends React.Component { } ZaboList.propTypes = { - zaboIdList: PropTypes.arrayOf (PropTypes.string).isRequired, - type: PropTypes.oneOf (['main', 'related', 'pins', 'group', 'search']).isRequired, + zaboIdList: PropTypes.arrayOf(PropTypes.string).isRequired, + type: PropTypes.oneOf(["main", "related", "pins", "group", "search"]).isRequired, getZaboList: PropTypes.func.isRequired, getPins: PropTypes.func.isRequired, getGroupZaboList: PropTypes.func.isRequired, @@ -106,7 +104,7 @@ ZaboList.propTypes = { }; ZaboList.defaultProps = { - query: '', + query: "", }; -export default withStackMaster (ZaboList); +export default withStackMaster(ZaboList); diff --git a/src/components/templates/ZaboList/ZaboList.stories.js b/src/components/templates/ZaboList/ZaboList.stories.js index c396eabf..e088beb4 100644 --- a/src/components/templates/ZaboList/ZaboList.stories.js +++ b/src/components/templates/ZaboList/ZaboList.stories.js @@ -1,8 +1,8 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; +import React from "react"; +import { storiesOf } from "@storybook/react"; -import ZaboList from './index'; +import ZaboList from "./index"; -storiesOf ('templates/ZaboList', module).add ('Default', () => , { - notes: '', +storiesOf("templates/ZaboList", module).add("Default", () => , { + notes: "", }); diff --git a/src/components/templates/ZaboList/ZaboList.styled.js b/src/components/templates/ZaboList/ZaboList.styled.js index 92142641..50f0be06 100644 --- a/src/components/templates/ZaboList/ZaboList.styled.js +++ b/src/components/templates/ZaboList/ZaboList.styled.js @@ -1,4 +1,4 @@ -import styled from 'styled-components'; +import styled from "styled-components"; const ZaboListWrapper = styled.div` width: 100%; diff --git a/src/components/templates/ZaboList/index.js b/src/components/templates/ZaboList/index.js index 9167c0ef..82cca090 100644 --- a/src/components/templates/ZaboList/index.js +++ b/src/components/templates/ZaboList/index.js @@ -1 +1 @@ -export { default } from './ZaboList.container'; +export { default } from "./ZaboList.container"; diff --git a/src/components/templates/ZaboList/withStackMaster.js b/src/components/templates/ZaboList/withStackMaster.js index e6e82f7f..acf368a7 100644 --- a/src/components/templates/ZaboList/withStackMaster.js +++ b/src/components/templates/ZaboList/withStackMaster.js @@ -1,46 +1,46 @@ /* eslint-disable */ -import React from 'react'; -import PropTypes from 'prop-types'; -import storage from 'lib/storage'; +import React from "react"; +import PropTypes from "prop-types"; +import storage from "lib/storage"; -export default Component => { +export default (Component) => { class StackMaster extends React.Component { - state = { stack: [] } + state = { stack: [] }; - componentDidMount () { + componentDidMount() { const { zaboId } = this.props; if (!zaboId) { - storage.setItem ('zaboStack', []); + storage.setItem("zaboStack", []); } else { - let zaboStack = storage.getItem ('zaboStack') || []; - zaboStack = Array.isArray (zaboStack) ? zaboStack : []; - const prev = zaboStack.pop (); - if (!!prev && prev !== zaboId) zaboStack.push (prev); - zaboStack.push (zaboId); - storage.setItem ('zaboStack', zaboStack); - this.setState ({ stack: zaboStack }); + let zaboStack = storage.getItem("zaboStack") || []; + zaboStack = Array.isArray(zaboStack) ? zaboStack : []; + const prev = zaboStack.pop(); + if (!!prev && prev !== zaboId) zaboStack.push(prev); + zaboStack.push(zaboId); + storage.setItem("zaboStack", zaboStack); + this.setState({ stack: zaboStack }); } } - componentDidUpdate (prevProps, prevState, snapshot) { + componentDidUpdate(prevProps, prevState, snapshot) { const { zaboId } = this.props; if (prevProps.zaboId === zaboId) return; if (!zaboId) { - this.setState ({ stack: [] }); - storage.setItem ('zaboStack'); + this.setState({ stack: [] }); + storage.setItem("zaboStack"); return; } - this.setState (prevState => { + this.setState((prevState) => { const { stack } = prevState; - stack.push (zaboId); - storage.setItem ('zaboStack', stack); + stack.push(zaboId); + storage.setItem("zaboStack", stack); return { stack }; }); } - render () { + render() { const { stack } = this.state; const { zaboId, ...props } = this.props; diff --git a/src/components/templates/ZaboUpload/InfoForm.js b/src/components/templates/ZaboUpload/InfoForm.js index d087caa4..32234082 100644 --- a/src/components/templates/ZaboUpload/InfoForm.js +++ b/src/components/templates/ZaboUpload/InfoForm.js @@ -1,76 +1,89 @@ -import React, { - useCallback, useEffect, useMemo, useState, -} from 'react'; -import PropTypes from 'prop-types'; -import { useDispatch, useSelector } from 'react-redux'; -import MomentUtils from '@date-io/moment'; -import { KeyboardDateTimePicker, MuiPickersUtilsProvider } from '@material-ui/pickers'; -import get from 'lodash.get'; -import moment from 'moment'; +import React, { useCallback, useEffect, useMemo, useState } from "react"; +import PropTypes from "prop-types"; +import { useDispatch, useSelector } from "react-redux"; +import MomentUtils from "@date-io/moment"; +import { KeyboardDateTimePicker, MuiPickersUtilsProvider } from "@material-ui/pickers"; +import get from "lodash.get"; +import moment from "moment"; -import ToggleButton from 'atoms/ToggleButton'; -import SimpleSelect from 'molecules/SimpleSelect'; -import StyledQuill from 'organisms/StyledQuill'; +import ToggleButton from "components/atoms/ToggleButton"; +import SimpleSelect from "components/molecules/SimpleSelect"; +import StyledQuill from "components/organisms/StyledQuill"; -import { setInfo } from 'store/reducers/upload'; -import { gridLayoutCompareFunction } from 'lib/utils'; +import { setInfo } from "store/reducers/upload"; +import { gridLayoutCompareFunction } from "lib/utils"; -import { InfoFormWrapper } from './InfoForm.styled'; +import { InfoFormWrapper } from "./InfoForm.styled"; const scheduleTypeOptions = [ - { value: '행사', label: '행사' }, - { value: '신청', label: '신청' }, + { value: "행사", label: "행사" }, + { value: "신청", label: "신청" }, ]; -const scheduleTypeOptionsH = scheduleTypeOptions.reduce ((acc, cur) => ({ - ...acc, [cur.value]: cur, -}), {}); +const scheduleTypeOptionsH = scheduleTypeOptions.reduce( + (acc, cur) => ({ + ...acc, + [cur.value]: cur, + }), + {}, +); const Form = ({ state, setState, preview }) => { - const { - title, description, hasSchedule, schedules, category, - } = state; + const { title, description, hasSchedule, schedules, category } = state; const schedule = schedules[0]; - const { - title: scheduleTitle, startAt, eventType, - } = schedule; + const { title: scheduleTitle, startAt, eventType } = schedule; - const timeLeft = useMemo (() => { + const timeLeft = useMemo(() => { if (!schedule.startAt) return { day: 0, hour: 0, min: 0 }; - const startTime = moment (schedule.startAt); - const current = moment (); - const duration = moment.duration (startTime.diff (current)); + const startTime = moment(schedule.startAt); + const current = moment(); + const duration = moment.duration(startTime.diff(current)); return { - day: duration.days (), - hour: duration.hours (), - min: duration.minutes (), + day: duration.days(), + hour: duration.hours(), + min: duration.minutes(), }; }, [schedule]); - const handleChange = useCallback (e => { - const { name, value } = e.target; - setState ({ [name]: value }); - }, [setState]); + const handleChange = useCallback( + (e) => { + const { name, value } = e.target; + setState({ [name]: value }); + }, + [setState], + ); - const setSchedule = useCallback (({ name, value }) => { - setState ({ schedules: [{ ...schedule, [name]: value }] }); - }, [setState, schedule]); + const setSchedule = useCallback( + ({ name, value }) => { + setState({ schedules: [{ ...schedule, [name]: value }] }); + }, + [setState, schedule], + ); - const onQuillChange = useCallback (e => { - setState ({ description: e }); - }, [setState]); + const onQuillChange = useCallback( + (e) => { + setState({ description: e }); + }, + [setState], + ); - const onTagClick = useCallback (name => { - const clone = category.map (tag => (tag.name === name - ? ({ ...tag, clicked: !tag.clicked }) - : tag)); - setState ({ category: clone }); - }, [setState, category]); + const onTagClick = useCallback( + (name) => { + const clone = category.map((tag) => + tag.name === name ? { ...tag, clicked: !tag.clicked } : tag, + ); + setState({ category: clone }); + }, + [setState, category], + ); - const handleToggle = useCallback (e => { - const { checked } = e.target; - setState ({ hasSchedule: checked }); - }, [setState]); + const handleToggle = useCallback( + (e) => { + const { checked } = e.target; + setState({ hasSchedule: checked }); + }, + [setState], + ); return ( @@ -80,9 +93,7 @@ const Form = ({ state, setState, preview }) => { -
    - {preview && title} -
    +
    {preview && title}
    @@ -106,15 +117,19 @@ const Form = ({ state, setState, preview }) => { placeholder="자보에 대한 설명을 작성해주세요." modules={{ toolbar: [ - ['bold', 'underline', 'strike'], - [{ list: 'ordered' }, { list: 'bullet' }, { indent: '+1' }, { indent: '-1' }], - ['link'], + ["bold", "underline", "strike"], + [{ list: "ordered" }, { list: "bullet" }, { indent: "+1" }, { indent: "-1" }], + ["link"], ], }} />
    - +

    일정이 존재하나요?

    @@ -132,16 +147,18 @@ const Form = ({ state, setState, preview }) => { maxLength="20" name="title" value={scheduleTitle} - onChange={e => setSchedule (e.target)} + onChange={(e) => setSchedule(e.target)} />
    -
    분류
    +
    + 분류 +
    { - setSchedule ({ name: 'eventType', value: newOption.value }); + onChange={(newOption) => { + setSchedule({ name: "eventType", value: newOption.value }); }} isClearable={false} width={150} @@ -155,8 +172,8 @@ const Form = ({ state, setState, preview }) => { required placeholder="우측 달력을 클릭하여 마감일을 선택해주세요." value={startAt} - onChange={value => { - setSchedule ({ name: 'startAt', value }); + onChange={(value) => { + setSchedule({ name: "startAt", value }); }} InputProps={{ disableUnderline: true, @@ -167,16 +184,18 @@ const Form = ({ state, setState, preview }) => { fullWidth ampm={false} invalidDateMessage={

    잘못된 형식입니다.

    } - style={{ height: '38px' }} + style={{ height: "38px" }} />
    다음과 같이 노출됩니다.
    -

    {scheduleTitle || '행사명'}

    -

    {eventType === '신청' && '신청이'} 얼마 남지 않았어요

    -
    남은 시간: {timeLeft.day}일 {timeLeft.hour}시간 {timeLeft.min}분
    +

    {scheduleTitle || "행사명"}

    +

    {eventType === "신청" && "신청이"} 얼마 남지 않았어요

    +
    + 남은 시간: {timeLeft.day}일 {timeLeft.hour}시간 {timeLeft.min}분 +
    @@ -184,11 +203,11 @@ const Form = ({ state, setState, preview }) => {
    태그
    - {category.map (item => ( + {category.map((item) => (
    onTagClick (item.name)} - className={item.clicked ? 'tag selected' : 'tag default'} + onClick={() => onTagClick(item.name)} + className={item.clicked ? "tag selected" : "tag default"} > #{item.name}
    @@ -202,56 +221,57 @@ const Form = ({ state, setState, preview }) => { }; Form.propTypes = { - state: PropTypes.shape ({ + state: PropTypes.shape({ title: PropTypes.string, description: PropTypes.string, hasSchedule: PropTypes.bool, - schedules: PropTypes.arrayOf (PropTypes.shape ({ - title: PropTypes.string, - startAt: PropTypes.string, - endAt: PropTypes.string, - eventType: PropTypes.string, - })), - category: PropTypes.arrayOf (PropTypes.shape ({ - name: PropTypes.string, - clicked: PropTypes.bool, - })), + schedules: PropTypes.arrayOf( + PropTypes.shape({ + title: PropTypes.string, + startAt: PropTypes.string, + endAt: PropTypes.string, + eventType: PropTypes.string, + }), + ), + category: PropTypes.arrayOf( + PropTypes.shape({ + name: PropTypes.string, + clicked: PropTypes.bool, + }), + ), }).isRequired, setState: PropTypes.func.isRequired, preview: PropTypes.string.isRequired, }; const InfoForm = () => { - const dispatch = useDispatch (); - const [preview, setPreview] = useState (); - const info = useSelector (state => get (state, ['upload', 'info'])); - const imageFiles = useSelector (state => get (state, ['upload', 'images'])); + const dispatch = useDispatch(); + const [preview, setPreview] = useState(); + const info = useSelector((state) => get(state, ["upload", "info"])); + const imageFiles = useSelector((state) => get(state, ["upload", "images"])); - useEffect (() => { - const sortedImageFiles = imageFiles.slice (); - sortedImageFiles.sort (gridLayoutCompareFunction); + useEffect(() => { + const sortedImageFiles = imageFiles.slice(); + sortedImageFiles.sort(gridLayoutCompareFunction); const titleImageFile = sortedImageFiles[0]; - let url = ''; + let url = ""; if (titleImageFile) { - url = URL.createObjectURL (titleImageFile); + url = URL.createObjectURL(titleImageFile); } - setPreview (url); + setPreview(url); return () => { - URL.revokeObjectURL (url); + URL.revokeObjectURL(url); }; }, [imageFiles]); - const setState = useCallback (updates => { - dispatch (setInfo ({ ...info, ...updates })); - }, [info]); - - return ( -
    + const setState = useCallback( + (updates) => { + dispatch(setInfo({ ...info, ...updates })); + }, + [info], ); + + return ; }; InfoForm.Form = Form; diff --git a/src/components/templates/ZaboUpload/InfoForm.styled.js b/src/components/templates/ZaboUpload/InfoForm.styled.js index c37fd0c3..e8495994 100644 --- a/src/components/templates/ZaboUpload/InfoForm.styled.js +++ b/src/components/templates/ZaboUpload/InfoForm.styled.js @@ -1,4 +1,4 @@ -import styled, { css } from 'styled-components'; +import styled, { css } from "styled-components"; const InfoFormWrapper = styled.div` padding-bottom: 40px; @@ -7,12 +7,16 @@ const InfoFormWrapper = styled.div` font-size: 18px; font-weight: bold; color: #363636; - &.label-tag { margin-bottom: 12px } - &.small { font-size: 16px } + &.label-tag { + margin-bottom: 12px; + } + &.small { + font-size: 16px; + } } .semi-label { font-size: 16px; - color: #8F8F8F; + color: #8f8f8f; } /*container for all inputs*/ @@ -83,7 +87,7 @@ const InfoFormWrapper = styled.div` margin-bottom: 20px; text-align: center; } - + .submit > button { width: 100%; height: 40px; @@ -122,7 +126,9 @@ const InfoFormWrapper = styled.div` /* ============ Responsive CSS ============ */ /* ======================================== */ @media (min-width: 640px) { - .label.label-tag { margin-bottom: 8px } + .label.label-tag { + margin-bottom: 8px; + } .headerLow { width: 100%; display: flex; @@ -172,7 +178,9 @@ InfoFormWrapper.Header = styled.section` margin: 24px 0 12px 0; font-size: 24px; } - p { padding-bottom: 40px } + p { + padding-bottom: 40px; + } } `; @@ -190,7 +198,7 @@ InfoFormWrapper.TitleImage = styled.section` flex: 1; height: 100%; margin-right: 48px; - background-color: #F4F4F4; + background-color: #f4f4f4; border-radius: 8px; padding: 12px; img { @@ -210,19 +218,20 @@ InfoFormWrapper.TitleImage = styled.section` InfoFormWrapper.Info = styled.section` flex: 1; height: 100%; - input.title-input, input.schedule-title-input { + input.title-input, + input.schedule-title-input { width: 100%; height: 38px; margin: 8px 0 18px 0; padding: 11px 16px; border-radius: 4px; - background-color: #F4F4F4; + background-color: #f4f4f4; color: #202020; border: 0; outline: none; font-size: 14px; &::placeholder { - color: #8F8F8F; + color: #8f8f8f; } } @media (max-width: 640px) { @@ -237,12 +246,17 @@ InfoFormWrapper.Info = styled.section` InfoFormWrapper.Info.Schedule = styled.section` width: 99%; height: 100%; - ${props => (props.hasSchedule ? css` - max-height: 542px; - @media (max-width: 640px) { max-height: 626px } - ` : css` - max-height: 72px; - `)}; + ${(props) => + props.hasSchedule + ? css` + max-height: 542px; + @media (max-width: 640px) { + max-height: 626px; + } + ` + : css` + max-height: 72px; + `}; transition: max-height 0.3s ease-in-out; padding: 0 29px; margin: 30px 0 48px; @@ -269,13 +283,16 @@ InfoFormWrapper.Info.Schedule = styled.section` .body { margin-top: 38px; padding-bottom: 36px; - ${props => (props.hasSchedule ? css` - visibility: visible; - opacity: 1; - ` : css` - visibility: hidden; - opacity: 0; - `)}; + ${(props) => + props.hasSchedule + ? css` + visibility: visible; + opacity: 1; + ` + : css` + visibility: hidden; + opacity: 0; + `}; transition: visibility 0s, opacity 0.5s linear; } .body-container { @@ -295,9 +312,10 @@ InfoFormWrapper.Info.Schedule = styled.section` .schedule-preview-box { margin-top: 8px; padding: 24px 32px; - border: 1px solid #E9E9E9; + border: 1px solid #e9e9e9; border-radius: 4px; - h3, p { + h3, + p { margin: 0; } h3 { @@ -307,11 +325,14 @@ InfoFormWrapper.Info.Schedule = styled.section` min-width: 50px; line-height: 24px; display: inline-block; - ${props => (props.hasTitle ? css` - color: #363636; - ` : css` - color: #D2D2D2; - `)} + ${(props) => + props.hasTitle + ? css` + color: #363636; + ` + : css` + color: #d2d2d2; + `} } p { font-size: 16px; @@ -331,6 +352,4 @@ InfoFormWrapper.Info.Schedule = styled.section` InfoFormWrapper.Editor = styled.section``; -export { - InfoFormWrapper, -}; +export { InfoFormWrapper }; diff --git a/src/components/templates/ZaboUpload/LeavingAlert.js b/src/components/templates/ZaboUpload/LeavingAlert.js index b546135c..4ed680a1 100644 --- a/src/components/templates/ZaboUpload/LeavingAlert.js +++ b/src/components/templates/ZaboUpload/LeavingAlert.js @@ -1,17 +1,17 @@ -import React, { useEffect } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; -import get from 'lodash.get'; +import React, { useEffect } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import get from "lodash.get"; -import { reset, setModal } from 'store/reducers/upload'; +import { reset, setModal } from "store/reducers/upload"; const LeavingAlert = () => { - const dispatch = useDispatch (); - const showModal = useSelector (state => get (state, ['upload', 'showModal'])); - useEffect (() => { + const dispatch = useDispatch(); + const showModal = useSelector((state) => get(state, ["upload", "showModal"])); + useEffect(() => { if (showModal) { - alert ('데이터를 저장하시겠습니까?'); - dispatch (reset ()); - dispatch (setModal (false)); + alert("데이터를 저장하시겠습니까?"); + dispatch(reset()); + dispatch(setModal(false)); } }, [showModal]); return null; diff --git a/src/components/templates/ZaboUpload/Loading.js b/src/components/templates/ZaboUpload/Loading.js index ce772ad4..95ad3e40 100644 --- a/src/components/templates/ZaboUpload/Loading.js +++ b/src/components/templates/ZaboUpload/Loading.js @@ -1,58 +1,58 @@ -import React from 'react'; -import styled from 'styled-components'; +import React from "react"; +import styled from "styled-components"; const Style = styled.div` position: fixed; top: 0; left: 0; align-items: center; - background-color: rgba(29,31,32, 0.5); + background-color: rgba(29, 31, 32, 0.5); display: flex; justify-content: center; width: 100%; height: 100%; - - .loader { + + .loader { position: fixed; left: 50%; top: 50%; - animation: rotate 1s infinite; + animation: rotate 1s infinite; height: 50px; width: 50px; } - + .loader:before, - .loader:after { + .loader:after { border-radius: 50%; - content: ''; + content: ""; display: block; - height: 20px; + height: 20px; width: 20px; } .loader:before { - animation: ball1 1s infinite; + animation: ball1 1s infinite; background-color: #cb2025; box-shadow: 30px 0 0 #f8b334; margin-bottom: 10px; } .loader:after { - animation: ball2 1s infinite; + animation: ball2 1s infinite; background-color: #00a096; box-shadow: 30px 0 0 #97bf0d; } - + @keyframes rotate { - 0% { - transform: rotate(0deg) scale(0.8); + 0% { + transform: rotate(0deg) scale(0.8); } - 50% { - transform: rotate(360deg) scale(1.2); + 50% { + transform: rotate(360deg) scale(1.2); } - 100% { - transform: rotate(720deg) scale(0.8); + 100% { + transform: rotate(720deg) scale(0.8); } } - + @keyframes ball1 { 0% { box-shadow: 30px 0 0 #f8b334; @@ -60,14 +60,14 @@ const Style = styled.div` 50% { box-shadow: 0 0 0 #f8b334; margin-bottom: 0; - transform: translate(15px,15px); + transform: translate(15px, 15px); } 100% { box-shadow: 30px 0 0 #f8b334; margin-bottom: 10px; } } - + @keyframes ball2 { 0% { box-shadow: 30px 0 0 #97bf0d; @@ -75,7 +75,7 @@ const Style = styled.div` 50% { box-shadow: 0 0 0 #97bf0d; margin-top: -20px; - transform: translate(15px,15px); + transform: translate(15px, 15px); } 100% { box-shadow: 30px 0 0 #97bf0d; diff --git a/src/components/templates/ZaboUpload/SelectGroup.js b/src/components/templates/ZaboUpload/SelectGroup.js index 0688d802..45545f06 100644 --- a/src/components/templates/ZaboUpload/SelectGroup.js +++ b/src/components/templates/ZaboUpload/SelectGroup.js @@ -1,16 +1,16 @@ -import React, { useCallback, useMemo } from 'react'; -import PropTypes from 'prop-types'; -import { useDispatch, useSelector } from 'react-redux'; -import styled from 'styled-components'; -import List from '@material-ui/core/List'; -import ListItem from '@material-ui/core/ListItem'; -import { makeStyles } from '@material-ui/core/styles'; -import get from 'lodash.get'; +import React, { useCallback, useMemo } from "react"; +import PropTypes from "prop-types"; +import { useDispatch, useSelector } from "react-redux"; +import styled from "styled-components"; +import List from "@material-ui/core/List"; +import ListItem from "@material-ui/core/ListItem"; +import { makeStyles } from "@material-ui/core/styles"; +import get from "lodash.get"; -import { setCurrentGroup } from 'store/reducers/auth'; -import { setGroupSelected } from 'store/reducers/upload'; +import { setCurrentGroup } from "store/reducers/auth"; +import { setGroupSelected } from "store/reducers/upload"; -import groupDefaultProfile from 'static/images/groupDefaultProfile.png'; +import groupDefaultProfile from "static/images/groupDefaultProfile.png"; const SelectGroupWrapper = styled.div` h1 { @@ -33,7 +33,7 @@ const SelectGroupWrapper = styled.div` } .divider { - border: 1px solid #E9E9E9; + border: 1px solid #e9e9e9; width: 582px; } @@ -49,12 +49,18 @@ const SelectGroupWrapper = styled.div` color: #202020; } li:hover { - h3 { color: #143441 } - .subtitle { color: #202020 } + h3 { + color: #143441; + } + .subtitle { + color: #202020; + } } - li.Mui-selected, li.Mui-selected:hover { + li.Mui-selected, + li.Mui-selected:hover { background-color: #143441; - h3, .subtitle { + h3, + .subtitle { color: white; } } @@ -63,116 +69,115 @@ const SelectGroupWrapper = styled.div` margin: 24px 0 12px 0; font-size: 24px; } - p { padding-bottom: 28px } + p { + padding-bottom: 28px; + } img { width: 60px; height: 60px; margin-right: 12px; } - h3 { font-size: 16px } - .subtitle { font-size: 14px } + h3 { + font-size: 16px; + } + .subtitle { + font-size: 14px; + } } `; -const useStyles = makeStyles (theme => ({ +const useStyles = makeStyles((theme) => ({ root: { - width: '100%', + width: "100%", backgroundColor: theme.palette.background.paper, padding: 0, }, item: { - width: '582px', - height: '106px', - '@media (max-width: 640px)': { - width: '100%', - height: '84px', + width: "582px", + height: "106px", + "@media (max-width: 640px)": { + width: "100%", + height: "84px", }, - '&.Mui-selected': { - backgroundColor: '#143441', + "&.Mui-selected": { + backgroundColor: "#143441", }, - '&:hover': { - backgroundColor: '#F4F4F4', - cursor: 'pointer', + "&:hover": { + backgroundColor: "#F4F4F4", + cursor: "pointer", }, }, })); const InsetDividers = ({ groupsInfo }) => { - const classes = useStyles (); - const currentGroup = useSelector (state => get (state, ['auth', 'info', 'currentGroup'])); - const dispatch = useDispatch (); + const classes = useStyles(); + const currentGroup = useSelector((state) => get(state, ["auth", "info", "currentGroup"])); + const dispatch = useDispatch(); - const updateGroup = useCallback (groupName => { - dispatch (setCurrentGroup (groupName)) - .then (() => dispatch (setGroupSelected (true))) - .catch (error => console.error (error)); + const updateGroup = useCallback((groupName) => { + dispatch(setCurrentGroup(groupName)) + .then(() => dispatch(setGroupSelected(true))) + .catch((error) => console.error(error)); }, []); return ( - { - groupsInfo.map ((info, i) => { - const { - _id, name, lastUpdated, subtitle, profilePhoto, - } = info; - return ( - - updateGroup (name)} - > - { - profilePhoto - ? profile photo - : default profile img - } -
    -

    {name}

    -
    {subtitle}
    -
    -
    - {i !== groupsInfo.length - 1 &&
    } -
    - ); - }) - } + {groupsInfo.map((info, i) => { + const { _id, name, lastUpdated, subtitle, profilePhoto } = info; + return ( + + updateGroup(name)} + > + {profilePhoto ? ( + profile photo + ) : ( + default profile img + )} +
    +

    {name}

    +
    {subtitle}
    +
    +
    + {i !== groupsInfo.length - 1 &&
    } +
    + ); + })}
    ); }; InsetDividers.propTypes = { - groupsInfo: PropTypes.arrayOf (PropTypes.shape ({ - _id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, - members: PropTypes.array, - lastUpdated: PropTypes.string, - })), + groupsInfo: PropTypes.arrayOf( + PropTypes.shape({ + _id: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + members: PropTypes.array, + lastUpdated: PropTypes.string, + }), + ), }; InsetDividers.defaultProps = { groupsInfo: [], }; - const SelectGroup = () => { - const groupsInfo = useSelector (state => get (state, ['auth', 'info', 'groups'])); + const groupsInfo = useSelector((state) => get(state, ["auth", "info", "groups"])); return (

    그룹 선택하기

    - {(groupsInfo && groupsInfo.length) - ? ( -
    -

    - 자보를 업로드할 소속 그룹을 선택해주세요. -

    - -
    - ) - :

    현재 속해 있는 그룹이 없습니다.

    } + {groupsInfo && groupsInfo.length ? ( +
    +

    자보를 업로드할 소속 그룹을 선택해주세요.

    + +
    + ) : ( +

    현재 속해 있는 그룹이 없습니다.

    + )}
    ); }; diff --git a/src/components/templates/ZaboUpload/UploadImages.js b/src/components/templates/ZaboUpload/UploadImages.js index da1442b0..e00324b7 100644 --- a/src/components/templates/ZaboUpload/UploadImages.js +++ b/src/components/templates/ZaboUpload/UploadImages.js @@ -1,57 +1,54 @@ -import './grid-layout.scss'; +import "./grid-layout.scss"; -import React, { - useCallback, useEffect, useMemo, useReducer, - useState, -} from 'react'; -import { useDispatch, useSelector } from 'react-redux'; -import { useDropzone } from 'react-dropzone'; -import styled, { css } from 'styled-components'; -import CloseIcon from '@material-ui/icons/Close'; -import { Responsive, WidthProvider } from '@sparcs-kaist/react-grid-layout'; -import debounce from 'lodash.debounce'; -import get from 'lodash.get'; -import throttle from 'lodash.throttle'; +import React, { useCallback, useEffect, useMemo, useReducer, useState } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { useDropzone } from "react-dropzone"; +import styled, { css } from "styled-components"; +import CloseIcon from "@material-ui/icons/Close"; +import { Responsive, WidthProvider } from "@sparcs-kaist/react-grid-layout"; +import debounce from "lodash.debounce"; +import get from "lodash.get"; +import throttle from "lodash.throttle"; -import { setImages } from 'store/reducers/upload'; -import useSetState from 'hooks/useSetState'; -import { gridLayoutCompareFunction, loadImageFile } from 'lib/utils'; +import { setImages } from "store/reducers/upload"; +import useSetState from "hooks/useSetState"; +import { gridLayoutCompareFunction, loadImageFile } from "lib/utils"; -import uploadImg from 'static/images/uploadImg.png'; +import uploadImg from "static/images/uploadImg.png"; -const ResponsiveGridLayout = WidthProvider (Responsive); +const ResponsiveGridLayout = WidthProvider(Responsive); const baseStyle = { flex: 1, - display: 'flex', - flexDirection: 'column', - alignItems: 'center', - borderRadius: '8px', - borderColor: '#eeeeee', - backgroundColor: '#fafafa', - color: '#bdbdbd', - outline: 'none', - transition: 'border .24s ease-in-out', + display: "flex", + flexDirection: "column", + alignItems: "center", + borderRadius: "8px", + borderColor: "#eeeeee", + backgroundColor: "#fafafa", + color: "#bdbdbd", + outline: "none", + transition: "border .24s ease-in-out", }; const activeStyle = { - borderColor: '#2196f3', + borderColor: "#2196f3", }; const acceptStyle = { - borderColor: '#00e676', + borderColor: "#00e676", }; const rejectStyle = { - borderColor: '#ff1744', + borderColor: "#ff1744", }; const thumbsContainer = { - display: 'flex', - flexDirection: 'row', - flexWrap: 'wrap', + display: "flex", + flexDirection: "row", + flexWrap: "wrap", marginTop: 16, - width: '100%', + width: "100%", }; const GridItem = styled.div` @@ -66,7 +63,7 @@ const ThumbOverlay = styled.div` width: 100%; height: 100%; z-index: 1000; - background-color: rgba(0,0,0,0.03); + background-color: rgba(0, 0, 0, 0.03); svg { visibility: hidden; } @@ -102,7 +99,7 @@ const ThumbInner = styled.div` const ThumbImage = styled.img` display: block; - ${props => { + ${(props) => { const { titleHeight, titleRatio, ratio } = props.info; if (!titleRatio || !ratio) return css``; if (ratio >= titleRatio) { @@ -113,7 +110,7 @@ const ThumbImage = styled.img` } return css` width: 200px; - height: ${Math.floor (200 / ratio)}px; + height: ${Math.floor(200 / ratio)}px; `; }}; `; @@ -132,7 +129,7 @@ const Wrapper = styled.section` text-align: right; button { width: 93px; - background: #F8F8F8; + background: #f8f8f8; border: 1.5px solid #143441; border-radius: 15px; padding: 8px 12px; @@ -152,7 +149,7 @@ const Wrapper = styled.section` } p { margin: 0; - &.placeholder-mobile { + &.placeholder-mobile { font-size: 14px; display: none; } @@ -172,14 +169,20 @@ const Wrapper = styled.section` margin: 24px 0 12px 0; font-size: 24px; } - .buttonDiv { display: none } + .buttonDiv { + display: none; + } .img.upload-icon { width: 16px; height: 16px; } p { - &.placeholder-web { display: none } - &.placeholder-mobile { display: block } + &.placeholder-web { + display: none; + } + &.placeholder-mobile { + display: block; + } } .base-component { min-height: 235px; @@ -189,26 +192,31 @@ const Wrapper = styled.section` `; Wrapper.Subtitle = styled.div` - .subtitle1, .subtitle2 { + .subtitle1, + .subtitle2 { display: inline-block; font-size: 16px; - color: #202020; + color: #202020; margin: 0; &.placeholder { - color: #8F8F8F; + color: #8f8f8f; } } - .subtitle-star { + .subtitle-star { display: none; font-size: 12px; } @media (max-width: 640px) { - .subtitle1 { display: block } - .subtitle2 { + .subtitle1 { + display: block; + } + .subtitle2 { font-size: 12px; margin: 10px 0 40px 0; } - .subtitle-star { display: inline-block } + .subtitle-star { + display: inline-block; + } } `; Wrapper.Subtitle.Sub = styled.div` @@ -224,89 +232,105 @@ Wrapper.Placeholder = styled.div` display: flex; align-items: center; justify-content: center; - ${props => (props.noFile ? '' : css` - position: relative; - height: 80px; - `)} + ${(props) => + props.noFile + ? "" + : css` + position: relative; + height: 80px; + `} `; let alerted; -const alertOnce = message => { +const alertOnce = (message) => { if (alerted) return; alerted = true; - alert (message); + alert(message); }; -const UploadImages = props => { - const reduxDispatch = useDispatch (); - const files = useSelector (state => get (state, ['upload', 'images'])); - const setFiles = newFiles => reduxDispatch (setImages (newFiles)); - const [widthInfo, setWidthInfo] = useState ({ +const UploadImages = (props) => { + const reduxDispatch = useDispatch(); + const files = useSelector((state) => get(state, ["upload", "images"])); + const setFiles = (newFiles) => reduxDispatch(setImages(newFiles)); + const [widthInfo, setWidthInfo] = useState({ width: 0, margin: 0, cols: 5, containerPadding: 0, }); const { cols } = widthInfo; - const [imagesInfo, setImagesInfo] = useSetState ({ + const [imagesInfo, setImagesInfo] = useSetState({ title: { ratio: 1, height: 200, }, }); const { key: titleKey, height: titleHeight, ratio: titleRatio } = imagesInfo.title; - const [showAlert, setShowAlert] = useState (false); + const [showAlert, setShowAlert] = useState(false); if (showAlert) { - alertOnce ('대표 이미지의 사진 비율이 너무 크거나 작습니다. 최대 비율에 맞게 조정되었습니다.'); - setShowAlert (false); + alertOnce("대표 이미지의 사진 비율이 너무 크거나 작습니다. 최대 비율에 맞게 조정되었습니다."); + setShowAlert(false); } - const dd = useMemo (() => debounce (setShowAlert, 500), []); - - const addImages = useCallback (acceptedFiles => { - setFiles ([ - ...files.map (file => Object.assign (file, { layout: file.updatedLayout })), - ...acceptedFiles.map ((file, index) => { - const i = files.length + index; - const key = `${file.name}-${i}`; // TODO: make it unique - const layout = { - x: i % cols, y: Math.floor (i / cols), w: 1, h: 1, i: key, - }; - return Object.assign (file, { - preview: URL.createObjectURL (file), key, layout, updatedLayout: layout, - }); - }), - ]); - }, [files]); + const dd = useMemo(() => debounce(setShowAlert, 500), []); + + const addImages = useCallback( + (acceptedFiles) => { + setFiles([ + ...files.map((file) => Object.assign(file, { layout: file.updatedLayout })), + ...acceptedFiles.map((file, index) => { + const i = files.length + index; + const key = `${file.name}-${i}`; // TODO: make it unique + const layout = { + x: i % cols, + y: Math.floor(i / cols), + w: 1, + h: 1, + i: key, + }; + return Object.assign(file, { + preview: URL.createObjectURL(file), + key, + layout, + updatedLayout: layout, + }); + }), + ]); + }, + [files], + ); - const removeImage = useCallback (key => { - const clone = files.slice ().map (x => Object.assign (x, { layout: { ...x.updatedLayout } })); - clone.sort (gridLayoutCompareFunction); - const deleteIndex = clone.findIndex (l => l.key === key); - if (deleteIndex === -1) return; - clone.splice (deleteIndex, 1); - for (let i = deleteIndex; i < clone.length; i += 1) { - clone[i].layout.x -= 1; - clone[i].updatedLayout.x -= 1; - if (clone[i].layout.x < 0) { - clone[i].layout.y -= 1; - clone[i].layout.x = cols - 1; - clone[i].updatedLayout.y -= 1; - clone[i].updatedLayout.x = cols - 1; + const removeImage = useCallback( + (key) => { + const clone = files.slice().map((x) => Object.assign(x, { layout: { ...x.updatedLayout } })); + clone.sort(gridLayoutCompareFunction); + const deleteIndex = clone.findIndex((l) => l.key === key); + if (deleteIndex === -1) return; + clone.splice(deleteIndex, 1); + for (let i = deleteIndex; i < clone.length; i += 1) { + clone[i].layout.x -= 1; + clone[i].updatedLayout.x -= 1; + if (clone[i].layout.x < 0) { + clone[i].layout.y -= 1; + clone[i].layout.x = cols - 1; + clone[i].updatedLayout.y -= 1; + clone[i].updatedLayout.x = cols - 1; + } } - } - setFiles (clone); - }, [files]); + setFiles(clone); + }, + [files], + ); - const updateImagesInfo = useCallback (async () => { + const updateImagesInfo = useCallback(async () => { const titleInfo = { ratio: 1, height: 200, }; const newImagesInfo = {}; - await Promise.all ( - files.map (async file => { + await Promise.all( + files.map(async (file) => { const { key } = file; - const isTitle = (file.updatedLayout.x === 0 && file.updatedLayout.y === 0); + const isTitle = file.updatedLayout.x === 0 && file.updatedLayout.y === 0; const info = imagesInfo[key]; if (isTitle) { titleInfo.key = file.key; @@ -314,134 +338,140 @@ const UploadImages = props => { if (info) { if (!isTitle) return; if (titleKey === key) { - Object.assign (titleInfo, info); + Object.assign(titleInfo, info); return; } titleInfo.ratio = info.ratio; return; } - const image = await loadImageFile (file); + const image = await loadImageFile(file); const ratio = image.width / image.height; if (isTitle) { titleInfo.ratio = ratio; } - newImagesInfo[key] = { key: file.key, ratio, height: Math.floor (200 / ratio) }; + newImagesInfo[key] = { key: file.key, ratio, height: Math.floor(200 / ratio) }; }), ); const tr = titleInfo.ratio; if (tr > 2) { titleInfo.ratio = 2; - dd (true); + dd(true); } else if (tr < 0.5) { titleInfo.ratio = 0.5; - dd (true); + dd(true); } else { - dd (false); + dd(false); } - titleInfo.height = Math.floor (200 / titleInfo.ratio); + titleInfo.height = Math.floor(200 / titleInfo.ratio); newImagesInfo.title = titleInfo; - setImagesInfo (newImagesInfo); + setImagesInfo(newImagesInfo); }, [files, imagesInfo]); const reducer = (state, action) => { switch (action.type) { - case 'addImages': { - const { acceptedFiles } = action; - addImages (acceptedFiles); - break; - } - case 'removeImage': { - removeImage (action.key); - break; - } - case 'relocate': { - const clone = files.slice (); - clone.sort (gridLayoutCompareFunction); - const result = clone.map ((file, index) => { - const newLayout = { - ...file.updatedLayout, - x: index % cols, - y: Math.floor (index / cols), - }; - return Object.assign (file, { layout: newLayout, updatedLayout: newLayout }); - }); - setFiles (result); - break; - } - case 'updateImagesInfo': { - updateImagesInfo ().catch (error => console.error (error)); - break; - } - case 'revokeObjectURL': { - setTimeout (() => { - files.forEach (file => URL.revokeObjectURL (file.preview)); - }, 0); - break; - } - case 'updateLayout': { - const { layout } = action; - const clone = files.map ((file, index) => Object.assign (file, { updatedLayout: layout[index] })); - setFiles (clone); - break; - } - default: { - throw new Error (action.type); - } + case "addImages": { + const { acceptedFiles } = action; + addImages(acceptedFiles); + break; + } + case "removeImage": { + removeImage(action.key); + break; + } + case "relocate": { + const clone = files.slice(); + clone.sort(gridLayoutCompareFunction); + const result = clone.map((file, index) => { + const newLayout = { + ...file.updatedLayout, + x: index % cols, + y: Math.floor(index / cols), + }; + return Object.assign(file, { layout: newLayout, updatedLayout: newLayout }); + }); + setFiles(result); + break; + } + case "updateImagesInfo": { + updateImagesInfo().catch((error) => console.error(error)); + break; + } + case "revokeObjectURL": { + setTimeout(() => { + files.forEach((file) => URL.revokeObjectURL(file.preview)); + }, 0); + break; + } + case "updateLayout": { + const { layout } = action; + const clone = files.map((file, index) => + Object.assign(file, { updatedLayout: layout[index] }), + ); + setFiles(clone); + break; + } + default: { + throw new Error(action.type); + } } }; - const [, dispatch] = useReducer (reducer, null); - const throttledDispatch = useMemo (() => throttle (dispatch, 100), [dispatch]); + const [, dispatch] = useReducer(reducer, null); + const throttledDispatch = useMemo(() => throttle(dispatch, 100), [dispatch]); - useEffect (() => () => dispatch ({ type: 'revokeObjectURL' }), []); // Make sure to revoke the data uris to avoid memory leaks - useEffect (() => { - dispatch ({ type: 'updateImagesInfo' }); + useEffect(() => () => dispatch({ type: "revokeObjectURL" }), []); // Make sure to revoke the data uris to avoid memory leaks + useEffect(() => { + dispatch({ type: "updateImagesInfo" }); }, [files]); - useEffect (() => { - dispatch ({ type: 'relocate' }); + useEffect(() => { + dispatch({ type: "relocate" }); }, [cols, dispatch]); - const { - getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject, open, - } = useDropzone ({ - accept: 'image/*', - onDrop: acceptedFiles => { - if (files.length + acceptedFiles.length > 20) { - alert ('이미지는 최대 20개까지 업로드 할 수 있습니다.'); - acceptedFiles.splice (20 - files.length); - } - dispatch ({ type: 'addImages', acceptedFiles }); - }, - }); + const { getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject, open } = + useDropzone({ + accept: "image/*", + onDrop: (acceptedFiles) => { + if (files.length + acceptedFiles.length > 20) { + alert("이미지는 최대 20개까지 업로드 할 수 있습니다."); + acceptedFiles.splice(20 - files.length); + } + dispatch({ type: "addImages", acceptedFiles }); + }, + }); + + const thumbs = useMemo( + () => + files.map(({ key, preview }) => ( + + + + { + e.stopPropagation(); + dispatch({ type: "removeImage", key }); + }} + /> + + + + + + + )), + [files, imagesInfo, dispatch], + ); - const thumbs = useMemo (() => files.map (({ key, preview }) => ( - - - - { - e.stopPropagation (); - dispatch ({ type: 'removeImage', key }); - }} - /> - - - - - - - )), [files, imagesInfo, dispatch]); - - const style = useMemo ( + const style = useMemo( () => ({ ...baseStyle, ...(isDragActive ? activeStyle : {}), @@ -458,15 +488,17 @@ const UploadImages = props => {
    이미지를 업로드하세요.  
    *
    -
    최대 20장까지 업로드 가능합니다. (이미지 사이즈는 첫 대표 이미지의 크기로 설정됩니다)
    +
    + 최대 20장까지 업로드 가능합니다. (이미지 사이즈는 첫 대표 이미지의 크기로 설정됩니다) +
    -
    - -