diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..ae8a53c --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,2 @@ +# set ubuntu version to 20.04 - https://github.com/devcontainers/features/issues/372 +FROM mcr.microsoft.com/vscode/devcontainers/base:0-ubuntu-20.04 diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..a3475d4 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,19 @@ +{ + "name": "GCP playground", + "image": "mcr.microsoft.com/vscode/devcontainers/python:3", + "features": { + "ghcr.io/devcontainers/features/sshd:1": { + "version": "latest" + } + }, + "settings": { + "extensions.ignoreRecommendations": true, + "workbench.startupEditor": "none", + "workbench.colorTheme": "Visual Studio Dark", + "workbench.colorCustomizations": {}, + "workbench.welcomePage.walkthroughs.openOnInstall": false, + "workbench.welcomePage.experimental.videoTutorials": "off", + "github.codespaces.defaultExtensions": [] + }, + "postStartCommand": "bash -c .devcontainer/setup.sh" +} diff --git a/.devcontainer/setup.sh b/.devcontainer/setup.sh index f7bc939..48eb4c1 100755 --- a/.devcontainer/setup.sh +++ b/.devcontainer/setup.sh @@ -6,19 +6,7 @@ export ENGINE_EVENT_ENDPOINT="${ENGINE_BASE_URL}/users/${WILCO_ID}/event" # Update engine that codespace started for user curl -L -X POST "${ENGINE_EVENT_ENDPOINT}" -H "Content-Type: application/json" --data-raw "{ \"event\": \"github_codespace_started\" }" -# Export backend envs when in codespaces -echo "export CODESPACE_BACKEND_HOST=\"${CODESPACE_BACKEND_HOST}\"" >> ~/.bashrc -echo "export CODESPACE_BACKEND_URL=\"${CODESPACE_BACKEND_URL}\"" >> ~/.bashrc -echo "export CODESPACE_WDS_SOCKET_PORT=443" >> ~/.bashrc - -# Export welcome prompt in bash: -echo "printf \"\n\n☁️☁️☁️️ Anythink: Develop in the Cloud ☁️☁️☁️\n\"" >> ~/.bashrc -echo "printf \"\n\x1b[31m \x1b[1m👉 Type: \\\`docker compose up\\\` to run the project. 👈\n\n\"" >> ~/.bashrc - -nohup bash -c "cd /wilco-agent && node agent.js &" >> /tmp/agent.log 2>&1 - -# Check if docker is installed -if command -v docker &> /dev/null -then - docker compose pull -fi +echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] http://packages.cloud.google.com/apt cloud-sdk main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list +curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - +sudo apt-get update +sudo apt-get install -y google-cloud-sdk diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index 8ebf549..0000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1,3 +0,0 @@ -# Description - -Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. diff --git a/.github/workflows/k8s.yml b/.github/workflows/k8s.yml deleted file mode 100644 index 9a56d6a..0000000 --- a/.github/workflows/k8s.yml +++ /dev/null @@ -1,157 +0,0 @@ -name: Build and deploy to Kubernetes -on: - push: - branches: - - main - -concurrency: - group: k8s - cancel-in-progress: true - -jobs: - check-kubernetes-enabled: - runs-on: ubuntu-20.04 - outputs: - kubernetes-enabled: ${{ steps.kubernetes-flag-defined.outputs.DEFINED }} - steps: - - id: kubernetes-flag-defined - if: "${{ env.ENABLE_KUBERNETES != '' }}" - run: echo "DEFINED=true" >> $GITHUB_OUTPUT - env: - ENABLE_KUBERNETES: ${{ secrets.ENABLE_KUBERNETES }} - - check-secret: - runs-on: ubuntu-20.04 - needs: [check-kubernetes-enabled] - outputs: - aws-creds-defined: ${{ steps.aws-creds-defined.outputs.DEFINED }} - kubeconfig-defined: ${{ steps.kubeconfig-defined.outputs.DEFINED }} - if: needs.check-kubernetes-enabled.outputs.kubernetes-enabled == 'true' - steps: - - id: aws-creds-defined - if: "${{ env.AWS_ACCESS_KEY_ID != '' && env.AWS_SECRET_ACCESS_KEY != '' }}" - run: echo "DEFINED=true" >> $GITHUB_OUTPUT - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - - - id: kubeconfig-defined - if: "${{ env.KUBECONFIG != '' }}" - run: echo "DEFINED=true" >> $GITHUB_OUTPUT - env: - KUBECONFIG: ${{ secrets.KUBECONFIG }} - - build-backend: - name: Build backend image - runs-on: ubuntu-20.04 - needs: [check-secret] - if: needs.check-secret.outputs.aws-creds-defined == 'true' - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v1-node16 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: us-east-2 - - - name: Login to Amazon ECR - id: login-ecr - uses: aws-actions/amazon-ecr-login@v1 - - - name: Set the image tag - run: echo IMAGE_TAG=${GITHUB_REPOSITORY/\//-}-latest >> $GITHUB_ENV - - - name: Set repository name - run: | - if [ ${{ secrets.CLUSTER_ENV }} == 'staging' ]; then - echo "REPO_NAME=staging-anythink-backend" >> $GITHUB_ENV - else - echo "REPO_NAME=anythink-backend" >> $GITHUB_ENV - fi - - - name: Build, tag, and push backend image to Amazon ECR - id: build-image-backend - run: | - docker build \ - -t ${{ steps.login-ecr.outputs.registry }}/${{ env.REPO_NAME }}:${{ env.IMAGE_TAG }} \ - -f backend/Dockerfile.aws \ - . - docker push ${{ steps.login-ecr.outputs.registry }}/${{ env.REPO_NAME }}:${{ env.IMAGE_TAG }} - - build-frontend: - name: Build frontend images - runs-on: ubuntu-20.04 - needs: [check-secret] - if: needs.check-secret.outputs.aws-creds-defined == 'true' - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v1-node16 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: us-east-2 - - - name: Login to Amazon ECR - id: login-ecr - uses: aws-actions/amazon-ecr-login@v1 - - - name: Set the image tag - run: echo IMAGE_TAG=${GITHUB_REPOSITORY/\//-}-latest >> $GITHUB_ENV - - - name: Set repository name - run: | - if [ ${{ secrets.CLUSTER_ENV }} == 'staging' ]; then - echo "REPO_NAME=staging-anythink-frontend" >> $GITHUB_ENV - else - echo "REPO_NAME=anythink-frontend" >> $GITHUB_ENV - fi - - - name: Build, tag, and push frontend image to Amazon ECR - id: build-image-frontend - run: | - docker build \ - -t ${{ steps.login-ecr.outputs.registry }}/${{ env.REPO_NAME }}:${{ env.IMAGE_TAG }} \ - -f frontend/Dockerfile.aws \ - . - docker push ${{ steps.login-ecr.outputs.registry }}/${{ env.REPO_NAME }}:${{ env.IMAGE_TAG }} - - deploy: - name: Deploy latest tag using helm - runs-on: ubuntu-20.04 - if: needs.check-secret.outputs.kubeconfig-defined == 'true' - needs: - - build-frontend - - build-backend - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Create kube config - run: | - mkdir -p $HOME/.kube/ - echo "${{ secrets.KUBECONFIG }}" > $HOME/.kube/config - chmod 600 $HOME/.kube/config - - name: Install helm - run: | - curl -LO https://get.helm.sh/helm-v3.8.0-linux-amd64.tar.gz - tar -zxvf helm-v3.8.0-linux-amd64.tar.gz - mv linux-amd64/helm /usr/local/bin/helm - helm version - - name: Lint helm charts - run: helm lint ./charts/ - - - name: Set the image tag - run: echo IMAGE_TAG=${GITHUB_REPOSITORY/\//-}-latest >> $GITHUB_ENV - - - name: Deploy - run: | - helm upgrade --install --timeout 10m anythink-market ./charts/ \ - --set clusterEnv=${{ secrets.CLUSTER_ENV }} \ - --set frontend.image.tag=${{ env.IMAGE_TAG }} \ - --set backend.image.tag=${{ env.IMAGE_TAG }} diff --git a/.github/workflows/wilco-actions.yml b/.github/workflows/wilco-actions.yml new file mode 100644 index 0000000..b732c86 --- /dev/null +++ b/.github/workflows/wilco-actions.yml @@ -0,0 +1,24 @@ +on: + pull_request: + branches: + - main + +jobs: + wilco: + runs-on: ubuntu-20.04 + timeout-minutes: 10 + name: Pr checks + + steps: + - name: Check out project + uses: actions/checkout@v2 + + - uses: oNaiPs/secrets-to-env-action@v1 + with: + secrets: ${{ toJSON(secrets) }} + + - name: Wilco checks + id: Wilco + uses: trywilco/actions@main + with: + engine: ${{ secrets.WILCO_ENGINE_URL }} diff --git a/.gitignore b/.gitignore index 10d146d..a09c56d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,37 +1 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/backend/node_modules -/frontend/node_modules -/.wilco-helpers/node_modules -/tests/e2e/node_modules -/tests/frontend/node_modules/ -/tests/frontend/test-results/ -/tests/frontend/playwright-report/ -/tests/frontend/playwright/.cache/ - -/.pnp -.pnp.js - -# testing -/coverage - -# production -/backend/build -/frontend/build - -# misc -.DS_Store -.env -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -#IDEs -/.idea/ +/.idea diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 0c878f1..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "workbench.startupEditor": "none" -} diff --git a/README.md b/README.md new file mode 100644 index 0000000..1eecd16 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# gcp-playground +GCP playground diff --git a/create_wilco_user.sh b/create_wilco_user.sh new file mode 100755 index 0000000..977fb0a --- /dev/null +++ b/create_wilco_user.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +# Variables +SERVICE_ACCOUNT_NAME="wilco-checks-service-account" +DESCRIPTION="Verify wilco actions" +DISPLAY_NAME="Wilco checks" +PROJECT_ID=$(gcloud config get-value project) +ROLE="roles/owner" +KEY_FILE_PATH="/tmp/wilco_creds.json" + +# Create the service account +gcloud iam service-accounts create $SERVICE_ACCOUNT_NAME \ + --description="$DESCRIPTION" \ + --display-name="$DISPLAY_NAME" + +# Assign the role to the service account +gcloud projects add-iam-policy-binding $PROJECT_ID \ + --member="serviceAccount:${SERVICE_ACCOUNT_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" \ + --role="$ROLE" + +# Generate the key file for the service account +gcloud iam service-accounts keys create $KEY_FILE_PATH \ + --iam-account "${SERVICE_ACCOUNT_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" + +gcloud services enable dataflow.googleapis.com + +credentials="`cat $KEY_FILE_PATH`" +stringified_credentials="$(echo "$credentials" | jq -R -s .)" + + +WILCO_ID="`cat .wilco`" +export ENGINE_EVENT_ENDPOINT="${ENGINE_BASE_URL}/users/${WILCO_ID}/event" + +# Update engine with service account credentials + +curl -L -X POST "${ENGINE_EVENT_ENDPOINT}" -H "Content-Type: application/json" --data-raw "{ \"event\": \"gcp_service_account_created\", \"metadata\": {\"credentials\": $stringified_credentials, \"project_id\": \"$PROJECT_ID\" }}" + +export GOOGLE_APPLICATION_CREDENTIALS=$KEY_FILE_PATH + +echo "Service account created successfully" diff --git a/frontend/.eslintignore b/frontend/.eslintignore deleted file mode 100644 index dd87e2d..0000000 --- a/frontend/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -build diff --git a/frontend/.gitignore b/frontend/.gitignore deleted file mode 100644 index edfc119..0000000 --- a/frontend/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -# See http://help.github.com/ignore-files/ for more about ignoring files. - -# dependencies -node_modules - -# testing -coverage - -# production -build - -# misc -.DS_Store -.env -npm-debug.log -.idea \ No newline at end of file diff --git a/frontend/Dockerfile.aws b/frontend/Dockerfile.aws deleted file mode 100644 index 9485ac1..0000000 --- a/frontend/Dockerfile.aws +++ /dev/null @@ -1,9 +0,0 @@ -FROM node:16 -WORKDIR /usr/src - -COPY frontend ./frontend -COPY .wilco ./.wilco - -# Pre-install npm packages -WORKDIR /usr/src/frontend -RUN yarn install diff --git a/frontend/jest.config.js b/frontend/jest.config.js deleted file mode 100644 index 582fe82..0000000 --- a/frontend/jest.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const config = { - verbose: true, - jest: { - setupFilesAfterEnv: ["src/setupTests.js"], - }, -}; - -module.exports = config; diff --git a/frontend/package.json b/frontend/package.json deleted file mode 100644 index 45a643d..0000000 --- a/frontend/package.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "name": "anythink-market-front", - "version": "0.1.0", - "engines": { - "node": "^16" - }, - "private": true, - "devDependencies": { - "@wojtekmaj/enzyme-adapter-react-17": "^0.6.7", - "core-js": "^3.25.1", - "enzyme": "^3.11.0", - "eslint-config-prettier": "^8.3.0", - "eslint-plugin-react": "^7.26.1", - "prettier": "2.4.1", - "react-test-renderer": "^17.0.2", - "redux-mock-store": "^1.5.4" - }, - "dependencies": { - "@babel/core": "^7.18.13", - "@babel/plugin-proposal-private-property-in-object": "^7.18.6", - "@babel/plugin-syntax-flow": "^7.18.6", - "@babel/plugin-transform-react-jsx": "^7.18.10", - "bootstrap": "^4.6.0", - "bootstrap-icons": "^1.7.1", - "history": "^4.6.3", - "jquery": "^3.6.1", - "marked": "^0.3.6", - "postcss": "^8.4.16", - "prop-types": "^15.5.10", - "react": "^17.0.2", - "react-dom": "^17.0.2", - "react-redux": "^5.0.7", - "react-router-dom": "^6.9.0", - "react-scripts": "^5.0.1", - "redux": "^3.6.0", - "redux-devtools-extension": "^2.13.2", - "sass": "^1.45.0", - "superagent": "^3.8.2", - "superagent-promise": "^1.1.0", - "typescript": "^4.8.2" - }, - "scripts": { - "start": "REACT_APP_WILCO_ID=${WILCO_ID:-\"$(cat ../.wilco)\"} react-scripts start", - "build": "react-scripts build", - "test": "react-scripts test --env=jsdom", - "eject": "react-scripts eject", - "format": "yarn prettier --write .", - "lint": "yarn eslint . && yarn prettier --check ." - }, - "eslintConfig": { - "extends": [ - "react-app", - "eslint:recommended" - ], - "rules": { - "no-var": "error" - } - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - }, - "resolutions": { - "autoprefixer": "10.4.5" - } -} diff --git a/frontend/public/50precentoff.png b/frontend/public/50precentoff.png deleted file mode 100644 index 4c835a1..0000000 Binary files a/frontend/public/50precentoff.png and /dev/null differ diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico deleted file mode 100644 index 201ae78..0000000 Binary files a/frontend/public/favicon.ico and /dev/null differ diff --git a/frontend/public/index.html b/frontend/public/index.html deleted file mode 100644 index f0441fc..0000000 --- a/frontend/public/index.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - - Anythink Market - - -
-
- - diff --git a/frontend/public/placeholder.png b/frontend/public/placeholder.png deleted file mode 100644 index bf1d310..0000000 Binary files a/frontend/public/placeholder.png and /dev/null differ diff --git a/frontend/public/style.css b/frontend/public/style.css deleted file mode 100644 index 2bb7fe2..0000000 --- a/frontend/public/style.css +++ /dev/null @@ -1,54 +0,0 @@ -* { - -webkit-font-smoothing: antialiased; -} -body { - font-family: "Inter", sans-serif; - -ms-text-size-adjust: 100%; - -webkit-text-size-adjust: 100%; - text-rendering: optimizeLegibility; - -moz-osx-font-smoothing: grayscale; - -webkit-font-feature-settings: "kern" 1, "liga" 1; - font-feature-settings: "kern" 1, "liga" 1; - scroll-behavior: smooth; -} -.top-announcement { - background-color: #59ca00; - padding: 15px; - font-size: 18px; - color: white; -} -.logo-text { - color: #59ca00 !important; - font-weight: 600; -} -.minegeek-navbar { - background-color: #393939; -} -.sunray { - background-image: url("sunray.jpeg"); - background-size: cover; -} -.text-white { - color: white; -} -.row-eq-height { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; -} -.minegear-btn { - background-color: #59ca00; - border: 0px; - border-radius: 0px; -} -.dramaticPerson { - opacity: 0; - position: fixed; - right: -500px; - bottom: 0px; - height: 590px; - width: 490px; - z-index: 1041; - background-size: cover; -} diff --git a/frontend/public/sunray.jpeg b/frontend/public/sunray.jpeg deleted file mode 100644 index f133496..0000000 Binary files a/frontend/public/sunray.jpeg and /dev/null differ diff --git a/frontend/public/verified_seller.svg b/frontend/public/verified_seller.svg deleted file mode 100644 index 2e1b353..0000000 --- a/frontend/public/verified_seller.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - diff --git a/frontend/readme.md b/frontend/readme.md deleted file mode 100644 index 2f5bc17..0000000 --- a/frontend/readme.md +++ /dev/null @@ -1,26 +0,0 @@ -# Anythink Frontend - -The Anythink Frontend is an SPA written with [React](https://reactjs.org/) and [Redux](https://redux.js.org/) - -## Getting started - -Make sure your server is up and running to serve requests. - -## Pages overview - -- Home page (URL: /#/ ) - - List of tags - - List of items pulled from either Feed, Global, or by Tag - - Pagination for list of items -- Sign in/Sign up pages (URL: /#/login, /#/register ) - - Use JWT (store the token in localStorage) -- Settings page (URL: /#/settings ) -- Editor page to create/edit articles (URL: /#/editor, /#/editor/slug ) -- Item page (URL: /#/item/slug ) - - Delete item button (only shown to item's author) - - Render markdown from server client side - - Comments section at bottom of page - - Delete comment button (only shown to comment's author) -- Profile page (URL: /#/@username, /#/@username/favorites ) - - Show basic user info - - List of items populated from seller's items or user favorite items diff --git a/frontend/src/agent.js b/frontend/src/agent.js deleted file mode 100644 index 972f3e3..0000000 --- a/frontend/src/agent.js +++ /dev/null @@ -1,98 +0,0 @@ -import superagentPromise from "superagent-promise"; -import _superagent from "superagent"; - -const superagent = superagentPromise(_superagent, global.Promise); - -const BACKEND_URL = - process.env.NODE_ENV !== "production" - ? process.env.REACT_APP_BACKEND_URL - : "https://api.anythink.market"; - -const API_ROOT = `${BACKEND_URL}/api`; - -const encode = encodeURIComponent; -const responseBody = (res) => res.body; - -let token = null; -const tokenPlugin = (req) => { - if (token) { - req.set("authorization", `Token ${token}`); - } -}; - -const requests = { - del: (url) => - superagent.del(`${API_ROOT}${url}`).use(tokenPlugin).then(responseBody), - get: (url) => - superagent.get(`${API_ROOT}${url}`).use(tokenPlugin).then(responseBody), - put: (url, body) => - superagent - .put(`${API_ROOT}${url}`, body) - .use(tokenPlugin) - .then(responseBody), - post: (url, body) => - superagent - .post(`${API_ROOT}${url}`, body) - .use(tokenPlugin) - .then(responseBody), -}; - -const Auth = { - current: () => requests.get("/user"), - login: (email, password) => - requests.post("/users/login", { user: { email, password } }), - register: (username, email, password) => - requests.post("/users", { user: { username, email, password } }), - save: (user) => requests.put("/user", { user }), -}; - -const Tags = { - getAll: () => requests.get("/tags"), -}; - -const limit = (count, p) => `limit=${count}&offset=${p ? p * count : 0}`; -const omitSlug = (item) => Object.assign({}, item, { slug: undefined }); -const Items = { - all: (page) => requests.get(`/items?${limit(1000, page)}`), - bySeller: (seller, page) => - requests.get(`/items?seller=${encode(seller)}&${limit(500, page)}`), - byTag: (tag, page) => - requests.get(`/items?tag=${encode(tag)}&${limit(1000, page)}`), - del: (slug) => requests.del(`/items/${slug}`), - favorite: (slug) => requests.post(`/items/${slug}/favorite`), - favoritedBy: (seller, page) => - requests.get(`/items?favorited=${encode(seller)}&${limit(500, page)}`), - feed: () => requests.get("/items/feed?limit=10&offset=0"), - get: (slug) => requests.get(`/items/${slug}`), - unfavorite: (slug) => requests.del(`/items/${slug}/favorite`), - update: (item) => - requests.put(`/items/${item.slug}`, { item: omitSlug(item) }), - create: (item) => requests.post("/items", { item }), -}; - -const Comments = { - create: (slug, comment) => - requests.post(`/items/${slug}/comments`, { comment }), - delete: (slug, commentId) => - requests.del(`/items/${slug}/comments/${commentId}`), - forItem: (slug) => requests.get(`/items/${slug}/comments`), -}; - -const Profile = { - follow: (username) => requests.post(`/profiles/${username}/follow`), - get: (username) => requests.get(`/profiles/${username}`), - unfollow: (username) => requests.del(`/profiles/${username}/follow`), -}; - -const agentObj = { - Items, - Auth, - Comments, - Profile, - Tags, - setToken: (_token) => { - token = _token; - }, -}; - -export default agentObj; diff --git a/frontend/src/components/App.js b/frontend/src/components/App.js deleted file mode 100644 index 8b23812..0000000 --- a/frontend/src/components/App.js +++ /dev/null @@ -1,81 +0,0 @@ -import agent from "../agent"; -import Header from "./Header"; -import React, { useEffect } from "react"; -import { connect } from "react-redux"; -import { APP_LOAD, REDIRECT } from "../constants/actionTypes"; -import Item from "./Item"; -import Editor from "./Editor"; -import Home from "./Home"; -import Login from "./Login"; -import Profile from "./Profile"; -import ProfileFavorites from "./ProfileFavorites"; -import Register from "./Register"; -import Settings from "./Settings"; -import { Route, Routes, useNavigate } from "react-router-dom"; - -const mapStateToProps = (state) => { - return { - appLoaded: state.common.appLoaded, - appName: state.common.appName, - currentUser: state.common.currentUser, - redirectTo: state.common.redirectTo, - }; -}; - -const mapDispatchToProps = (dispatch) => ({ - onLoad: (payload, token) => - dispatch({ type: APP_LOAD, payload, token, skipTracking: true }), - onRedirect: () => dispatch({ type: REDIRECT }), -}); - -const App = (props) => { - const { redirectTo, onRedirect, onLoad } = props; - const navigate = useNavigate(); - - useEffect(() => { - if (redirectTo) { - navigate(redirectTo); - onRedirect(); - } - }, [redirectTo, onRedirect, navigate]); - - useEffect(() => { - const token = window.localStorage.getItem("jwt"); - if (token) { - agent.setToken(token); - } - onLoad(token ? agent.Auth.current() : null, token); - }, [onLoad]); - - if (props.appLoaded) { - return ( -
-
- - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - -
- ); - } - return ( -
-
-
- ); -} - -export default connect(mapStateToProps, mapDispatchToProps)(App); \ No newline at end of file diff --git a/frontend/src/components/Editor.js b/frontend/src/components/Editor.js deleted file mode 100644 index 700a401..0000000 --- a/frontend/src/components/Editor.js +++ /dev/null @@ -1,176 +0,0 @@ -import ListErrors from "./ListErrors"; -import React from "react"; -import agent from "../agent"; -import { connect } from "react-redux"; -import { - ADD_TAG, - EDITOR_PAGE_LOADED, - REMOVE_TAG, - ITEM_SUBMITTED, - EDITOR_PAGE_UNLOADED, - UPDATE_FIELD_EDITOR, -} from "../constants/actionTypes"; -import { withRouterParams } from "./commons"; - -const mapStateToProps = (state) => ({ - ...state.editor, -}); - -const mapDispatchToProps = (dispatch) => ({ - onAddTag: () => dispatch({ type: ADD_TAG }), - onLoad: (payload) => dispatch({ type: EDITOR_PAGE_LOADED, payload }), - onRemoveTag: (tag) => dispatch({ type: REMOVE_TAG, tag }), - onSubmit: (payload) => dispatch({ type: ITEM_SUBMITTED, payload }), - onUnload: (payload) => dispatch({ type: EDITOR_PAGE_UNLOADED }), - onUpdateField: (key, value) => - dispatch({ type: UPDATE_FIELD_EDITOR, key, value }), -}); - -class Editor extends React.Component { - constructor() { - super(); - - const updateFieldEvent = (key) => (ev) => - this.props.onUpdateField(key, ev.target.value); - this.changeTitle = updateFieldEvent("title"); - this.changeDescription = updateFieldEvent("description"); - this.changeImage = updateFieldEvent("image"); - this.changeTagInput = updateFieldEvent("tagInput"); - - this.watchForEnter = (ev) => { - if (ev.keyCode === 13) { - ev.preventDefault(); - this.props.onAddTag(); - } - }; - - this.removeTagHandler = (tag) => () => { - this.props.onRemoveTag(tag); - }; - - this.submitForm = (ev) => { - ev.preventDefault(); - const item = { - title: this.props.title, - description: this.props.description, - image: this.props.image, - tagList: this.props.tagList, - }; - - const slug = { slug: this.props.itemSlug }; - const promise = this.props.itemSlug - ? agent.Items.update(Object.assign(item, slug)) - : agent.Items.create(item); - - this.props.onSubmit(promise); - }; - } - - componentDidUpdate(prevProps) { - if (this.props.params.slug !== prevProps.params.slug) { - if (this.props.params.slug) { - this.props.onUnload(); - return this.props.onLoad(agent.Items.get(this.props.params.slug)); - } - this.props.onLoad(null); - } - } - - componentDidMount() { - if (this.props.params.slug) { - return this.props.onLoad(agent.Items.get(this.props.params.slug)); - } - this.props.onLoad(null); - } - - componentWillUnmount() { - this.props.onUnload(); - } - - render() { - return ( -
-
-
-
- - -
-
-
- -
- -
- -
- -
- -
- -
- - -
- {(this.props.tagList || []).map((tag) => { - return ( - - - {tag} - - ); - })} -
-
- - -
-
-
-
-
-
- ); - } -} - -export default connect(mapStateToProps, mapDispatchToProps)(withRouterParams(Editor)); diff --git a/frontend/src/components/Header.js b/frontend/src/components/Header.js deleted file mode 100644 index be37dfc..0000000 --- a/frontend/src/components/Header.js +++ /dev/null @@ -1,73 +0,0 @@ -import React from "react"; -import { Link } from "react-router-dom"; -import logo from "../imgs/topbar_logo.png"; - -const LoggedOutView = () => { - return ( - - ); -}; - -const LoggedInView = (props) => { - return ( - - ); -}; - -class Header extends React.Component { - render() { - return ( - - ); - } -} - -export default Header; diff --git a/frontend/src/components/Home/Banner.js b/frontend/src/components/Home/Banner.js deleted file mode 100644 index 60eed20..0000000 --- a/frontend/src/components/Home/Banner.js +++ /dev/null @@ -1,19 +0,0 @@ -import React from "react"; -import logo from "../../imgs/logo.png"; - -const Banner = () => { - return ( -
-
- -
- A place to - get - the cool stuff. -
-
-
- ); -}; - -export default Banner; diff --git a/frontend/src/components/Home/MainView.js b/frontend/src/components/Home/MainView.js deleted file mode 100644 index bf92549..0000000 --- a/frontend/src/components/Home/MainView.js +++ /dev/null @@ -1,100 +0,0 @@ -import ItemList from "../ItemList"; -import React from "react"; -import agent from "../../agent"; -import { connect } from "react-redux"; -import { CHANGE_TAB } from "../../constants/actionTypes"; - -const YourFeedTab = (props) => { - if (props.token) { - const clickHandler = (ev) => { - ev.preventDefault(); - props.onTabClick("feed", agent.Items.feed, agent.Items.feed()); - }; - - return ( -
  • - -
  • - ); - } - return null; -}; - -const GlobalFeedTab = (props) => { - const clickHandler = (ev) => { - ev.preventDefault(); - props.onTabClick("all", agent.Items.all, agent.Items.all()); - }; - return ( -
  • - -
  • - ); -}; - -const TagFilterTab = (props) => { - if (!props.tag) { - return null; - } - - return ( -
  • - -
  • - ); -}; - -const mapStateToProps = (state) => ({ - ...state.itemList, - tags: state.home.tags, - token: state.common.token, -}); - -const mapDispatchToProps = (dispatch) => ({ - onTabClick: (tab, pager, payload) => - dispatch({ type: CHANGE_TAB, tab, pager, payload }), -}); - -const MainView = (props) => { - return ( -
    -
    - -
    - - -
    - ); -}; - -export default connect(mapStateToProps, mapDispatchToProps)(MainView); diff --git a/frontend/src/components/Home/Tags.js b/frontend/src/components/Home/Tags.js deleted file mode 100644 index 01cba5d..0000000 --- a/frontend/src/components/Home/Tags.js +++ /dev/null @@ -1,40 +0,0 @@ -import React from "react"; -import agent from "../../agent"; - -const Tags = (props) => { - const tags = props.tags; - if (tags) { - return ( -
    - Popular tags: - - {tags.map((tag) => { - const handleClick = (ev) => { - ev.preventDefault(); - props.onClickTag( - tag, - (page) => agent.Items.byTag(tag, page), - agent.Items.byTag(tag) - ); - }; - - return ( - - ); - })} - -
    - ); - } else { - return
    Loading Tags...
    ; - } -}; - -export default Tags; diff --git a/frontend/src/components/Home/index.js b/frontend/src/components/Home/index.js deleted file mode 100644 index 34e09ae..0000000 --- a/frontend/src/components/Home/index.js +++ /dev/null @@ -1,54 +0,0 @@ -import Banner from "./Banner"; -import MainView from "./MainView"; -import React, { useEffect } from "react"; -import Tags from "./Tags"; -import agent from "../../agent"; -import { connect } from "react-redux"; -import { - HOME_PAGE_LOADED, - HOME_PAGE_UNLOADED, - APPLY_TAG_FILTER, -} from "../../constants/actionTypes"; - -const Promise = global.Promise; - -const mapStateToProps = (state) => ({ - ...state.home, - appName: state.common.appName, - token: state.common.token, -}); - -const mapDispatchToProps = (dispatch) => ({ - onClickTag: (tag, pager, payload) => - dispatch({ type: APPLY_TAG_FILTER, tag, pager, payload }), - onLoad: (tab, pager, payload) => - dispatch({ type: HOME_PAGE_LOADED, tab, pager, payload }), - onUnload: () => dispatch({ type: HOME_PAGE_UNLOADED }), -}); - -const Home = ({onLoad, onUnload, tags, onClickTag}) => { - const tab = "all"; - const itemsPromise = agent.Items.all; - - useEffect(() => { - onLoad( - tab, - itemsPromise, - Promise.all([agent.Tags.getAll(), itemsPromise()]) - ); - return onUnload; - }, [onLoad, onUnload, tab, itemsPromise]); - - return ( -
    - - -
    - - -
    -
    - ); -} - -export default connect(mapStateToProps, mapDispatchToProps)(Home); \ No newline at end of file diff --git a/frontend/src/components/Item/Comment.js b/frontend/src/components/Item/Comment.js deleted file mode 100644 index f852408..0000000 --- a/frontend/src/components/Item/Comment.js +++ /dev/null @@ -1,42 +0,0 @@ -import DeleteButton from "./DeleteButton"; -import { Link } from "react-router-dom"; -import React from "react"; - -const Comment = (props) => { - const comment = props.comment; - const show = - props.currentUser && props.currentUser.username === comment.seller.username; - return ( -
    -
    -
    -

    {comment.body}

    -
    - - {comment.seller.username} - -   - - {comment.seller.username} - - | - - {new Date(comment.createdAt).toDateString()} - - -
    -
    -
    -
    - ); -}; - -export default Comment; diff --git a/frontend/src/components/Item/CommentContainer.js b/frontend/src/components/Item/CommentContainer.js deleted file mode 100644 index 88562b4..0000000 --- a/frontend/src/components/Item/CommentContainer.js +++ /dev/null @@ -1,46 +0,0 @@ -import CommentInput from "./CommentInput"; -import CommentList from "./CommentList"; -import { Link } from "react-router-dom"; -import React from "react"; - -const CommentContainer = (props) => { - if (props.currentUser) { - return ( -
    - -
    -
    - - -
    -
    -
    - ); - } else { - return ( -
    - -

    - - Sign in - -  or  - - sign up - -  to add comments on this item. -

    -
    - ); - } -}; - -export default CommentContainer; diff --git a/frontend/src/components/Item/CommentInput.js b/frontend/src/components/Item/CommentInput.js deleted file mode 100644 index 250a241..0000000 --- a/frontend/src/components/Item/CommentInput.js +++ /dev/null @@ -1,59 +0,0 @@ -import React from "react"; -import agent from "../../agent"; -import { connect } from "react-redux"; -import { ADD_COMMENT } from "../../constants/actionTypes"; - -const mapDispatchToProps = (dispatch) => ({ - onSubmit: (payload) => dispatch({ type: ADD_COMMENT, payload }), -}); - -class CommentInput extends React.Component { - constructor() { - super(); - this.state = { - body: "", - }; - - this.setBody = (ev) => { - this.setState({ body: ev.target.value }); - }; - - this.createComment = async (ev) => { - ev.preventDefault(); - agent.Comments.create(this.props.slug, { - body: this.state.body, - }).then((payload) => { - this.props.onSubmit(payload); - }); - this.setState({ body: "" }); - }; - } - - render() { - return ( -
    -
    - -
    -
    - {this.props.currentUser.username} - -
    -
    - ); - } -} - -export default connect(() => ({}), mapDispatchToProps)(CommentInput); diff --git a/frontend/src/components/Item/CommentList.js b/frontend/src/components/Item/CommentList.js deleted file mode 100644 index b1bcb35..0000000 --- a/frontend/src/components/Item/CommentList.js +++ /dev/null @@ -1,21 +0,0 @@ -import Comment from "./Comment"; -import React from "react"; - -const CommentList = (props) => { - return ( -
    - {props.comments.map((comment) => { - return ( - - ); - })} -
    - ); -}; - -export default CommentList; diff --git a/frontend/src/components/Item/DeleteButton.js b/frontend/src/components/Item/DeleteButton.js deleted file mode 100644 index b78b1b2..0000000 --- a/frontend/src/components/Item/DeleteButton.js +++ /dev/null @@ -1,27 +0,0 @@ -import React from "react"; -import agent from "../../agent"; -import { connect } from "react-redux"; -import { DELETE_COMMENT } from "../../constants/actionTypes"; - -const mapDispatchToProps = (dispatch) => ({ - onClick: (payload, commentId) => - dispatch({ type: DELETE_COMMENT, payload, commentId }), -}); - -const DeleteButton = (props) => { - const del = () => { - const payload = agent.Comments.delete(props.slug, props.commentId); - props.onClick(payload, props.commentId); - }; - - if (props.show) { - return ( - - - - ); - } - return null; -}; - -export default connect(() => ({}), mapDispatchToProps)(DeleteButton); diff --git a/frontend/src/components/Item/ItemActions.js b/frontend/src/components/Item/ItemActions.js deleted file mode 100644 index b6d8615..0000000 --- a/frontend/src/components/Item/ItemActions.js +++ /dev/null @@ -1,36 +0,0 @@ -import { Link } from "react-router-dom"; -import React from "react"; -import agent from "../../agent"; -import { connect } from "react-redux"; -import { DELETE_ITEM } from "../../constants/actionTypes"; - -const mapDispatchToProps = (dispatch) => ({ - onClickDelete: (payload) => dispatch({ type: DELETE_ITEM, payload }), -}); - -const ItemActions = (props) => { - const item = props.item; - const del = () => { - props.onClickDelete(agent.Items.del(item.slug)); - }; - if (props.canModify) { - return ( - - - Edit Item - - - - - ); - } - - return ; -}; - -export default connect(() => ({}), mapDispatchToProps)(ItemActions); diff --git a/frontend/src/components/Item/ItemMeta.js b/frontend/src/components/Item/ItemMeta.js deleted file mode 100644 index c3bdb6e..0000000 --- a/frontend/src/components/Item/ItemMeta.js +++ /dev/null @@ -1,30 +0,0 @@ -import ItemActions from "./ItemActions"; -import { Link } from "react-router-dom"; -import React from "react"; - -const ItemMeta = (props) => { - const item = props.item; - return ( -
    - - {item.seller.username} - - -
    - - {item.seller.username} - - {new Date(item.createdAt).toDateString()} -
    - - -
    - ); -}; - -export default ItemMeta; diff --git a/frontend/src/components/Item/index.js b/frontend/src/components/Item/index.js deleted file mode 100644 index 7d1bf58..0000000 --- a/frontend/src/components/Item/index.js +++ /dev/null @@ -1,85 +0,0 @@ -import ItemMeta from "./ItemMeta"; -import CommentContainer from "./CommentContainer"; -import React, { useEffect } from "react"; -import { connect } from "react-redux"; -import marked from "marked"; -import { - ITEM_PAGE_LOADED, - ITEM_PAGE_UNLOADED, -} from "../../constants/actionTypes"; -import { getItemAndComments } from "./utils/ItemFetcher"; -import { useParams } from "react-router-dom"; - -const mapStateToProps = (state) => ({ - ...state.item, - currentUser: state.common.currentUser, -}); - -const mapDispatchToProps = (dispatch) => ({ - onLoad: (payload) => dispatch({ type: ITEM_PAGE_LOADED, payload }), - onUnload: () => dispatch({ type: ITEM_PAGE_UNLOADED }), -}); - -const Item = (props) => { - const params = useParams(); - const {onLoad, onUnload} = props; - useEffect(() => { - getItemAndComments( - params.id - ).then(([item, comments]) => { - onLoad([item, comments]); - }); - return onUnload; - }, [onLoad, onUnload, params]); - - if (!props.item) { - return null; - } - - const markup = { - __html: marked(props.item.description, { sanitize: true }), - }; - const canModify = - props.currentUser && - props.currentUser.username === props.item.seller.username; - return ( -
    -
    -
    -
    - {props.item.title} -
    - -
    -

    {props.item.title}

    - -
    - {props.item.tagList.map((tag) => { - return ( - - {tag} - - ); - })} -
    -
    - -
    - -
    -
    -
    - ); -} - -export default connect(mapStateToProps, mapDispatchToProps)(Item); diff --git a/frontend/src/components/Item/utils/ItemFetcher.js b/frontend/src/components/Item/utils/ItemFetcher.js deleted file mode 100644 index 6ebd6c8..0000000 --- a/frontend/src/components/Item/utils/ItemFetcher.js +++ /dev/null @@ -1,8 +0,0 @@ -import agent from "../../../agent"; - -export async function getItemAndComments(id) { - const item = await agent.Items.get(id); - const comments = await agent.Comments.forItem(id); - - return [item, comments]; -} diff --git a/frontend/src/components/ItemList.js b/frontend/src/components/ItemList.js deleted file mode 100644 index 268714e..0000000 --- a/frontend/src/components/ItemList.js +++ /dev/null @@ -1,35 +0,0 @@ -import ItemPreview from "./ItemPreview"; -import ListPagination from "./ListPagination"; -import React from "react"; - -const ItemList = (props) => { - if (!props.items) { - return
    Loading...
    ; - } - - if (props.items.length === 0) { - return
    No items are here... yet.
    ; - } - - return ( -
    -
    - {props.items.map((item) => { - return ( -
    - -
    - ); - })} -
    - - -
    - ); -}; - -export default ItemList; diff --git a/frontend/src/components/ItemPreview.js b/frontend/src/components/ItemPreview.js deleted file mode 100644 index ce89b00..0000000 --- a/frontend/src/components/ItemPreview.js +++ /dev/null @@ -1,66 +0,0 @@ -import React from "react"; -import { Link } from "react-router-dom"; -import agent from "../agent"; -import { connect } from "react-redux"; -import { ITEM_FAVORITED, ITEM_UNFAVORITED } from "../constants/actionTypes"; - -const mapDispatchToProps = (dispatch) => ({ - favorite: (slug) => - dispatch({ - type: ITEM_FAVORITED, - payload: agent.Items.favorite(slug), - }), - unfavorite: (slug) => - dispatch({ - type: ITEM_UNFAVORITED, - payload: agent.Items.unfavorite(slug), - }), -}); - -const ItemPreview = (props) => { - const item = props.item; - - const handleClick = (ev) => { - ev.preventDefault(); - if (item.favorited) { - props.unfavorite(item.slug); - } else { - props.favorite(item.slug); - } - }; - - return ( -
    - item -
    - -

    {item.title}

    -

    {item.description}

    - -
    - - {item.seller.username} - - -
    -
    -
    - ); -}; - -export default connect(() => ({}), mapDispatchToProps)(ItemPreview); diff --git a/frontend/src/components/ListErrors.js b/frontend/src/components/ListErrors.js deleted file mode 100644 index 33c97e8..0000000 --- a/frontend/src/components/ListErrors.js +++ /dev/null @@ -1,24 +0,0 @@ -import React from "react"; - -class ListErrors extends React.Component { - render() { - const errors = this.props.errors; - if (errors) { - return ( - - ); - } else { - return null; - } - } -} - -export default ListErrors; diff --git a/frontend/src/components/ListPagination.js b/frontend/src/components/ListPagination.js deleted file mode 100644 index fcefbcc..0000000 --- a/frontend/src/components/ListPagination.js +++ /dev/null @@ -1,52 +0,0 @@ -import React from "react"; -import agent from "../agent"; -import { connect } from "react-redux"; -import { SET_PAGE } from "../constants/actionTypes"; - -const mapDispatchToProps = (dispatch) => ({ - onSetPage: (page, payload) => dispatch({ type: SET_PAGE, page, payload }), -}); - -const ListPagination = (props) => { - if (props.itemsCount <= 10) { - return null; - } - - const range = []; - for (let i = 0; i < Math.ceil(props.itemsCount / 10); ++i) { - range.push(i); - } - - const setPage = (page) => { - if (props.pager) { - props.onSetPage(page, props.pager(page)); - } else { - props.onSetPage(page, agent.Items.all(page)); - } - }; - - return ( - - ); -}; - -export default connect(() => ({}), mapDispatchToProps)(ListPagination); diff --git a/frontend/src/components/Login.js b/frontend/src/components/Login.js deleted file mode 100644 index af4f12d..0000000 --- a/frontend/src/components/Login.js +++ /dev/null @@ -1,121 +0,0 @@ -import { Link } from "react-router-dom"; -import ListErrors from "./ListErrors"; -import React from "react"; -import agent from "../agent"; -import { connect } from "react-redux"; -import { - UPDATE_FIELD_AUTH, - LOGIN, - LOGIN_PAGE_UNLOADED, -} from "../constants/actionTypes"; - -const mapStateToProps = (state) => ({ ...state.auth }); - -const mapDispatchToProps = (dispatch) => ({ - onChangeEmail: (value) => - dispatch({ type: UPDATE_FIELD_AUTH, key: "email", value }), - onChangePassword: (value) => - dispatch({ type: UPDATE_FIELD_AUTH, key: "password", value }), - onSubmit: (email, password) => - dispatch({ type: LOGIN, payload: agent.Auth.login(email, password) }), - onUnload: () => dispatch({ type: LOGIN_PAGE_UNLOADED }), -}); - -class Login extends React.Component { - constructor() { - super(); - this.changeEmail = (ev) => this.props.onChangeEmail(ev.target.value); - this.changePassword = (ev) => this.props.onChangePassword(ev.target.value); - this.submitForm = (email, password) => (ev) => { - ev.preventDefault(); - this.props.onSubmit(email, password); - }; - } - - componentWillUnmount() { - this.props.onUnload(); - } - - render() { - const email = this.props.email; - const password = this.props.password; - return ( -
    -
    -
    -
    -

    Sign In

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

    - - Need an account? - -

    -
    -
    -
    -
    - ); - } -} - -export default connect(mapStateToProps, mapDispatchToProps)(Login); diff --git a/frontend/src/components/Profile.js b/frontend/src/components/Profile.js deleted file mode 100644 index b2e0f0b..0000000 --- a/frontend/src/components/Profile.js +++ /dev/null @@ -1,172 +0,0 @@ -import ItemList from "./ItemList"; -import React from "react"; -import { Link } from "react-router-dom"; -import agent from "../agent"; -import { connect } from "react-redux"; -import { - FOLLOW_USER, - UNFOLLOW_USER, - PROFILE_PAGE_LOADED, - PROFILE_PAGE_UNLOADED, -} from "../constants/actionTypes"; -import { withRouterParams } from "./commons"; - -const EditProfileSettings = (props) => { - if (props.isUser) { - return ( - - Edit Profile Settings - - ); - } - return null; -}; - -const FollowUserButton = (props) => { - if (props.isUser) { - return null; - } - - let classes = "btn btn-sm action-btn"; - if (props.user.following) { - classes += " btn-secondary"; - } else { - classes += " btn-outline-secondary"; - } - - const handleClick = (ev) => { - ev.preventDefault(); - if (props.user.following) { - props.unfollow(props.user.username); - } else { - props.follow(props.user.username); - } - }; - - return ( - - ); -}; - -const mapStateToProps = (state) => ({ - ...state.itemList, - currentUser: state.common.currentUser, - profile: state.profile, -}); - -const mapDispatchToProps = (dispatch) => ({ - onFollow: (username) => - dispatch({ - type: FOLLOW_USER, - payload: agent.Profile.follow(username), - }), - onLoad: (payload) => dispatch({ type: PROFILE_PAGE_LOADED, payload }), - onUnfollow: (username) => - dispatch({ - type: UNFOLLOW_USER, - payload: agent.Profile.unfollow(username), - }), - onUnload: () => dispatch({ type: PROFILE_PAGE_UNLOADED }), -}); - -class Profile extends React.Component { - componentDidMount() { - const username = this.props.params.username?.substring(1); - this.props.onLoad( - Promise.all([ - agent.Profile.get(username), - agent.Items.bySeller(username), - ]) - ); - } - - componentWillUnmount() { - this.props.onUnload(); - } - - renderTabs() { - return ( - - ); - } - - render() { - const profile = this.props.profile; - if (!profile) { - return null; - } - - const isUser = - this.props.currentUser && - this.props.profile.username === this.props.currentUser.username; - - return ( -
    -
    -
    -
    - {profile.username} -

    {profile.username}

    -

    {profile.bio}

    - - - -
    -
    -
    - -
    -
    -
    -
    {this.renderTabs()}
    - - -
    -
    -
    -
    - ); - } -} - -export default connect(mapStateToProps, mapDispatchToProps)(withRouterParams(Profile)); -export { Profile, mapStateToProps }; diff --git a/frontend/src/components/ProfileFavorites.js b/frontend/src/components/ProfileFavorites.js deleted file mode 100644 index 5fd3fba..0000000 --- a/frontend/src/components/ProfileFavorites.js +++ /dev/null @@ -1,56 +0,0 @@ -import { Profile, mapStateToProps } from "./Profile"; -import React from "react"; -import { Link } from "react-router-dom"; -import agent from "../agent"; -import { connect } from "react-redux"; -import { - PROFILE_PAGE_LOADED, - PROFILE_PAGE_UNLOADED, -} from "../constants/actionTypes"; -import { withRouterParams } from "./commons"; - -const mapDispatchToProps = (dispatch) => ({ - onLoad: (pager, payload) => - dispatch({ type: PROFILE_PAGE_LOADED, pager, payload }), - onUnload: () => dispatch({ type: PROFILE_PAGE_UNLOADED }), -}); - -class ProfileFavorites extends Profile { - componentDidMount() { - const username = this.props.params.username?.substring(1); - this.props.onLoad( - (page) => agent.Items.favoritedBy(username, page), - Promise.all([ - agent.Profile.get(username), - agent.Items.favoritedBy(username), - ]) - ); - } - - componentWillUnmount() { - this.props.onUnload(); - } - - renderTabs() { - return ( - - ); - } -} - -export default connect(mapStateToProps, mapDispatchToProps)(withRouterParams(ProfileFavorites)); diff --git a/frontend/src/components/Register.js b/frontend/src/components/Register.js deleted file mode 100644 index 195a25a..0000000 --- a/frontend/src/components/Register.js +++ /dev/null @@ -1,148 +0,0 @@ -import { Link } from "react-router-dom"; -import ListErrors from "./ListErrors"; -import React from "react"; -import agent from "../agent"; -import { connect } from "react-redux"; -import { - UPDATE_FIELD_AUTH, - REGISTER, - REGISTER_PAGE_UNLOADED, -} from "../constants/actionTypes"; - -const mapStateToProps = (state) => ({ ...state.auth }); - -const mapDispatchToProps = (dispatch) => ({ - onChangeEmail: (value) => - dispatch({ type: UPDATE_FIELD_AUTH, key: "email", value }), - onChangePassword: (value) => - dispatch({ type: UPDATE_FIELD_AUTH, key: "password", value }), - onChangeUsername: (value) => - dispatch({ type: UPDATE_FIELD_AUTH, key: "username", value }), - onSubmit: (username, email, password) => { - const payload = agent.Auth.register(username, email, password); - dispatch({ type: REGISTER, payload }); - }, - onUnload: () => dispatch({ type: REGISTER_PAGE_UNLOADED }), -}); - -class Register extends React.Component { - constructor() { - super(); - this.changeEmail = (ev) => this.props.onChangeEmail(ev.target.value); - this.changePassword = (ev) => this.props.onChangePassword(ev.target.value); - this.changeUsername = (ev) => this.props.onChangeUsername(ev.target.value); - this.submitForm = (username, email, password) => (ev) => { - ev.preventDefault(); - this.props.onSubmit(username, email, password); - }; - } - - componentWillUnmount() { - this.props.onUnload(); - } - - render() { - const email = this.props.email; - const password = this.props.password; - const username = this.props.username; - - return ( -
    -
    -
    -
    -

    Sign Up

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

    - - Have an account? - -

    -
    -
    -
    -
    - ); - } -} - -export default connect(mapStateToProps, mapDispatchToProps)(Register); diff --git a/frontend/src/components/Settings.js b/frontend/src/components/Settings.js deleted file mode 100644 index e4791bc..0000000 --- a/frontend/src/components/Settings.js +++ /dev/null @@ -1,142 +0,0 @@ -import ListErrors from "./ListErrors"; -import React, { useCallback, useEffect, useState } from "react"; -import agent from "../agent"; -import { connect } from "react-redux"; -import { - SETTINGS_SAVED, - SETTINGS_PAGE_UNLOADED, - LOGOUT, -} from "../constants/actionTypes"; - -const SettingsForm = ({ currentUser, onSubmitForm }) => { - const [user, setUser] = useState({}); - - useEffect(() => { - if (currentUser) { - setUser(currentUser); - } - }, [currentUser]); - - const updateState = useCallback((field) => (ev) => { - const newState = Object.assign({}, user, { [field]: ev.target.value }); - setUser(newState); - }, [user]); - - const submitForm = useCallback((ev) => { - ev.preventDefault(); - const userToSubmit = { ...user }; - if (!userToSubmit.password) { - delete userToSubmit.password; - } - onSubmitForm(userToSubmit); - }, [user, onSubmitForm]); - - return ( -
    -
    -
    - -
    - -
    - -
    - -
    - -
    - -
    - -
    - -
    - -
    - - -
    -
    - ); -} - -const mapStateToProps = (state) => ({ - ...state.settings, - currentUser: state.common.currentUser, -}); - -const mapDispatchToProps = (dispatch) => ({ - onClickLogout: () => dispatch({ type: LOGOUT }), - onSubmitForm: (user) => - dispatch({ type: SETTINGS_SAVED, payload: agent.Auth.save(user) }), - onUnload: () => dispatch({ type: SETTINGS_PAGE_UNLOADED }), -}); - -class Settings extends React.Component { - render() { - return ( -
    -
    -
    -
    -

    Your Settings

    - - - - - -
    - - -
    -
    -
    -
    - ); - } -} - -export default connect(mapStateToProps, mapDispatchToProps)(Settings); diff --git a/frontend/src/components/commons.js b/frontend/src/components/commons.js deleted file mode 100644 index 8f1fd1c..0000000 --- a/frontend/src/components/commons.js +++ /dev/null @@ -1,5 +0,0 @@ -import { useParams } from "react-router-dom"; - -export function withRouterParams(Component) { - return props => ; -} diff --git a/frontend/src/constants/actionTypes.js b/frontend/src/constants/actionTypes.js deleted file mode 100644 index bb5380b..0000000 --- a/frontend/src/constants/actionTypes.js +++ /dev/null @@ -1,37 +0,0 @@ -export const APP_LOAD = "APP_LOAD"; -export const REDIRECT = "REDIRECT"; -export const ITEM_SUBMITTED = "ITEM_SUBMITTED"; -export const SETTINGS_SAVED = "SETTINGS_SAVED"; -export const DELETE_ITEM = "DELETE_ITEM"; -export const SETTINGS_PAGE_UNLOADED = "SETTINGS_PAGE_UNLOADED"; -export const HOME_PAGE_LOADED = "HOME_PAGE_LOADED"; -export const HOME_PAGE_UNLOADED = "HOME_PAGE_UNLOADED"; -export const ITEM_PAGE_LOADED = "ITEM_PAGE_LOADED"; -export const ITEM_PAGE_UNLOADED = "ITEM_PAGE_UNLOADED"; -export const ADD_COMMENT = "ADD_COMMENT"; -export const DELETE_COMMENT = "DELETE_COMMENT"; -export const ITEM_FAVORITED = "ITEM_FAVORITED"; -export const ITEM_UNFAVORITED = "ITEM_UNFAVORITED"; -export const SET_PAGE = "SET_PAGE"; -export const APPLY_TAG_FILTER = "APPLY_TAG_FILTER"; -export const CHANGE_TAB = "CHANGE_TAB"; -export const PROFILE_PAGE_LOADED = "PROFILE_PAGE_LOADED"; -export const PROFILE_PAGE_UNLOADED = "PROFILE_PAGE_UNLOADED"; -export const LOGIN = "LOGIN"; -export const LOGOUT = "LOGOUT"; -export const REGISTER = "REGISTER"; -export const LOGIN_PAGE_UNLOADED = "LOGIN_PAGE_UNLOADED"; -export const REGISTER_PAGE_UNLOADED = "REGISTER_PAGE_UNLOADED"; -export const ASYNC_START = "ASYNC_START"; -export const ASYNC_END = "ASYNC_END"; -export const EDITOR_PAGE_LOADED = "EDITOR_PAGE_LOADED"; -export const EDITOR_PAGE_UNLOADED = "EDITOR_PAGE_UNLOADED"; -export const ADD_TAG = "ADD_TAG"; -export const REMOVE_TAG = "REMOVE_TAG"; -export const UPDATE_FIELD_AUTH = "UPDATE_FIELD_AUTH"; -export const UPDATE_FIELD_EDITOR = "UPDATE_FIELD_EDITOR"; -export const FOLLOW_USER = "FOLLOW_USER"; -export const UNFOLLOW_USER = "UNFOLLOW_USER"; -export const PROFILE_FAVORITES_PAGE_UNLOADED = - "PROFILE_FAVORITES_PAGE_UNLOADED"; -export const PROFILE_FAVORITES_PAGE_LOADED = "PROFILE_FAVORITES_PAGE_LOADED"; diff --git a/frontend/src/custom.scss b/frontend/src/custom.scss deleted file mode 100644 index 0b4d757..0000000 --- a/frontend/src/custom.scss +++ /dev/null @@ -1,61 +0,0 @@ -@import url("https://fonts.googleapis.com/css?family=Poppins:300,400,500,600,700,800"); - -// Override default variables before the import -$primary: #2b1456; -$secondary: #ff2b98; - -$body-color: white; //this is the text color -$body-bg: $primary; - -$dark: #170539; -$light: #af93f2; - -$input-border-color: #d0d0d0; - -$font-family-base: "Poppins", sans-serif !important; - -$theme-colors: ( - "light-gray": #f2f2f2, -); - -// Import Bootstrap and its default variables -@import "~bootstrap/scss/bootstrap.scss"; -@import "~bootstrap-icons/font/bootstrap-icons.css"; - -body { - background-image: url("./imgs/background.png"); - background-position: top; - background-repeat: no-repeat; -} -.page { - margin-top: 2 * $spacer; - margin-bottom: 2 * $spacer; -} - -.user-pic { - height: 40px; - width: 40px; -} - -.user-img { - width: 100px; - height: 100px; - border-radius: 100px; -} - -.item-img { - height: 150px; - object-fit: cover; -} - -.crop-text-3 { - -webkit-line-clamp: 3; - overflow: hidden; - text-overflow: ellipsis; - display: -webkit-box; - -webkit-box-orient: vertical; -} - -.user-info { - min-width: 800px; -} diff --git a/frontend/src/imgs/background.png b/frontend/src/imgs/background.png deleted file mode 100644 index 6c2e0f9..0000000 Binary files a/frontend/src/imgs/background.png and /dev/null differ diff --git a/frontend/src/imgs/logo.png b/frontend/src/imgs/logo.png deleted file mode 100644 index 89757c2..0000000 Binary files a/frontend/src/imgs/logo.png and /dev/null differ diff --git a/frontend/src/imgs/topbar_logo.png b/frontend/src/imgs/topbar_logo.png deleted file mode 100644 index e7fefd3..0000000 Binary files a/frontend/src/imgs/topbar_logo.png and /dev/null differ diff --git a/frontend/src/index.js b/frontend/src/index.js deleted file mode 100644 index a6ecd9b..0000000 --- a/frontend/src/index.js +++ /dev/null @@ -1,18 +0,0 @@ -import "./custom.scss"; -import ReactDOM from "react-dom"; -import { Provider } from "react-redux"; -import React from "react"; -import { store } from "./store"; - -import App from "./components/App"; -import { BrowserRouter } from "react-router-dom"; - -ReactDOM.render( - - - - - , - - document.getElementById("root") -); diff --git a/frontend/src/middleware.js b/frontend/src/middleware.js deleted file mode 100644 index 4f82efb..0000000 --- a/frontend/src/middleware.js +++ /dev/null @@ -1,65 +0,0 @@ -import agent from "./agent"; -import { - ASYNC_START, - ASYNC_END, - LOGIN, - LOGOUT, - REGISTER, -} from "./constants/actionTypes"; - -const promiseMiddleware = (store) => (next) => (action) => { - if (isPromise(action.payload)) { - store.dispatch({ type: ASYNC_START, subtype: action.type }); - - const currentView = store.getState().viewChangeCounter; - const skipTracking = action.skipTracking; - - action.payload.then( - (res) => { - const currentState = store.getState(); - if (!skipTracking && currentState.viewChangeCounter !== currentView) { - return; - } - action.payload = res; - store.dispatch({ type: ASYNC_END, promise: action.payload }); - store.dispatch(action); - }, - (error) => { - const currentState = store.getState(); - if (!skipTracking && currentState.viewChangeCounter !== currentView) { - return; - } - action.error = true; - action.payload = error.response.body; - if (!action.skipTracking) { - store.dispatch({ type: ASYNC_END, promise: action.payload }); - } - store.dispatch(action); - } - ); - - return; - } - - next(action); -}; - -const localStorageMiddleware = (store) => (next) => (action) => { - if (action.type === REGISTER || action.type === LOGIN) { - if (!action.error) { - window.localStorage.setItem("jwt", action.payload.user.token); - agent.setToken(action.payload.user.token); - } - } else if (action.type === LOGOUT) { - window.localStorage.setItem("jwt", ""); - agent.setToken(null); - } - - next(action); -}; - -function isPromise(v) { - return v && typeof v.then === "function"; -} - -export { promiseMiddleware, localStorageMiddleware }; diff --git a/frontend/src/reducer.js b/frontend/src/reducer.js deleted file mode 100644 index 65173ca..0000000 --- a/frontend/src/reducer.js +++ /dev/null @@ -1,20 +0,0 @@ -import item from "./reducers/item"; -import itemList from "./reducers/itemList"; -import auth from "./reducers/auth"; -import { combineReducers } from "redux"; -import common from "./reducers/common"; -import editor from "./reducers/editor"; -import home from "./reducers/home"; -import profile from "./reducers/profile"; -import settings from "./reducers/settings"; - -export default combineReducers({ - item, - itemList, - auth, - common, - editor, - home, - profile, - settings, -}); diff --git a/frontend/src/reducers/auth.js b/frontend/src/reducers/auth.js deleted file mode 100644 index 6128b11..0000000 --- a/frontend/src/reducers/auth.js +++ /dev/null @@ -1,36 +0,0 @@ -import { - LOGIN, - REGISTER, - LOGIN_PAGE_UNLOADED, - REGISTER_PAGE_UNLOADED, - ASYNC_START, - UPDATE_FIELD_AUTH, -} from "../constants/actionTypes"; - -const reducer = (state = {}, action) => { - switch (action.type) { - case LOGIN: - case REGISTER: - return { - ...state, - inProgress: false, - errors: action.error ? action.payload.errors : null, - }; - case LOGIN_PAGE_UNLOADED: - case REGISTER_PAGE_UNLOADED: - return {}; - case ASYNC_START: - if (action.subtype === LOGIN || action.subtype === REGISTER) { - return { ...state, inProgress: true }; - } - break; - case UPDATE_FIELD_AUTH: - return { ...state, [action.key]: action.value }; - default: - return state; - } - - return state; -}; - -export default reducer; diff --git a/frontend/src/reducers/common.js b/frontend/src/reducers/common.js deleted file mode 100644 index 3ef54b4..0000000 --- a/frontend/src/reducers/common.js +++ /dev/null @@ -1,79 +0,0 @@ -import { - APP_LOAD, - REDIRECT, - LOGOUT, - ITEM_SUBMITTED, - SETTINGS_SAVED, - LOGIN, - REGISTER, - DELETE_ITEM, - ITEM_PAGE_UNLOADED, - EDITOR_PAGE_UNLOADED, - HOME_PAGE_UNLOADED, - PROFILE_PAGE_UNLOADED, - PROFILE_FAVORITES_PAGE_UNLOADED, - SETTINGS_PAGE_UNLOADED, - LOGIN_PAGE_UNLOADED, - REGISTER_PAGE_UNLOADED, -} from "../constants/actionTypes"; - -const defaultState = { - appName: "Anythink Market", - token: null, - viewChangeCounter: 0, -}; - -const reducer = (state = defaultState, action) => { - switch (action.type) { - case APP_LOAD: - return { - ...state, - token: action.token || null, - appLoaded: true, - currentUser: action.payload ? action.payload.user : null, - }; - case REDIRECT: - return { ...state, redirectTo: null }; - case LOGOUT: - return { ...state, redirectTo: "/", token: null, currentUser: null }; - case ITEM_SUBMITTED: { - const redirectUrl = `/item/${action.payload.item.slug}`; - return { ...state, redirectTo: redirectUrl }; - } - case SETTINGS_SAVED: - return { - ...state, - redirectTo: action.error ? null : "/", - currentUser: action.error ? null : action.payload.user, - }; - case LOGIN: - return { - ...state, - redirectTo: action.error ? null : "/", - token: action.error ? null : action.payload.user.token, - currentUser: action.error ? null : action.payload.user, - }; - case REGISTER: - return { - ...state, - redirectTo: action.error ? null : `/@${action.payload.user.username}`, - token: action.error ? null : action.payload.user.token, - currentUser: action.error ? null : action.payload.user, - }; - case DELETE_ITEM: - return { ...state, redirectTo: "/" }; - case ITEM_PAGE_UNLOADED: - case EDITOR_PAGE_UNLOADED: - case HOME_PAGE_UNLOADED: - case PROFILE_PAGE_UNLOADED: - case PROFILE_FAVORITES_PAGE_UNLOADED: - case SETTINGS_PAGE_UNLOADED: - case LOGIN_PAGE_UNLOADED: - case REGISTER_PAGE_UNLOADED: - return { ...state, viewChangeCounter: state.viewChangeCounter + 1 }; - default: - return state; - } -}; - -export default reducer; diff --git a/frontend/src/reducers/editor.js b/frontend/src/reducers/editor.js deleted file mode 100644 index 4320e70..0000000 --- a/frontend/src/reducers/editor.js +++ /dev/null @@ -1,56 +0,0 @@ -import { - EDITOR_PAGE_LOADED, - EDITOR_PAGE_UNLOADED, - ITEM_SUBMITTED, - ASYNC_START, - ADD_TAG, - REMOVE_TAG, - UPDATE_FIELD_EDITOR, -} from "../constants/actionTypes"; - -const reducer = (state = {}, action) => { - switch (action.type) { - case EDITOR_PAGE_LOADED: - return { - ...state, - itemSlug: action.payload ? action.payload.item.slug : "", - title: action.payload ? action.payload.item.title : "", - description: action.payload ? action.payload.item.description : "", - image: action.payload ? action.payload.item.image : "", - tagInput: "", - tagList: action.payload ? action.payload.item.tagList : [], - }; - case EDITOR_PAGE_UNLOADED: - return {}; - case ITEM_SUBMITTED: - return { - ...state, - inProgress: null, - errors: action.error ? action.payload.errors : null, - }; - case ASYNC_START: - if (action.subtype === ITEM_SUBMITTED) { - return { ...state, inProgress: true }; - } - break; - case ADD_TAG: - return { - ...state, - tagList: state.tagList.concat([state.tagInput]), - tagInput: "", - }; - case REMOVE_TAG: - return { - ...state, - tagList: state.tagList.filter((tag) => tag !== action.tag), - }; - case UPDATE_FIELD_EDITOR: - return { ...state, [action.key]: action.value }; - default: - return state; - } - - return state; -}; - -export default reducer; diff --git a/frontend/src/reducers/home.js b/frontend/src/reducers/home.js deleted file mode 100644 index b9bc097..0000000 --- a/frontend/src/reducers/home.js +++ /dev/null @@ -1,17 +0,0 @@ -import { HOME_PAGE_LOADED, HOME_PAGE_UNLOADED } from "../constants/actionTypes"; - -const reducer = (state = {}, action) => { - switch (action.type) { - case HOME_PAGE_LOADED: - return { - ...state, - tags: action.payload[0].tags, - }; - case HOME_PAGE_UNLOADED: - return {}; - default: - return state; - } -}; - -export default reducer; diff --git a/frontend/src/reducers/item.js b/frontend/src/reducers/item.js deleted file mode 100644 index 918201c..0000000 --- a/frontend/src/reducers/item.js +++ /dev/null @@ -1,38 +0,0 @@ -import { - ITEM_PAGE_LOADED, - ITEM_PAGE_UNLOADED, - ADD_COMMENT, - DELETE_COMMENT, -} from "../constants/actionTypes"; - -const reducer = (state = {}, action) => { - switch (action.type) { - case ITEM_PAGE_LOADED: - return { - ...state, - item: action.payload[0].item, - comments: action.payload[1].comments, - }; - case ITEM_PAGE_UNLOADED: - return {}; - case ADD_COMMENT: - return { - ...state, - commentErrors: action.error ? action.payload.errors : null, - comments: action.error - ? null - : (state.comments || []).concat([action.payload.comment]), - }; - case DELETE_COMMENT: { - const commentId = action.commentId; - return { - ...state, - comments: state.comments.filter((comment) => comment.id !== commentId), - }; - } - default: - return state; - } -}; - -export default reducer; diff --git a/frontend/src/reducers/itemList.js b/frontend/src/reducers/itemList.js deleted file mode 100644 index 016a996..0000000 --- a/frontend/src/reducers/itemList.js +++ /dev/null @@ -1,88 +0,0 @@ -import { - ITEM_FAVORITED, - ITEM_UNFAVORITED, - SET_PAGE, - APPLY_TAG_FILTER, - HOME_PAGE_LOADED, - HOME_PAGE_UNLOADED, - CHANGE_TAB, - PROFILE_PAGE_LOADED, - PROFILE_PAGE_UNLOADED, - PROFILE_FAVORITES_PAGE_LOADED, - PROFILE_FAVORITES_PAGE_UNLOADED, -} from "../constants/actionTypes"; - -const reducer = (state = {}, action) => { - switch (action.type) { - case ITEM_FAVORITED: - case ITEM_UNFAVORITED: - return { - ...state, - items: state.items.map((item) => { - if (item.slug === action.payload.item.slug) { - return { - ...item, - favorited: action.payload.item.favorited, - favoritesCount: action.payload.item.favoritesCount, - }; - } - return item; - }), - }; - case SET_PAGE: - return { - ...state, - items: action.payload.items, - itemsCount: action.payload.itemsCount, - currentPage: action.page, - }; - case APPLY_TAG_FILTER: - return { - ...state, - pager: action.pager, - items: action.payload.items, - itemsCount: action.payload.itemsCount, - tab: null, - tag: action.tag, - currentPage: 0, - }; - case HOME_PAGE_LOADED: - return { - ...state, - pager: action.pager, - tags: action.payload[0].tags, - items: action.payload[1].items, - itemsCount: action.payload[1].itemsCount, - currentPage: 0, - tab: action.tab, - }; - case HOME_PAGE_UNLOADED: - return {}; - case CHANGE_TAB: - return { - ...state, - pager: action.pager, - items: action.payload.items, - itemsCount: action.payload.itemsCount, - tab: action.tab, - currentPage: 0, - tag: null, - }; - case PROFILE_PAGE_LOADED: - case PROFILE_FAVORITES_PAGE_LOADED: - return { - ...state, - pager: action.pager, - items: action.payload?.[1]?.items, - itemsCount: action.payload?.[1]?.itemsCount, - currentPage: 0, - }; - case PROFILE_PAGE_UNLOADED: - case PROFILE_FAVORITES_PAGE_UNLOADED: - return {}; - default: - return state; - } -}; - -export default reducer; diff --git a/frontend/src/reducers/profile.js b/frontend/src/reducers/profile.js deleted file mode 100644 index 5d4fe85..0000000 --- a/frontend/src/reducers/profile.js +++ /dev/null @@ -1,26 +0,0 @@ -import { - PROFILE_PAGE_LOADED, - PROFILE_PAGE_UNLOADED, - FOLLOW_USER, - UNFOLLOW_USER, -} from "../constants/actionTypes"; - -const reducer = (state = {}, action) => { - switch (action.type) { - case PROFILE_PAGE_LOADED: - return { - ...action.payload?.[0]?.profile, - }; - case PROFILE_PAGE_UNLOADED: - return {}; - case FOLLOW_USER: - case UNFOLLOW_USER: - return { - ...action.payload.profile, - }; - default: - return state; - } -}; - -export default reducer; diff --git a/frontend/src/reducers/settings.js b/frontend/src/reducers/settings.js deleted file mode 100644 index 2cf4da0..0000000 --- a/frontend/src/reducers/settings.js +++ /dev/null @@ -1,27 +0,0 @@ -import { - SETTINGS_SAVED, - SETTINGS_PAGE_UNLOADED, - ASYNC_START, -} from "../constants/actionTypes"; - -const reducer = (state = {}, action) => { - switch (action.type) { - case SETTINGS_SAVED: - return { - ...state, - inProgress: false, - errors: action.error ? action.payload.errors : null, - }; - case SETTINGS_PAGE_UNLOADED: - return {}; - case ASYNC_START: - return { - ...state, - inProgress: true, - }; - default: - return state; - } -}; - -export default reducer; diff --git a/frontend/src/setupTests.js b/frontend/src/setupTests.js deleted file mode 100644 index 0772595..0000000 --- a/frontend/src/setupTests.js +++ /dev/null @@ -1,5 +0,0 @@ -import "core-js"; -import { configure } from "enzyme"; -import Adapter from "@wojtekmaj/enzyme-adapter-react-17"; - -configure({ adapter: new Adapter() }); diff --git a/frontend/src/store.js b/frontend/src/store.js deleted file mode 100644 index 5ac25dc..0000000 --- a/frontend/src/store.js +++ /dev/null @@ -1,25 +0,0 @@ -import { applyMiddleware, createStore } from "redux"; -import { composeWithDevTools } from "redux-devtools-extension/developmentOnly"; -import { promiseMiddleware, localStorageMiddleware } from "./middleware"; -import reducer from "./reducer"; - -import { createBrowserHistory } from "history"; - -export const history = createBrowserHistory(); - -const getMiddleware = () => { - if (process.env.NODE_ENV === "production") { - return applyMiddleware( - promiseMiddleware, - localStorageMiddleware - ); - } else { - // Enable additional logging in non-production environments. - return applyMiddleware( - promiseMiddleware, - localStorageMiddleware, - ); - } -}; - -export const store = createStore(reducer, composeWithDevTools(getMiddleware())); diff --git a/frontend/src/tests/components/Header.test.js b/frontend/src/tests/components/Header.test.js deleted file mode 100644 index 592b742..0000000 --- a/frontend/src/tests/components/Header.test.js +++ /dev/null @@ -1,54 +0,0 @@ -import { create } from "react-test-renderer"; -import { mount } from "enzyme"; -import { BrowserRouter as Router } from "react-router-dom"; -import Header from "../../components/Header"; - -describe("Header component", () => { - it("Snapshot testing with no user", () => { - const component = create( - -
    - - ); - let tree = component.toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it("Snapshot testing with user", () => { - const component = create( - -
    - - ); - let tree = component.toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it("Check link to main page", () => { - const header = mount( - -
    - - ); - expect(header.find("Link").first().prop("to")).toEqual("/"); - }); - - it("Render register button when there's no user", () => { - const header = mount( - -
    - - ); - expect(header.find("li > Link").first().text()).toEqual("Sign in"); - }); - - it("Render user name when there's a user", () => { - const user = { username: "user name", image: "image.png" }; - const header = mount( - -
    - - ); - expect(header.find("li > Link").last().text()).toEqual(user.username); - }); -}); diff --git a/frontend/src/tests/components/__snapshots__/Header.test.js.snap b/frontend/src/tests/components/__snapshots__/Header.test.js.snap deleted file mode 100644 index e2509e5..0000000 --- a/frontend/src/tests/components/__snapshots__/Header.test.js.snap +++ /dev/null @@ -1,119 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Header component Snapshot testing with no user 1`] = ` - -`; - -exports[`Header component Snapshot testing with user 1`] = ` - -`; diff --git a/frontend/src/tests/item/CommentInput.test.js b/frontend/src/tests/item/CommentInput.test.js deleted file mode 100644 index ab7fcf5..0000000 --- a/frontend/src/tests/item/CommentInput.test.js +++ /dev/null @@ -1,64 +0,0 @@ -import { create } from "react-test-renderer"; -import { mount } from "enzyme"; -import configureMockStore from "redux-mock-store"; -import CommentInput from "../../components/Item/CommentInput"; -import agent from "../../agent"; -import { ADD_COMMENT } from "../../constants/actionTypes"; - -const mockStore = configureMockStore(); -agent.Comments.create = jest.fn(); - -describe("CommentInput component", () => { - let store; - - beforeEach(() => { - store = mockStore({}); - }); - - it("Snapshot testing with no user", () => { - const component = create( - - ); - let tree = component.toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it("Submit text", () => { - const user = { username: "name", image: "" }; - const component = mount( - - ); - const comment = { id: 1 }; - agent.Comments.create.mockResolvedValue(comment); - - const event = { target: { value: "sometext" } }; - component.find("textarea").simulate("change", event); - component.find("form").simulate("submit"); - - setImmediate(async () => { - expect(store.getActions()).toHaveLength(1); - expect(store.getActions()[0].type).toEqual(ADD_COMMENT); - expect(await store.getActions()[0].payload).toEqual(comment); - }); - }); - - it("Clear text after submit", async () => { - const user = { username: "name", image: "" }; - - const component = mount( - - ); - - const comment = { id: 1 }; - agent.Comments.create.mockResolvedValue(comment); - - const event = { target: { value: "sometext" } }; - component.find("textarea").simulate("change", event); - component.find("form").simulate("submit"); - expect(component.find("textarea").text()).toHaveLength(0); - }); -}); diff --git a/frontend/src/tests/item/__snapshots__/CommentInput.test.js.snap b/frontend/src/tests/item/__snapshots__/CommentInput.test.js.snap deleted file mode 100644 index f739b2c..0000000 --- a/frontend/src/tests/item/__snapshots__/CommentInput.test.js.snap +++ /dev/null @@ -1,35 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`CommentInput component Snapshot testing with no user 1`] = ` -
    -
    -