├── .babelrc ├── .editorconfig ├── .eslintrc ├── .github └── ISSUE_TEMPLATE.md ├── .gitignore ├── .istanbul.yml ├── .npmrc ├── .travis.yml ├── LICENSE ├── Procfile ├── README.md ├── appveyor.yml ├── config ├── auth.js └── passport.js ├── dist ├── favicon.ico ├── index.html ├── main.0f65c57f51c7ffd775a6.js ├── main.0f65c57f51c7ffd775a6.js.map ├── main.f88d1775e3064b9f33756ae417af7ab8.css ├── main.f88d1775e3064b9f33756ae417af7ab8.css.map ├── plain.png ├── roboto-blackitalic-webfont.woff ├── roboto-blackitalic-webfont.woff2 ├── roboto-bold-webfont.woff ├── roboto-bold-webfont.woff2 ├── roboto-bolditalic-webfont.woff ├── roboto-bolditalic-webfont.woff2 ├── roboto-italic-webfont.woff ├── roboto-italic-webfont.woff2 ├── roboto-light-webfont.woff ├── roboto-light-webfont.woff2 ├── roboto-lightitalic-webfont.woff ├── roboto-lightitalic-webfont.woff2 ├── roboto-medium-webfont.woff ├── roboto-medium-webfont.woff2 ├── roboto-mediumitalic-webfont.woff ├── roboto-mediumitalic-webfont.woff2 ├── roboto-regular-webfont.woff ├── roboto-regular-webfont.woff2 ├── robotomono-bold-webfont.woff ├── robotomono-bold-webfont.woff2 ├── robotomono-bolditalic-webfont.woff ├── robotomono-bolditalic-webfont.woff2 ├── robotomono-italic-webfont.woff ├── robotomono-italic-webfont.woff2 ├── robotomono-light-webfont.woff ├── robotomono-light-webfont.woff2 ├── robotomono-lightitalic-webfont.woff ├── robotomono-lightitalic-webfont.woff2 ├── robotomono-medium-webfont.woff ├── robotomono-medium-webfont.woff2 ├── robotomono-mediumitalic-webfont.woff ├── robotomono-mediumitalic-webfont.woff2 ├── robotomono-regular-webfont.woff └── robotomono-regular-webfont.woff2 ├── models ├── item.js └── user.js ├── package.json ├── server ├── api.js ├── authRoutes.js └── logoutRoute.js ├── src ├── actions │ ├── allItemsActions.js │ ├── appActions.js │ ├── commonActions.js │ ├── individualItemActions.js │ ├── myItemsActions.js │ ├── profileActions.js │ └── tradeActions.js ├── assets │ ├── fonts │ │ ├── fonts.css │ │ ├── roboto-black-webfont.woff │ │ ├── roboto-black-webfont.woff2 │ │ ├── roboto-blackitalic-webfont.woff │ │ ├── roboto-blackitalic-webfont.woff2 │ │ ├── roboto-bold-webfont.woff │ │ ├── roboto-bold-webfont.woff2 │ │ ├── roboto-bolditalic-webfont.woff │ │ ├── roboto-bolditalic-webfont.woff2 │ │ ├── roboto-italic-webfont.woff │ │ ├── roboto-italic-webfont.woff2 │ │ ├── roboto-light-webfont.woff │ │ ├── roboto-light-webfont.woff2 │ │ ├── roboto-lightitalic-webfont.woff │ │ ├── roboto-lightitalic-webfont.woff2 │ │ ├── roboto-medium-webfont.woff │ │ ├── roboto-medium-webfont.woff2 │ │ ├── roboto-mediumitalic-webfont.woff │ │ ├── roboto-mediumitalic-webfont.woff2 │ │ ├── roboto-regular-webfont.woff │ │ ├── roboto-regular-webfont.woff2 │ │ ├── roboto-thin-webfont.woff │ │ ├── roboto-thin-webfont.woff2 │ │ ├── roboto-thinitalic-webfont.woff │ │ ├── roboto-thinitalic-webfont.woff2 │ │ ├── robotomono-bold-webfont.woff │ │ ├── robotomono-bold-webfont.woff2 │ │ ├── robotomono-bolditalic-webfont.woff │ │ ├── robotomono-bolditalic-webfont.woff2 │ │ ├── robotomono-italic-webfont.woff │ │ ├── robotomono-italic-webfont.woff2 │ │ ├── robotomono-light-webfont.woff │ │ ├── robotomono-light-webfont.woff2 │ │ ├── robotomono-lightitalic-webfont.woff │ │ ├── robotomono-lightitalic-webfont.woff2 │ │ ├── robotomono-medium-webfont.woff │ │ ├── robotomono-medium-webfont.woff2 │ │ ├── robotomono-mediumitalic-webfont.woff │ │ ├── robotomono-mediumitalic-webfont.woff2 │ │ ├── robotomono-regular-webfont.woff │ │ ├── robotomono-regular-webfont.woff2 │ │ ├── robotomono-thin-webfont.woff │ │ ├── robotomono-thin-webfont.woff2 │ │ ├── robotomono-thinitalic-webfont.woff │ │ └── robotomono-thinitalic-webfont.woff2 │ └── images │ │ ├── addItemPic.svg │ │ ├── arrow.svg │ │ ├── fileUpload.svg │ │ ├── logo.png │ │ ├── plain.png │ │ └── user.svg ├── components │ ├── AddItemPage │ │ ├── index.js │ │ └── styles.sass │ ├── App │ │ ├── index.js │ │ └── styles.sass │ ├── BasicInfo │ │ ├── index.js │ │ └── styles.sass │ ├── ErrorPage │ │ ├── index.js │ │ └── styles.sass │ ├── Footer │ │ ├── index.js │ │ └── styles.sass │ ├── Item │ │ ├── index.js │ │ └── styles.sass │ ├── Login │ │ ├── index.js │ │ └── styles.sass │ ├── OtherInfo │ │ ├── index.js │ │ └── styles.sass │ ├── ProposedTrade │ │ ├── index.js │ │ └── styles.sass │ ├── TradeRequest │ │ ├── index.js │ │ └── styles.sass │ └── UserItem │ │ ├── index.js │ │ └── styles.sass ├── constants │ └── actionTypes.js ├── containers │ ├── Header │ │ ├── index.js │ │ └── styles.sass │ ├── ItemPage │ │ ├── index.js │ │ └── styles.sass │ ├── Main │ │ ├── index.js │ │ └── styles.sass │ ├── MyItems │ │ ├── index.js │ │ └── styles.sass │ ├── Profile │ │ ├── index.js │ │ └── styles.sass │ └── Trades │ │ ├── index.js │ │ └── styles.sass ├── favicon.ico ├── index.ejs ├── index.js ├── reducers │ ├── allItemsReducer.js │ ├── appDataReducer.js │ ├── index.js │ ├── individualItemReducer.js │ ├── initialState.js │ ├── myItemsReducer.js │ ├── profileDataReducer.js │ └── tradesDataReducer.js ├── routes.js ├── store │ └── configureStore.js ├── styles │ ├── animation.sass │ ├── fonts.sass │ ├── global.sass │ ├── mediaqueries.sass │ └── variables.sass ├── utils │ ├── checkAuth.js │ └── loadPageProps.js └── webpack-public-path.js ├── tools ├── .yarnclean ├── analyzeBundle.js ├── build.js ├── chalkConfig.js ├── distServer.js ├── fileMock.js ├── nodeVersionCheck.js ├── server.js ├── srcServer.js └── startMessage.js ├── webpack.config.dev.js ├── webpack.config.prod.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "react", 4 | "stage-1" 5 | ], 6 | "env": { 7 | "development": { 8 | "presets": [ 9 | "latest", 10 | "react-hmre" 11 | ] 12 | }, 13 | "production": { 14 | "presets": [ 15 | ["latest", { 16 | "es2015": { 17 | "modules": false 18 | } 19 | }] 20 | ], 21 | "plugins": [ 22 | "transform-react-constant-elements", 23 | "transform-react-remove-prop-types" 24 | ] 25 | }, 26 | "test": { 27 | "presets": [ 28 | "latest" 29 | ] 30 | } 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": [ 4 | "eslint:recommended", 5 | "plugin:import/errors", 6 | "plugin:import/warnings" 7 | ], 8 | "plugins": [ 9 | "react" 10 | ], 11 | "parser": "babel-eslint", 12 | "parserOptions": { 13 | "ecmaVersion": 6, 14 | "sourceType": "module", 15 | "ecmaFeatures": { 16 | "jsx": true, 17 | "experimentalObjectRestSpread": true 18 | } 19 | }, 20 | "env": { 21 | "es6": true, 22 | "browser": true, 23 | "node": true, 24 | "jquery": true, 25 | "jest": true 26 | }, 27 | "rules": { 28 | "quotes": 0, 29 | "no-console": 1, 30 | "no-debugger": 1, 31 | "no-var": 1, 32 | "semi": [1, "always"], 33 | "no-trailing-spaces": 0, 34 | "eol-last": 0, 35 | "no-underscore-dangle": 0, 36 | "no-alert": 0, 37 | "no-lone-blocks": 0, 38 | "jsx-quotes": 1, 39 | "react/display-name": [ 1, {"ignoreTranspilerName": false }], 40 | "react/forbid-prop-types": [1, {"forbid": ["any"]}], 41 | "react/jsx-boolean-value": 0, 42 | "react/jsx-closing-bracket-location": 0, 43 | "react/jsx-curly-spacing": 1, 44 | "react/jsx-indent-props": 0, 45 | "react/jsx-key": 1, 46 | "react/jsx-max-props-per-line": 0, 47 | "react/jsx-no-bind": 0, 48 | "react/jsx-no-duplicate-props": 1, 49 | "react/jsx-no-literals": 0, 50 | "react/jsx-no-undef": 1, 51 | "react/jsx-pascal-case": 1, 52 | "react/jsx-sort-prop-types": 0, 53 | "react/jsx-sort-props": 0, 54 | "react/jsx-uses-react": 1, 55 | "react/jsx-uses-vars": 1, 56 | "react/jsx-wrap-multilines": 1, 57 | "react/no-danger": 1, 58 | "react/no-did-mount-set-state": 1, 59 | "react/no-did-update-set-state": 1, 60 | "react/no-direct-mutation-state": 1, 61 | "react/no-multi-comp": 1, 62 | "react/no-set-state": 0, 63 | "react/no-unknown-property": 1, 64 | "react/prefer-es6-class": 1, 65 | "react/prop-types": 1, 66 | "react/react-in-jsx-scope": 1, 67 | "import/extensions": 1, 68 | "react/self-closing-comp": 1, 69 | "react/sort-comp": 1 70 | }, 71 | "globals": { 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Node version: 2 | 3 | npm version: 4 | 5 | Operating system: 6 | 7 | Command line used: 8 | 9 | Steps to reproduce: 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log* 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 27 | node_modules 28 | 29 | # IDEA/Webstorm project files 30 | .idea 31 | *.iml 32 | 33 | #VSCode metadata 34 | .vscode 35 | 36 | # Mac files 37 | .DS_Store 38 | 39 | # Env file 40 | .env 41 | 42 | # now.json 43 | now.json 44 | -------------------------------------------------------------------------------- /.istanbul.yml: -------------------------------------------------------------------------------- 1 | instrumentation: 2 | excludes: ['*.spec.js'] 3 | extensions: ['.js'] 4 | include-all-sources: true 5 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | save-exact=true 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | cache: yarn 3 | node_js: 4 | - "6" 5 | - "5" 6 | - "4" 7 | after_success: 8 | # Send coverage data to coveralls. 9 | - yarn run test:cover:travis 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Arshad Khan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: npm run herokuStart 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # trader 2 | A full stack app for trading. 3 | 4 | ## User stories 5 | * I can view all books posted by every user. 6 | * I can add a new book. 7 | * I can update my settings to store my full name, city, and state 8 | * I can propose a trade and wait for the other user to accept the trade. 9 | 10 | ## Tech Stack 11 | * React 12 | * Redux 13 | * React Router 14 | * Flexbox 15 | * Nodejs 16 | * Express 17 | * Mongoose/MongoDB 18 | * Webpack 19 | * now as paas(Using heroku atm) 20 | * Use React-redux-router 21 | * yarn 22 | 23 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # Test against this version of Node.js 2 | environment: 3 | matrix: 4 | # node.js 5 | - nodejs_version: "6" 6 | - nodejs_version: "5" 7 | - nodejs_version: "4" 8 | 9 | # Install scripts. (runs after repo cloning) 10 | install: 11 | # Get the latest stable version of Node.js or io.js 12 | - ps: Install-Product node $env:nodejs_version 13 | # install modules 14 | - yarn 15 | 16 | cache: 17 | - "%LOCALAPPDATA%\\Yarn" 18 | 19 | # Post-install test scripts. 20 | test_script: 21 | # Output useful info for debugging. 22 | - node --version 23 | - npm --version 24 | # run tests 25 | - npm test 26 | 27 | # Don't actually build. 28 | build: off 29 | 30 | notifications: 31 | - provider: Email 32 | to: 33 | - housecor@gmail.com 34 | subject: 'Build failed: react-slingshot' 35 | message: The continuous integration build failed. See https://ci.appveyor.com/project/CoryHouse/react-slingshot/ for details. 36 | on_build_success: false 37 | on_build_failure: true 38 | on_build_status_changed: false 39 | -------------------------------------------------------------------------------- /config/auth.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const APP_URL = 4 | process.env.NODE_ENV === "production" ? process.env.APP_URL : process.env.DEV_APP_URL; 5 | 6 | module.exports = { 7 | 'facebookAuth': { 8 | 'clientID': process.env.FACEBOOK_KEY, 9 | 'clientSecret': process.env.FACEBOOK_SECRET, 10 | 'callbackURL': APP_URL + 'auth/facebook/callback' 11 | }, 12 | 'twitterAuth': { 13 | 'clientID': process.env.TWITTER_KEY, 14 | 'clientSecret': process.env.TWITTER_SECRET, 15 | 'callbackURL': APP_URL + 'auth/twitter/callback' 16 | }, 17 | 'googleAuth': { 18 | 'clientID': process.env.GOOGLE_KEY, 19 | 'clientSecret': process.env.GOOGLE_SECRET, 20 | 'callbackURL': APP_URL + 'auth/google/callback' 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /config/passport.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const GoogleStrategy = require('passport-google-oauth').OAuth2Strategy; 4 | const FacebookStrategy = require('passport-facebook').Strategy; 5 | const TwitterStrategy = require('passport-twitter').Strategy; 6 | const User = require('../models/user'); 7 | const configAuth = require('./auth'); 8 | 9 | module.exports = function (passport) { 10 | passport.serializeUser((user, done) => { 11 | done(null, user.id); 12 | }); 13 | 14 | passport.deserializeUser((id, done) => { 15 | User.findById(id, function (err, user) { 16 | done(err, user); 17 | }); 18 | }); 19 | 20 | passport.use(new TwitterStrategy({ 21 | consumerKey: configAuth.twitterAuth.clientID, 22 | consumerSecret: configAuth.twitterAuth.clientSecret, 23 | callbackURL: configAuth.twitterAuth.callbackURL 24 | }, 25 | (token, tokenSecret, profile, done) => { 26 | process.nextTick(function () { 27 | User.findOne({ 'twitter.id': profile.id }, (err, user) => { 28 | if (err) 29 | return done(err); 30 | if (user) { 31 | return done(null, user); 32 | } else { 33 | const newUser = new User(); 34 | newUser.twitter.id = profile.id; 35 | newUser.tradesProposed = []; 36 | newUser.tradeRequests = []; 37 | newUser.notificationsCount = 0; 38 | newUser.twitter.token = token; 39 | newUser.twitter.username = profile.username; 40 | newUser.name = profile.displayName; 41 | newUser.dp = profile.photos && profile.photos[0].value; 42 | newUser.dp = newUser.dp && newUser.dp.replace("_normal", ""); 43 | newUser.address = { 44 | localAddress: "", 45 | pinCode: "", 46 | state: "", 47 | city: "", 48 | country: "", 49 | landmark: "" 50 | }; 51 | newUser.items = []; 52 | newUser.phoneNo = ""; 53 | newUser.email = ""; 54 | 55 | newUser.save((err) => { 56 | if (err) 57 | throw err; 58 | return done(null, newUser); 59 | }); 60 | } 61 | }); 62 | }); 63 | 64 | })); 65 | 66 | passport.use(new FacebookStrategy({ 67 | clientID: configAuth.facebookAuth.clientID, 68 | clientSecret: configAuth.facebookAuth.clientSecret, 69 | callbackURL: configAuth.facebookAuth.callbackURL, 70 | profileFields: ['id', 'name','picture.type(large)', 'emails', 'displayName', 'about', 'gender'] 71 | }, 72 | (token, refreshToken, profile, done) => { 73 | process.nextTick(function () { 74 | User.findOne({ 'facebook.id': profile.id }, (err, user) => { 75 | if (err) 76 | return done(err); 77 | if (user) { 78 | return done(null, user); 79 | } else { 80 | const newUser = new User(); 81 | newUser.facebook.id = profile.id; 82 | newUser.tradesProposed = []; 83 | newUser.tradeRequests = []; 84 | newUser.notificationsCount = 0; 85 | newUser.facebook.token = token; 86 | newUser.name = profile.displayName; 87 | newUser.facebook.email = (profile.emails && profile.emails[0].value) || "Email not added"; 88 | newUser.dp = profile.photos && profile.photos[0].value; 89 | newUser.address = { 90 | localAddress: "", 91 | pinCode: "", 92 | state: "", 93 | city: "", 94 | country: "", 95 | landmark: "" 96 | }; 97 | newUser.items = []; 98 | newUser.phoneNo = ""; 99 | newUser.email = ""; 100 | 101 | newUser.save((err) => { 102 | if (err) 103 | throw err; 104 | return done(null, newUser); 105 | }); 106 | } 107 | }); 108 | }); 109 | 110 | })); 111 | 112 | passport.use(new GoogleStrategy({ 113 | clientID: configAuth.googleAuth.clientID, 114 | clientSecret: configAuth.googleAuth.clientSecret, 115 | callbackURL: configAuth.googleAuth.callbackURL, 116 | }, 117 | (token, refreshToken, profile, done) => { 118 | process.nextTick(() => { 119 | User.findOne({ 'google.id': profile.id }, (err, user) => { 120 | if (err) 121 | return done(err); 122 | if (user) { 123 | return done(null, user); 124 | } else { 125 | const newUser = new User(); 126 | newUser.google.id = profile.id; 127 | newUser.tradesProposed = []; 128 | newUser.notificationsCount = 0; 129 | newUser.tradeRequests = []; 130 | newUser.google.token = token; 131 | newUser.name = profile.displayName; 132 | newUser.google.email = profile.emails[0].value; // pull the first email 133 | newUser.dp = profile.photos && profile.photos[0].value; 134 | newUser.dp = newUser.dp && newUser.dp.slice(0, newUser.dp.lastIndexOf('?')); 135 | newUser.address = { 136 | localAddress: "", 137 | pinCode: "", 138 | state: "", 139 | city: "", 140 | country: "", 141 | landmark: "" 142 | }; 143 | newUser.items = []; 144 | newUser.phoneNo = ""; 145 | newUser.email = ""; 146 | 147 | newUser.save((err) => { 148 | if (err) 149 | throw err; 150 | return done(null, newUser); 151 | }); 152 | } 153 | }); 154 | }); 155 | 156 | })); 157 | }; 158 | -------------------------------------------------------------------------------- /dist/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/favicon.ico -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | Trader
-------------------------------------------------------------------------------- /dist/plain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/plain.png -------------------------------------------------------------------------------- /dist/roboto-blackitalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/roboto-blackitalic-webfont.woff -------------------------------------------------------------------------------- /dist/roboto-blackitalic-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/roboto-blackitalic-webfont.woff2 -------------------------------------------------------------------------------- /dist/roboto-bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/roboto-bold-webfont.woff -------------------------------------------------------------------------------- /dist/roboto-bold-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/roboto-bold-webfont.woff2 -------------------------------------------------------------------------------- /dist/roboto-bolditalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/roboto-bolditalic-webfont.woff -------------------------------------------------------------------------------- /dist/roboto-bolditalic-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/roboto-bolditalic-webfont.woff2 -------------------------------------------------------------------------------- /dist/roboto-italic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/roboto-italic-webfont.woff -------------------------------------------------------------------------------- /dist/roboto-italic-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/roboto-italic-webfont.woff2 -------------------------------------------------------------------------------- /dist/roboto-light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/roboto-light-webfont.woff -------------------------------------------------------------------------------- /dist/roboto-light-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/roboto-light-webfont.woff2 -------------------------------------------------------------------------------- /dist/roboto-lightitalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/roboto-lightitalic-webfont.woff -------------------------------------------------------------------------------- /dist/roboto-lightitalic-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/roboto-lightitalic-webfont.woff2 -------------------------------------------------------------------------------- /dist/roboto-medium-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/roboto-medium-webfont.woff -------------------------------------------------------------------------------- /dist/roboto-medium-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/roboto-medium-webfont.woff2 -------------------------------------------------------------------------------- /dist/roboto-mediumitalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/roboto-mediumitalic-webfont.woff -------------------------------------------------------------------------------- /dist/roboto-mediumitalic-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/roboto-mediumitalic-webfont.woff2 -------------------------------------------------------------------------------- /dist/roboto-regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/roboto-regular-webfont.woff -------------------------------------------------------------------------------- /dist/roboto-regular-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/roboto-regular-webfont.woff2 -------------------------------------------------------------------------------- /dist/robotomono-bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/robotomono-bold-webfont.woff -------------------------------------------------------------------------------- /dist/robotomono-bold-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/robotomono-bold-webfont.woff2 -------------------------------------------------------------------------------- /dist/robotomono-bolditalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/robotomono-bolditalic-webfont.woff -------------------------------------------------------------------------------- /dist/robotomono-bolditalic-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/robotomono-bolditalic-webfont.woff2 -------------------------------------------------------------------------------- /dist/robotomono-italic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/robotomono-italic-webfont.woff -------------------------------------------------------------------------------- /dist/robotomono-italic-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/robotomono-italic-webfont.woff2 -------------------------------------------------------------------------------- /dist/robotomono-light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/robotomono-light-webfont.woff -------------------------------------------------------------------------------- /dist/robotomono-light-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/robotomono-light-webfont.woff2 -------------------------------------------------------------------------------- /dist/robotomono-lightitalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/robotomono-lightitalic-webfont.woff -------------------------------------------------------------------------------- /dist/robotomono-lightitalic-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/robotomono-lightitalic-webfont.woff2 -------------------------------------------------------------------------------- /dist/robotomono-medium-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/robotomono-medium-webfont.woff -------------------------------------------------------------------------------- /dist/robotomono-medium-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/robotomono-medium-webfont.woff2 -------------------------------------------------------------------------------- /dist/robotomono-mediumitalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/robotomono-mediumitalic-webfont.woff -------------------------------------------------------------------------------- /dist/robotomono-mediumitalic-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/robotomono-mediumitalic-webfont.woff2 -------------------------------------------------------------------------------- /dist/robotomono-regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/robotomono-regular-webfont.woff -------------------------------------------------------------------------------- /dist/robotomono-regular-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/dist/robotomono-regular-webfont.woff2 -------------------------------------------------------------------------------- /models/item.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const mongoose = require('mongoose'); 4 | const Schema = mongoose.Schema; 5 | 6 | const Item = new Schema({ 7 | itemName: String, 8 | itemPic: String, 9 | itemPrice: String, 10 | itemCurrency: String, 11 | itemDescription: String, 12 | itemTags: String, 13 | itemOwner: String, 14 | itemOwnerId: String, 15 | itemAdditionDate: String, 16 | itemRequests: Array, 17 | key: Number 18 | }); 19 | 20 | module.exports = mongoose.model('Item', Item); 21 | -------------------------------------------------------------------------------- /models/user.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const mongoose = require('mongoose'); 4 | const Schema = mongoose.Schema; 5 | 6 | const User = new Schema({ 7 | name: String, 8 | dp: String, 9 | items: Array, 10 | phoneNo: String, 11 | email: String, 12 | address: { 13 | country: String, 14 | city: String, 15 | state: String, 16 | landmark: String, 17 | localAddress: String, 18 | pinCode: String 19 | }, 20 | trades: Array, 21 | notificationsCount: Number, 22 | google: { 23 | id: String, 24 | token: String, 25 | email: String 26 | }, 27 | twitter: { 28 | id: String, 29 | token: String, 30 | username: String 31 | }, 32 | facebook: { 33 | id: String, 34 | token: String, 35 | email: String 36 | } 37 | }); 38 | 39 | module.exports = mongoose.model('User', User); 40 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "trading-app", 3 | "version": "0.1.0", 4 | "description": "A full stack js app for trading anything.", 5 | "engines": { 6 | "npm": ">=3" 7 | }, 8 | "scripts": { 9 | "preinstall": "node tools/nodeVersionCheck.js", 10 | "setup": "node tools/setup/setupMessage.js && npm install && node tools/setup/setup.js", 11 | "start-message": "babel-node tools/startMessage.js", 12 | "prestart": "npm-run-all --parallel start-message", 13 | "start": "npm-run-all --parallel open:src lint:watch", 14 | "open:src": "babel-node tools/server.js development", 15 | "open:dist": "babel-node tools/server.js production", 16 | "lint": "esw webpack.config.* src tools --color", 17 | "lint:watch": "npm run lint -- --watch", 18 | "clean-dist": "npm run remove-dist && mkdir dist", 19 | "remove-dist": "rimraf ./dist", 20 | "prebuild": "npm run clean-dist && npm run lint && npm run test", 21 | "build": "babel-node tools/build.js && npm run open:dist", 22 | "test": "node --harmony node_modules/jest/bin/jest", 23 | "test:cover": "npm run test -- --coverage ", 24 | "test:cover:travis": "npm run test:cover && cat ./coverage/lcov.info | node_modules/coveralls/bin/coveralls.js", 25 | "test:watch": "npm run test -- --watch", 26 | "open:cover": "npm run test:cover && open coverage/lcov-report/index.html", 27 | "analyze-bundle": "babel-node ./tools/analyzeBundle.js", 28 | "herokuStart": "node tools/distServer.js production" 29 | }, 30 | "author": "Arshad Khan ", 31 | "license": "MIT", 32 | "dependencies": { 33 | "babel": "6.23.0", 34 | "bluebird": "^3.5.0", 35 | "body-parser": "^1.16.1", 36 | "cloudinary": "^1.8.0", 37 | "dotenv": "^4.0.0", 38 | "express": "4.15.2", 39 | "express-session": "^1.15.1", 40 | "mongoose": "^4.8.2", 41 | "multer": "^1.3.0", 42 | "object-assign": "4.1.0", 43 | "passport": "^0.3.2", 44 | "passport-facebook": "^2.1.1", 45 | "passport-google-oauth": "^1.0.0", 46 | "passport-twitter": "^1.0.4", 47 | "react": "15.4.1", 48 | "react-addons-css-transition-group": "^15.4.2", 49 | "react-dom": "15.4.1", 50 | "react-redux": "5.0.1", 51 | "react-router": "3.0.0", 52 | "react-router-redux": "4.0.7", 53 | "react-tap-event-plugin": "^2.0.1", 54 | "redux": "3.6.0", 55 | "redux-logger": "^2.8.2", 56 | "redux-thunk": "2.1.0", 57 | "rmdir": "^1.2.0", 58 | "unfetch": "^2.1.2" 59 | }, 60 | "devDependencies": { 61 | "autoprefixer": "6.5.4", 62 | "babel-cli": "6.18.0", 63 | "babel-core": "6.20.0", 64 | "babel-eslint": "7.1.1", 65 | "babel-jest": "18.0.0", 66 | "babel-loader": "6.2.10", 67 | "babel-plugin-transform-react-constant-elements": "6.9.1", 68 | "babel-plugin-transform-react-remove-prop-types": "0.2.11", 69 | "babel-polyfill": "6.20.0", 70 | "babel-preset-latest": "6.16.0", 71 | "babel-preset-react": "6.16.0", 72 | "babel-preset-react-hmre": "1.1.1", 73 | "babel-preset-stage-1": "6.16.0", 74 | "browser-sync": "2.18.5", 75 | "chalk": "1.1.3", 76 | "connect-history-api-fallback": "1.3.0", 77 | "coveralls": "2.11.15", 78 | "css-loader": "0.26.1", 79 | "enzyme": "2.6.0", 80 | "eslint": "3.12.2", 81 | "eslint-plugin-import": "2.2.0", 82 | "eslint-plugin-react": "6.8.0", 83 | "eslint-watch": "2.1.14", 84 | "extract-text-webpack-plugin": "2.0.0-beta.4", 85 | "file-loader": "0.9.0", 86 | "html-webpack-plugin": "2.24.1", 87 | "identity-obj-proxy": "3.0.0", 88 | "jest": "18.1.0", 89 | "json-loader": "0.5.4", 90 | "mockdate": "2.0.1", 91 | "node-sass": "4.0.0", 92 | "npm-run-all": "3.1.2", 93 | "open": "0.0.5", 94 | "postcss-loader": "1.2.1", 95 | "prompt": "1.0.0", 96 | "react-addons-test-utils": "15.4.1", 97 | "redux-immutable-state-invariant": "^2.0.0", 98 | "replace": "0.3.0", 99 | "rimraf": "^2.6.1", 100 | "sass-loader": "4.1.0", 101 | "style-loader": "0.13.1", 102 | "url-loader": "0.5.7", 103 | "webpack": "2.2.1", 104 | "webpack-bundle-analyzer": "2.1.1", 105 | "webpack-dev-middleware": "1.9.0", 106 | "webpack-hot-middleware": "2.13.2", 107 | "webpack-md5-hash": "0.0.5" 108 | }, 109 | "keywords": [], 110 | "repository": { 111 | "type": "git", 112 | "url": "https://www.github.com/arshdkhn1/trade-app" 113 | }, 114 | "jest": { 115 | "moduleNameMapper": { 116 | "\\.(css|scss)$": "identity-obj-proxy", 117 | "^.+\\.(gif|ttf|eot|svg|woff|woff2|ico)$": "/tools/fileMock.js" 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /server/api.js: -------------------------------------------------------------------------------- 1 | const User = require('../models/user'); 2 | const Item = require('../models/item'); 3 | const objectAssign = require('object-assign'); 4 | const cloudinary = require('cloudinary'); 5 | const multer = require('multer'); 6 | const path = require('path'); 7 | const cp = require('child_process'); 8 | 9 | const uploadDir = path.resolve(process.cwd(), 'uploads'); 10 | 11 | const upload = multer({ 12 | dest: uploadDir, 13 | limits: { fileSize: 512000 } 14 | }).single('itemPic'); 15 | 16 | module.exports = function (app) { 17 | 18 | cloudinary.config({ 19 | cloud_name: process.env.CAPI_CLOUD_NAME, 20 | api_key: process.env.CAPI_KEY, 21 | api_secret: process.env.CAPI_SECRET 22 | }); 23 | 24 | const isLoggedIn = (req, res, next) => { 25 | if (req.isAuthenticated()) { 26 | next(); 27 | } else { 28 | res.json({ 'error': 'UNAUTHORIZED' }); 29 | } 30 | }; 31 | 32 | app.get('/isUserLoggedIn', isLoggedIn, (req, res) => { 33 | res.json({ 'error': '', 'notificationsCount': req.user.notificationsCount }) 34 | }); 35 | 36 | app.get('/api/getProfileData', isLoggedIn, (req, res) => { 37 | const { name, address, phoneNo, email, dp } = req.user; 38 | res.json({ name, address, phoneNo, email, dp }); 39 | }); 40 | 41 | app.post('/api/setProfileData', isLoggedIn, (req, res) => { 42 | const { landmark, city, state, pinCode, country, localAddress } = req.body; 43 | const address = { landmark, city, state, pinCode, country, localAddress }; 44 | const phoneNo = req.body.phoneNo; 45 | const email = req.body.email; 46 | const newProfileData = req.query.edit === 'location' ? { address } : { phoneNo, email }; 47 | User.findByIdAndUpdate(req.user.id, newProfileData, { new: true }) 48 | .exec((err, doc) => { 49 | if (err) { 50 | res.status(500).send({ error: "Error happened while updating user info!" }); 51 | } else { 52 | const { address, phoneNo, email } = doc; 53 | res.json({ address, phoneNo, email }); 54 | } 55 | }); 56 | }); 57 | 58 | app.post('/api/addMyItem', (req, res) => { 59 | upload(req, res, err => { 60 | if (err) { 61 | res.status(500).send('File upload failed.').end(); 62 | } else { 63 | if (!req.file) { 64 | return res.status(403).send('Please upload a picture of item!').end(); 65 | } 66 | 67 | if (!/^image\/(jpe?g|png|gif)$/i.test(req.file.mimetype)) { 68 | return res.status(403).send('Please upload JPEG or PNG or GIF image file!').end(); 69 | } 70 | 71 | const date = new Date(); 72 | const ownerInfo = { itemOwnerId: req.user._id, itemOwner: req.user.name }; 73 | const data = objectAssign( 74 | {}, 75 | req.body, 76 | { 77 | itemAdditionDate: date.toDateString().slice(4), 78 | itemRequests: [], key: date.getTime() 79 | }, 80 | ownerInfo 81 | ); 82 | const newItem = new Item(data); 83 | 84 | cloudinary.uploader.upload(`${req.file.path}`, function (result) { 85 | newItem.itemPic = result.secure_url; 86 | newItem.save((err, doc) => { 87 | if (err) { 88 | console.error('Error happened while adding new myitem-', err); 89 | res.status(500).send({ error: 'Some error happened while adding new item!' }); 90 | } else { 91 | const item = objectAssign({}, doc.toObject()); 92 | delete item._id; 93 | delete item.__v; 94 | delete item.itemOwnerId; 95 | res.json(item); 96 | } 97 | }); 98 | 99 | // clear the uploadDir 100 | cp.exec('rm -r ' + uploadDir + '/*', err => { 101 | if (err) { 102 | console.error('Error happenned while clearing uploadDir-', err); 103 | } 104 | }); 105 | 106 | }, { public_id: `${date.getTime()}` }); 107 | 108 | } 109 | }); 110 | }); 111 | 112 | app.get('/api/getMyItemsData', isLoggedIn, (req, res) => { 113 | Item.find({ itemOwnerId: req.user._id.toString() }, 114 | ['key', 'itemName', 'itemPic', 'itemCurrency', 'itemAdditionDate', 115 | 'itemPrice', 'itemDescription', 'itemTags'], 116 | { 117 | sort: { key: -1 } 118 | } 119 | ) 120 | .exec((err, docs) => { 121 | if (err) { 122 | console.error('Error happened while loading myItems-', err); 123 | res.status(500).send({ error: 'Some error happened while loading all of your items!' }); 124 | } else { 125 | res.json(docs); 126 | } 127 | }); 128 | }); 129 | 130 | // Checks first whether user is loggedIn or not then deletes item ioi item's owner is current user 131 | app.delete('/api/deleteMyItem/:key', isLoggedIn, (req, res) => { 132 | Item.find({ key: req.params.key, itemOwnerId: req.user._id }) 133 | .remove((err) => { 134 | if (err) { 135 | console.error('Error happened while deleting item with key', req.params.key, "-", err); 136 | res.sendStatus(500); 137 | } else { 138 | res.sendStatus(200); 139 | cloudinary.uploader.destroy(`${req.params.key}`); 140 | } 141 | }); 142 | }); 143 | 144 | app.get('/api/getAllItemsData', (req, res) => { 145 | Item.find({}, 146 | ['key', 'itemName', 'itemCurrency', 'itemPrice', 'itemPic'], 147 | { 148 | sort: { key: -1 } 149 | } 150 | ) 151 | .exec((err, docs) => { 152 | if (err) { 153 | console.error('Error happened while loading allItems-', err); 154 | res.sendStatus(500); 155 | } else { 156 | res.json(docs); 157 | } 158 | }); 159 | }); 160 | 161 | app.get('/api/getIndividualItemData/:key', (req, res) => { 162 | Item.findOne({ key: req.params.key }, 163 | ['key', 'itemName', 'itemCurrency', 'itemPrice', 'itemPic', 'itemRequests', 164 | 'itemDescription', 'itemAdditionDate', 'itemTags', 'itemOwner', 'itemOwnerId'] 165 | ) 166 | .exec((err, doc) => { 167 | if (err) { 168 | console.error('Error happened while loading individual Item-', err); 169 | res.sendStatus(500); 170 | } else { 171 | if (doc) { 172 | 173 | const isSoldOut = doc.itemRequests.some(elem => elem.reqStatus === 'ACCEPTED'); 174 | 175 | const item = objectAssign({}, doc.toObject()); 176 | // checking whether the current user has requested the item 177 | // in past or not 178 | 179 | let itemRequestedByCurrentUser = false; 180 | 181 | if (req.user) { 182 | itemRequestedByCurrentUser = item.itemRequests.some(elem => ( 183 | elem.reqMaker.id === req.user._id.toString() 184 | )); 185 | } 186 | 187 | const ownItem = item.itemOwnerId === (req.user && req.user._id.toString()); 188 | delete item._id; 189 | delete item.itemOwnerId; 190 | delete item.__v; 191 | item.ownItem = ownItem; 192 | res.json(objectAssign(item, { itemRequestedByCurrentUser, isSoldOut })); 193 | } else { 194 | res.sendStatus(400); 195 | } 196 | } 197 | }); 198 | }); 199 | 200 | app.get('/api/requestitem/:key', isLoggedIn, (req, res) => { 201 | Item.findOne({ key: parseInt(req.params.key, 10) }, (err, doc) => { 202 | if (err) { 203 | console.error('Error happened while loading allItems-', err); 204 | res.sendStatus(500); 205 | } else { 206 | 207 | User.findOne({ _id: doc.itemOwnerId }, (err, doc) => { 208 | if (!err) { 209 | doc.notificationsCount += 1; 210 | doc.markModified('notificationsCount'); 211 | doc.save(); 212 | } 213 | }); 214 | 215 | // dont push itemRequest if its already there. 216 | const itemRequestedByCurrentUser = doc.itemRequests.some(elem => ( 217 | elem.reqMaker.id === req.user._id.toString() 218 | )); 219 | 220 | // checkout whether item has already sold out or not. 221 | const isSoldOut = doc.itemRequests.some(elem => elem.reqStatus === 'ACCEPTED'); 222 | 223 | if (isSoldOut) { 224 | res.status(409).send('Item Sold Out'); 225 | } else if (!itemRequestedByCurrentUser) { 226 | const itemRequest = { 227 | reqMaker: { 228 | uniqueId: new Date().getTime(), 229 | id: req.user._id.toString(), 230 | name: req.user.name 231 | }, 232 | reqStatus: 'PENDING' 233 | }; 234 | doc.itemRequests.push(itemRequest); 235 | doc.save((err, doc) => { 236 | const itemRequestedByCurrentUser = true; 237 | 238 | const proposedTrade = {}; 239 | proposedTrade.id = req.params.key; 240 | proposedTrade.itemName = doc.itemName; 241 | proposedTrade.itemPic = doc.itemPic; 242 | proposedTrade.itemOwner = doc.itemOwner; 243 | proposedTrade.reqStatus = "PENDING"; 244 | proposedTrade.reqMakerInfo = []; 245 | req.user.trades.unshift(proposedTrade); 246 | req.user.markModified('trades'); 247 | req.user.save(err => { 248 | if (err) { 249 | console.log('Error happened when adding trades request to user model.'); 250 | res.status(500).send('Error while saving to user model!').end(); 251 | } else { 252 | res.json(objectAssign({}, doc.toObject(), { itemRequestedByCurrentUser })); 253 | } 254 | }); 255 | 256 | }); 257 | } else { 258 | res.json(doc.toObject()); 259 | } 260 | } 261 | }); 262 | }); 263 | 264 | app.get('/api/getTradesData', isLoggedIn, (req, res) => { 265 | Item.find({ itemOwnerId: req.user._id }, 266 | { 'itemRequests': 1, _id: 0, 'itemPic': 1, 'itemName': 1, 'key': 1 }) 267 | .exec((err, docs) => { 268 | if (err) { 269 | res.status(500).send('Failed to fetch item trade requests!').end(); 270 | } else { 271 | let requests = docs.filter(elem => elem.itemRequests.length > 0); 272 | requests = requests.map(elem => { 273 | elem.itemRequests = elem.itemRequests.map(elemItem => { 274 | return ({ 275 | reqStatus: elemItem.reqStatus, 276 | reqMaker: elemItem.reqMaker.name, 277 | docId: elemItem.reqMaker.uniqueId 278 | }); 279 | }); 280 | return elem; 281 | }); 282 | res.json({ proposedTrades: req.user.trades, tradeRequests: requests }); 283 | } 284 | 285 | req.user.notificationsCount = 0; 286 | req.user.markModified('notificationCount'); 287 | req.user.save(); 288 | }); 289 | }); 290 | 291 | app.post('/api/removeitemrequest', isLoggedIn, (req, res) => { 292 | const key = req.body.id; 293 | Item.findOne({ key: parseInt(key, 10) }) 294 | .exec((err, doc) => { 295 | if (err) { 296 | console.log("Some error happened while removing item request-", err); 297 | res.status(500).send('Some error happened while removing item request'); 298 | } else { 299 | 300 | User.findOne({ _id: doc.itemOwnerId }, (err, doc) => { 301 | if (!err) { 302 | doc.notificationsCount -= 1; 303 | doc.markModified('notificationsCount'); 304 | doc.save(); 305 | } 306 | }); 307 | 308 | doc.itemRequests = doc.itemRequests.filter(elem => ( 309 | elem.reqMaker.id !== req.user._id.toString() 310 | )); 311 | doc.save(err => { 312 | if (err) { 313 | console.log("Some error happened while removing item request-", err); 314 | } else { 315 | req.user.trades = req.user.trades.filter( 316 | elem => elem.id !== key 317 | ); 318 | req.user.markModified('trades'); 319 | req.user.save(err => { 320 | if (err) { 321 | console.log("Error while removing cancelling trade proposal!"); 322 | } else { 323 | res.json({ proposedTrades: req.user.trades }); 324 | } 325 | }); 326 | } 327 | }); 328 | } 329 | }); 330 | }); 331 | 332 | app.post('/api/declinerequest', isLoggedIn, (req, res) => { 333 | // first remove itemRequest = require(item 334 | let userId, reqStatus; 335 | Item.findOne({ key: parseInt(req.body.key, 10) }) 336 | .exec((err, doc) => { 337 | if (err) { 338 | res.status(500).send('Error happened while declining trade request!').end(); 339 | console.log('Error happened while declining trade request!'); 340 | } else { 341 | 342 | doc.itemRequests = doc.itemRequests.filter(elem => { 343 | if (elem.reqMaker.uniqueId.toString() === req.body.docId) { 344 | userId = elem.reqMaker.id; 345 | reqStatus = elem.reqStatus; 346 | return false; 347 | } else { 348 | return true; 349 | } 350 | }); 351 | 352 | if (reqStatus === 'PENDING') { 353 | doc.save(err => { 354 | if (err) { 355 | res.status(500).send('Error happened while declining trade request!').end(); 356 | console.log('Error happened while declining trade request!'); 357 | } else { 358 | // remove proposedTrade item = require(the user who made that request. 359 | User.findOne({ _id: userId }) 360 | .exec((err, doc) => { 361 | if (err) { 362 | res.status(500).send('Error happened while declining trade request!').end(); 363 | console.log('Error happened while declining trade request!'); 364 | } else { 365 | doc.trades = doc.trades.filter(elem => elem.id !== req.body.key); 366 | doc.save(err => { 367 | if (err) { 368 | res.status(500).send('Error happened while declining trade request!').end(); 369 | console.log('Error happened while declining trade request!'); 370 | } else { 371 | res.json({ status: 'OK' }); 372 | } 373 | }); 374 | } 375 | }); 376 | } 377 | }); 378 | } else { 379 | res.json({ status: 'Accepted trade requests can\'t be declined' }); 380 | } 381 | 382 | } 383 | }); 384 | }); 385 | 386 | app.post('/api/acceptrequest', isLoggedIn, (req, res) => { 387 | const { key, docId } = req.body; 388 | let userId, prevReqStatus; 389 | Item.findOne({ key: parseInt(key, 10) }) 390 | .exec((err, doc) => { 391 | if (err) { 392 | res.status(500).send('Error happened while accepting trade request!').end(); 393 | console.log('Error happened while accepting trade request!'); 394 | } else { 395 | 396 | doc.itemRequests = doc.itemRequests.map(elem => { 397 | if (elem.reqMaker.uniqueId.toString() === docId) { 398 | userId = elem.reqMaker.id; 399 | prevReqStatus = elem.reqStatus; 400 | // mongoose unable to see changes in embedded arrays 401 | // check out issue - https://github.com/Automattic/mongoose/issues/1204 402 | elem.reqStatus = 'ACCEPTED'; 403 | } 404 | return elem; 405 | }); 406 | doc.markModified('itemRequests'); 407 | if (prevReqStatus === 'PENDING') { 408 | doc.save(err => { 409 | if (err) { 410 | res.status(500).send('Error happened while accepting trade request!').end(); 411 | console.log('Error happened while accepting trade request!'); 412 | } else { 413 | // remove proposedTrade item = require(the user who made that request. 414 | User.findOne({ _id: userId }) 415 | .exec((err, doc) => { 416 | if (err) { 417 | res.status(500).send('Error happened while declining trade request!').end(); 418 | console.log('Error happened while declining trade request!'); 419 | } else { 420 | doc.trades = doc.trades.map(elem => { 421 | if (elem.id === key) { 422 | elem.reqStatus = "ACCEPTED"; 423 | elem.reqMakerInfo = [req.user.email, req.user.phoneNo]; 424 | } 425 | return elem; 426 | }); 427 | 428 | // for notifications 429 | doc.notificationsCount += 1; 430 | doc.markModified('notificationsCount'); 431 | 432 | doc.markModified('trades'); 433 | doc.save(err => { 434 | if (err) { 435 | res.status(500).send('Error happened while declining trade request!').end(); 436 | console.log('Error happened while declining trade request!'); 437 | } else { 438 | res.json({ status: 'OK' }); 439 | } 440 | }); 441 | } 442 | }); 443 | } 444 | }); 445 | } else { 446 | res.json({ status: 'Trade request is already accepted!' }); 447 | } 448 | } 449 | }); 450 | 451 | }); 452 | 453 | }; 454 | -------------------------------------------------------------------------------- /server/authRoutes.js: -------------------------------------------------------------------------------- 1 | module.exports = function (app, passport) { 2 | 3 | const saveQueryVar = (req, res, next) => { 4 | const last_item= req.query.l_i; 5 | if(last_item) { 6 | req.session.returnTo = last_item; 7 | } 8 | next(); 9 | }; 10 | 11 | // route for facebook authentication and login 12 | app.get('/auth/facebook', saveQueryVar, passport.authenticate('facebook', { scope: 'email' })); 13 | 14 | // handle the callback after facebook has authenticated the user 15 | app.get('/auth/facebook/callback', 16 | passport.authenticate('facebook', { 17 | failureRedirect: '/login' 18 | }), 19 | function (req, res) { 20 | const {email, phoneNo} = req.user; 21 | const redirectPath = email.concat(phoneNo) ? '/': '/profile?message=fillProfileInfo'; 22 | 23 | res.redirect(req.session.returnTo || redirectPath); 24 | delete req.session.returnTo; 25 | req.session.save(); 26 | }); 27 | 28 | // route for twitter authentication and login 29 | app.get('/auth/twitter', saveQueryVar, passport.authenticate('twitter')); 30 | 31 | // handle the callback after twitter has authenticated the user 32 | app.get('/auth/twitter/callback', 33 | passport.authenticate('twitter', { 34 | failureRedirect: '/login' 35 | }), 36 | function (req, res) { 37 | const {email, phoneNo} = req.user; 38 | const redirectPath = email.concat(phoneNo) ? '/': '/profile?message=fillProfileInfo'; 39 | 40 | res.redirect(req.session.returnTo || redirectPath); 41 | delete req.session.returnTo; 42 | req.session.save(); 43 | }); 44 | 45 | // route for google authentication and login 46 | app.get('/auth/google', saveQueryVar, passport.authenticate('google', { scope: ['profile', 'email'] })); 47 | 48 | // the callback after google has authenticated the user 49 | app.get('/auth/google/callback', 50 | passport.authenticate('google', { 51 | failureRedirect: '/login' 52 | }), 53 | function (req, res) { 54 | const {email, phoneNo} = req.user; 55 | const redirectPath = email.concat(phoneNo) ? '/': '/profile?message=fillProfileInfo'; 56 | 57 | res.redirect(req.session.returnTo || redirectPath); 58 | delete req.session.returnTo; 59 | req.session.save(); 60 | }); 61 | 62 | }; 63 | -------------------------------------------------------------------------------- /server/logoutRoute.js: -------------------------------------------------------------------------------- 1 | module.exports = function (app) { 2 | app.post('/logout', function (req, res) { 3 | req.logout(); 4 | res.sendStatus(200); 5 | }); 6 | }; 7 | -------------------------------------------------------------------------------- /src/actions/allItemsActions.js: -------------------------------------------------------------------------------- 1 | // import * as types from '../constants/actionTypes'; 2 | // import fetch from 'unfetch'; 3 | // import objectAssign from 'object-assign'; 4 | 5 | // export function addMyItem(itemData) { 6 | // return (dispatch) => { 7 | // fetch('/api/addMyItem', { 8 | // method: 'POST', 9 | // body: JSON.stringify(itemData), 10 | // headers: { 11 | // 'Accept': 'application/json', 12 | // 'Content-Type': 'application/json', 13 | // 'Cache': 'no-cache' 14 | // }, 15 | // credentials: 'same-origin' 16 | // }) 17 | // .then(response => { 18 | // if (response.status >= 400) { 19 | // throw new Error(response); 20 | // } else { 21 | // return response.json(); 22 | // } 23 | // }) 24 | // .then(data => { 25 | // dispatch( 26 | // { 27 | // type: types.ADD_MY_ITEM, 28 | // payload: data 29 | // } 30 | // ); 31 | // }) 32 | // .catch(err => { 33 | // /* eslint-disable no-console */ 34 | // console.error(`Got error:${err} while dispatching ADD_MY_ITEM!`); 35 | // }); 36 | // }; 37 | // } 38 | 39 | -------------------------------------------------------------------------------- /src/actions/appActions.js: -------------------------------------------------------------------------------- 1 | import * as types from '../constants/actionTypes'; 2 | 3 | export function updateAppState(appData) { 4 | return (dispatch) => { 5 | dispatch( 6 | { 7 | type: types.UPDATE_APP_STATE, 8 | payload: appData 9 | } 10 | ); 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /src/actions/commonActions.js: -------------------------------------------------------------------------------- 1 | /*eslint import/namespace: ['error', { allowComputed: true }]*/ 2 | import * as types from '../constants/actionTypes'; 3 | import fetch from 'unfetch'; 4 | 5 | const captialize = str => str[0].toUpperCase() + str.slice(1); 6 | 7 | export function getInitialState(cb, page) { 8 | return (dispatch) => { 9 | fetch(`/api/get${captialize(page)}Data`, { 10 | method: 'GET', 11 | headers: { 12 | 'Accept': 'application/json', 13 | 'Content-Type': 'application/json', 14 | 'Cache': 'no-cache' 15 | }, 16 | credentials: 'same-origin' 17 | }) 18 | .then(response => { 19 | if (response.status >= 400) { 20 | throw new Error(response); 21 | } else { 22 | return response.json(); 23 | } 24 | }) 25 | .then(data => { 26 | dispatch( 27 | { 28 | type: types[`GET_INITIAL_${page.toUpperCase()}_STATE`], 29 | payload: data 30 | } 31 | ); 32 | cb(); 33 | }) 34 | .catch(err => { 35 | /* eslint-disable no-console */ 36 | console.error(`Got error:${err} while dispatching GET_INITIAL_${page.toUpperCase()}_STATE!`); 37 | cb(); 38 | }); 39 | }; 40 | } 41 | -------------------------------------------------------------------------------- /src/actions/individualItemActions.js: -------------------------------------------------------------------------------- 1 | /*eslint import/namespace: ['error', { allowComputed: true }]*/ 2 | import * as types from '../constants/actionTypes'; 3 | import fetch from 'unfetch'; 4 | 5 | const captialize = str => str[0].toUpperCase() + str.slice(1); 6 | 7 | export function loadIndividualItemState(cb, replace, page, id) { 8 | return (dispatch) => { 9 | fetch(`/api/get${captialize(page)}Data/${id}`, { 10 | method: 'GET', 11 | headers: { 12 | 'Accept': 'application/json', 13 | 'Content-Type': 'application/json', 14 | 'Cache': 'no-cache' 15 | }, 16 | credentials: 'same-origin' 17 | }) 18 | .then(response => { 19 | if (response.status >= 400) { 20 | throw new Error(response); 21 | } else { 22 | return response.json(); 23 | } 24 | }) 25 | .then(data => { 26 | dispatch( 27 | { 28 | type: types[`GET_INITIAL_${page.toUpperCase()}_STATE`], 29 | payload: data 30 | } 31 | ); 32 | cb(); 33 | }) 34 | .catch(err => { 35 | /* eslint-disable no-console */ 36 | console.error(`Got error:${err} while dispatching GET_INITIAL_${page.toUpperCase()}_STATE!`); 37 | replace({ 38 | pathname: '/pagenotfound', 39 | state: { nextPathname: `/item/${id}` } 40 | }); 41 | cb(); 42 | }); 43 | }; 44 | } 45 | 46 | export function requestItem(id, showErrMsg) { 47 | return (dispatch) => { 48 | fetch(`/api/requestitem/${id}`, { 49 | method: 'GET', 50 | headers: { 51 | 'Accept': 'application/json', 52 | 'Content-Type': 'application/json', 53 | 'Cache': 'no-cache' 54 | }, 55 | credentials: 'same-origin' 56 | }) 57 | .then(response => { 58 | if (response.status >= 400) { 59 | throw new Error(response); 60 | } else { 61 | return response.json(); 62 | } 63 | }) 64 | .then(data => { 65 | dispatch( 66 | { 67 | type: types[`UPDATE_INDIVIDUALITEM_STATE`], 68 | payload: data 69 | } 70 | ); 71 | }) 72 | .catch(err => { 73 | /* eslint-disable no-console */ 74 | showErrMsg('Sorry, item can\'t be requested. Try Again!'); 75 | console.error(`Got error:${err} while requesting item!`); 76 | }); 77 | }; 78 | } 79 | -------------------------------------------------------------------------------- /src/actions/myItemsActions.js: -------------------------------------------------------------------------------- 1 | import * as types from '../constants/actionTypes'; 2 | import fetch from 'unfetch'; 3 | import objectAssign from 'object-assign'; 4 | 5 | export function addMyItem(itemData, closeModal, showErrorMsg, hideWaitingMsg) { 6 | return (dispatch) => { 7 | fetch('/api/addMyItem', { 8 | method: 'POST', 9 | body: itemData, 10 | headers: { 11 | 'Accept': 'application/json', 12 | 'Cache': 'no-cache' 13 | }, 14 | credentials: 'same-origin' 15 | }) 16 | .then(response => { 17 | if (response.status >= 400) { 18 | throw new Error(response.statusText); 19 | } else { 20 | return response.json(); 21 | } 22 | }) 23 | .then(data => { 24 | dispatch( 25 | { 26 | type: types.ADD_MY_ITEM, 27 | payload: data 28 | } 29 | ); 30 | hideWaitingMsg(); 31 | closeModal(); 32 | }) 33 | .catch(err => { 34 | /* eslint-disable no-console */ 35 | hideWaitingMsg(); 36 | console.log(err); 37 | showErrorMsg(`Sorry! Your item can\'t be created. Try again!`); 38 | console.error(`Got error:${err} while dispatching ADD_MY_ITEM!`); 39 | }); 40 | }; 41 | } 42 | 43 | export function deleteMyItem(key, node) { 44 | return (dispatch) => { 45 | fetch(`/api/deleteMyItem/${key}`, { 46 | method: 'DELETE', 47 | headers: { 48 | 'Accept': 'application/json', 49 | 'Content-Type': 'application/json', 50 | 'Cache': 'no-cache' 51 | }, 52 | credentials: 'same-origin' 53 | }) 54 | .then(response => { 55 | if (response.status >= 400) { 56 | throw new Error(response); 57 | } else { 58 | // hides item in fancy way 59 | objectAssign(node.style, { opacity: "0", marginBottom: `-${node.offsetHeight + 14}px`, zIndex: '-22' }); 60 | setTimeout(() => { 61 | dispatch({ 62 | type: types.DELETE_MY_ITEM, 63 | payload: key 64 | }); 65 | }, 1000); 66 | } 67 | }) 68 | .catch(err => { 69 | /* eslint-disable no-console */ 70 | console.error(`Got error:${err} while dispatching DELETE_MY_ITEM!`); 71 | }); 72 | }; 73 | } 74 | -------------------------------------------------------------------------------- /src/actions/profileActions.js: -------------------------------------------------------------------------------- 1 | import * as types from '../constants/actionTypes'; 2 | import fetch from 'unfetch'; 3 | 4 | export function updateProfileState(changedState, editSection) { 5 | return (dispatch) => { 6 | fetch(`/api/setProfileData?edit=${editSection}`, { 7 | method: 'POST', 8 | body: JSON.stringify(changedState), 9 | headers: { 10 | 'Accept': 'application/json', 11 | 'Content-Type': 'application/json', 12 | 'Cache': 'no-cache' 13 | }, 14 | credentials: 'same-origin' 15 | }) 16 | .then(response => { 17 | if (response.status >= 400) { 18 | throw new Error(response); 19 | } else { 20 | return response.json(); 21 | } 22 | }) 23 | .then(profileData => dispatch( 24 | { 25 | type: types.UPDATE_PROFILE_STATE, 26 | payload: profileData 27 | } 28 | )) 29 | .catch(err => { 30 | /* eslint-disable no-console */ 31 | console.error(`Got error:${err} while dispatching UPDATE_PROFILE_INFO!`); 32 | }); 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /src/actions/tradeActions.js: -------------------------------------------------------------------------------- 1 | import * as types from '../constants/actionTypes'; 2 | import fetch from 'unfetch'; 3 | import objectAssign from 'object-assign'; 4 | 5 | export function acceptTrade(key, docId, btn1, btn2) { 6 | return (dispatch) => { 7 | fetch('/api/acceptrequest', { 8 | method: 'POST', 9 | body: JSON.stringify({ key, docId }), 10 | headers: { 11 | 'Accept': 'application/json', 12 | 'Content-Type': 'application/json', 13 | 'Cache': 'no-cache' 14 | }, 15 | credentials: 'same-origin' 16 | }) 17 | .then(response => { 18 | if (response.status >= 400) { 19 | throw new Error(response); 20 | } else { 21 | return response.json(); 22 | } 23 | }) 24 | .then(res => { 25 | if(res.status === 'OK') { 26 | dispatch( 27 | { 28 | type: types.ACCEPT_TRADE_REQ, 29 | payload: docId 30 | } 31 | ); 32 | } 33 | }) 34 | .catch(err => { 35 | /* eslint-disable no-console */ 36 | btn1.classList.remove('disabled'); 37 | btn2.classList.remove('disabled'); 38 | console.error(`Got error:${err} while dispatching ACCEPT_TRADE_REQ!`); 39 | }); 40 | }; 41 | } 42 | 43 | export function declineTradeReq(key, docId, node, btn1, btn2) { 44 | return (dispatch) => { 45 | fetch('/api/declinerequest', { 46 | method: 'POST', 47 | body: JSON.stringify({ key, docId }), 48 | headers: { 49 | 'Accept': 'application/json', 50 | 'Content-Type': 'application/json', 51 | 'Cache': 'no-cache' 52 | }, 53 | credentials: 'same-origin' 54 | }) 55 | .then(response => { 56 | if (response.status >= 400) { 57 | throw new Error(response); 58 | } else { 59 | return response.json(); 60 | } 61 | }) 62 | .then(res => { 63 | if (res.status === 'OK') { 64 | objectAssign(node.style, { opacity: "0", marginBottom: `-${node.offsetHeight}px`, zIndex: '-22' }); 65 | setTimeout(() => { 66 | dispatch({ 67 | type: types.UPDATE_TRADEREQUESTS_STATE, 68 | payload: docId 69 | }); 70 | }, 1000); 71 | } 72 | }) 73 | .catch(err => { 74 | /* eslint-disable no-console */ 75 | node.classList.remove('blacklisted'); 76 | btn1.classList.remove('disabled'); 77 | btn2.classList.remove('disabled'); 78 | console.error(`Got error:${err} while dispatching DECLINE_TRADE_REQ!`); 79 | }); 80 | }; 81 | } 82 | 83 | export function cancelTradeProposed(id, node, btn) { 84 | return (dispatch) => { 85 | fetch(`/api/removeitemrequest`, { 86 | method: 'POST', 87 | body: JSON.stringify({ id }), 88 | headers: { 89 | 'Accept': 'application/json', 90 | 'Content-Type': 'application/json', 91 | 'Cache': 'no-cache' 92 | }, 93 | credentials: 'same-origin' 94 | }) 95 | .then(response => { 96 | if (response.status >= 400) { 97 | throw new Error(response); 98 | } else { 99 | return response.json(); 100 | } 101 | }) 102 | .then(data => { 103 | objectAssign(node.style, { opacity: "0", marginBottom: `-${node.offsetHeight}px`, zIndex: '-22' }); 104 | setTimeout(() => { 105 | dispatch({ 106 | type: types.UPDATE_TRADE_STATE, 107 | payload: data 108 | }); 109 | }, 1000); 110 | }) 111 | .catch(err => { 112 | /* eslint-disable no-console */ 113 | btn.classList.remove('disabled'); 114 | btn.disabled = false; 115 | node.classList.remove('blacklisted'); 116 | console.error(`Got error:${err} while dispatching CANCEL_TRADE_REQ!`); 117 | }); 118 | }; 119 | } 120 | -------------------------------------------------------------------------------- /src/assets/fonts/fonts.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'robotoblack'; 3 | src: url('roboto-black-webfont.woff2') format('woff2'), 4 | url('roboto-black-webfont.woff') format('woff'); 5 | font-weight: normal; 6 | font-style: normal; 7 | 8 | } 9 | 10 | 11 | 12 | 13 | @font-face { 14 | font-family: 'robotoblack_italic'; 15 | src: url('roboto-blackitalic-webfont.woff2') format('woff2'), 16 | url('roboto-blackitalic-webfont.woff') format('woff'); 17 | font-weight: normal; 18 | font-style: normal; 19 | 20 | } 21 | 22 | 23 | 24 | 25 | @font-face { 26 | font-family: 'robotobold'; 27 | src: url('roboto-bold-webfont.woff2') format('woff2'), 28 | url('roboto-bold-webfont.woff') format('woff'); 29 | font-weight: normal; 30 | font-style: normal; 31 | 32 | } 33 | 34 | 35 | 36 | 37 | @font-face { 38 | font-family: 'robotobold_italic'; 39 | src: url('roboto-bolditalic-webfont.woff2') format('woff2'), 40 | url('roboto-bolditalic-webfont.woff') format('woff'); 41 | font-weight: normal; 42 | font-style: normal; 43 | 44 | } 45 | 46 | 47 | 48 | 49 | @font-face { 50 | font-family: 'robotoitalic'; 51 | src: url('roboto-italic-webfont.woff2') format('woff2'), 52 | url('roboto-italic-webfont.woff') format('woff'); 53 | font-weight: normal; 54 | font-style: normal; 55 | 56 | } 57 | 58 | 59 | 60 | 61 | @font-face { 62 | font-family: 'robotolight'; 63 | src: url('roboto-light-webfont.woff2') format('woff2'), 64 | url('roboto-light-webfont.woff') format('woff'); 65 | font-weight: normal; 66 | font-style: normal; 67 | 68 | } 69 | 70 | 71 | 72 | 73 | @font-face { 74 | font-family: 'robotolight_italic'; 75 | src: url('roboto-lightitalic-webfont.woff2') format('woff2'), 76 | url('roboto-lightitalic-webfont.woff') format('woff'); 77 | font-weight: normal; 78 | font-style: normal; 79 | 80 | } 81 | 82 | 83 | 84 | 85 | @font-face { 86 | font-family: 'robotomedium'; 87 | src: url('roboto-medium-webfont.woff2') format('woff2'), 88 | url('roboto-medium-webfont.woff') format('woff'); 89 | font-weight: normal; 90 | font-style: normal; 91 | 92 | } 93 | 94 | 95 | 96 | 97 | @font-face { 98 | font-family: 'robotomedium_italic'; 99 | src: url('roboto-mediumitalic-webfont.woff2') format('woff2'), 100 | url('roboto-mediumitalic-webfont.woff') format('woff'); 101 | font-weight: normal; 102 | font-style: normal; 103 | 104 | } 105 | 106 | 107 | 108 | 109 | @font-face { 110 | font-family: 'roboto_monobold'; 111 | src: url('robotomono-bold-webfont.woff2') format('woff2'), 112 | url('robotomono-bold-webfont.woff') format('woff'); 113 | font-weight: normal; 114 | font-style: normal; 115 | 116 | } 117 | 118 | 119 | 120 | 121 | @font-face { 122 | font-family: 'roboto_monobold_italic'; 123 | src: url('robotomono-bolditalic-webfont.woff2') format('woff2'), 124 | url('robotomono-bolditalic-webfont.woff') format('woff'); 125 | font-weight: normal; 126 | font-style: normal; 127 | 128 | } 129 | 130 | 131 | 132 | 133 | @font-face { 134 | font-family: 'roboto_monoitalic'; 135 | src: url('robotomono-italic-webfont.woff2') format('woff2'), 136 | url('robotomono-italic-webfont.woff') format('woff'); 137 | font-weight: normal; 138 | font-style: normal; 139 | 140 | } 141 | 142 | @font-face { 143 | font-family: 'roboto_monolight'; 144 | src: url('robotomono-light-webfont.woff2') format('woff2'), 145 | url('robotomono-light-webfont.woff') format('woff'); 146 | font-weight: normal; 147 | font-style: normal; 148 | 149 | } 150 | 151 | 152 | 153 | 154 | @font-face { 155 | font-family: 'roboto_monolight_italic'; 156 | src: url('robotomono-lightitalic-webfont.woff2') format('woff2'), 157 | url('robotomono-lightitalic-webfont.woff') format('woff'); 158 | font-weight: normal; 159 | font-style: normal; 160 | 161 | } 162 | 163 | 164 | 165 | 166 | @font-face { 167 | font-family: 'roboto_monomedium'; 168 | src: url('robotomono-medium-webfont.woff2') format('woff2'), 169 | url('robotomono-medium-webfont.woff') format('woff'); 170 | font-weight: normal; 171 | font-style: normal; 172 | 173 | } 174 | 175 | 176 | 177 | 178 | @font-face { 179 | font-family: 'roboto_monomedium_italic'; 180 | src: url('robotomono-mediumitalic-webfont.woff2') format('woff2'), 181 | url('robotomono-mediumitalic-webfont.woff') format('woff'); 182 | font-weight: normal; 183 | font-style: normal; 184 | 185 | } 186 | 187 | 188 | 189 | 190 | @font-face { 191 | font-family: 'roboto_monoregular'; 192 | src: url('robotomono-regular-webfont.woff2') format('woff2'), 193 | url('robotomono-regular-webfont.woff') format('woff'); 194 | font-weight: normal; 195 | font-style: normal; 196 | 197 | } 198 | 199 | 200 | 201 | 202 | @font-face { 203 | font-family: 'roboto_monothin'; 204 | src: url('robotomono-thin-webfont.woff2') format('woff2'), 205 | url('robotomono-thin-webfont.woff') format('woff'); 206 | font-weight: normal; 207 | font-style: normal; 208 | 209 | } 210 | 211 | 212 | 213 | 214 | @font-face { 215 | font-family: 'roboto_monothin_italic'; 216 | src: url('robotomono-thinitalic-webfont.woff2') format('woff2'), 217 | url('robotomono-thinitalic-webfont.woff') format('woff'); 218 | font-weight: normal; 219 | font-style: normal; 220 | 221 | } 222 | 223 | 224 | 225 | 226 | @font-face { 227 | font-family: 'robotoregular'; 228 | src: url('roboto-regular-webfont.woff2') format('woff2'), 229 | url('roboto-regular-webfont.woff') format('woff'); 230 | font-weight: normal; 231 | font-style: normal; 232 | 233 | } 234 | 235 | 236 | 237 | 238 | @font-face { 239 | font-family: 'robotothin'; 240 | src: url('roboto-thin-webfont.woff2') format('woff2'), 241 | url('roboto-thin-webfont.woff') format('woff'); 242 | font-weight: normal; 243 | font-style: normal; 244 | 245 | } 246 | 247 | 248 | 249 | 250 | @font-face { 251 | font-family: 'robotothin_italic'; 252 | src: url('roboto-thinitalic-webfont.woff2') format('woff2'), 253 | url('roboto-thinitalic-webfont.woff') format('woff'); 254 | font-weight: normal; 255 | font-style: normal; 256 | 257 | } 258 | -------------------------------------------------------------------------------- /src/assets/fonts/roboto-black-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/roboto-black-webfont.woff -------------------------------------------------------------------------------- /src/assets/fonts/roboto-black-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/roboto-black-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/roboto-blackitalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/roboto-blackitalic-webfont.woff -------------------------------------------------------------------------------- /src/assets/fonts/roboto-blackitalic-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/roboto-blackitalic-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/roboto-bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/roboto-bold-webfont.woff -------------------------------------------------------------------------------- /src/assets/fonts/roboto-bold-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/roboto-bold-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/roboto-bolditalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/roboto-bolditalic-webfont.woff -------------------------------------------------------------------------------- /src/assets/fonts/roboto-bolditalic-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/roboto-bolditalic-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/roboto-italic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/roboto-italic-webfont.woff -------------------------------------------------------------------------------- /src/assets/fonts/roboto-italic-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/roboto-italic-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/roboto-light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/roboto-light-webfont.woff -------------------------------------------------------------------------------- /src/assets/fonts/roboto-light-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/roboto-light-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/roboto-lightitalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/roboto-lightitalic-webfont.woff -------------------------------------------------------------------------------- /src/assets/fonts/roboto-lightitalic-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/roboto-lightitalic-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/roboto-medium-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/roboto-medium-webfont.woff -------------------------------------------------------------------------------- /src/assets/fonts/roboto-medium-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/roboto-medium-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/roboto-mediumitalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/roboto-mediumitalic-webfont.woff -------------------------------------------------------------------------------- /src/assets/fonts/roboto-mediumitalic-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/roboto-mediumitalic-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/roboto-regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/roboto-regular-webfont.woff -------------------------------------------------------------------------------- /src/assets/fonts/roboto-regular-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/roboto-regular-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/roboto-thin-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/roboto-thin-webfont.woff -------------------------------------------------------------------------------- /src/assets/fonts/roboto-thin-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/roboto-thin-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/roboto-thinitalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/roboto-thinitalic-webfont.woff -------------------------------------------------------------------------------- /src/assets/fonts/roboto-thinitalic-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/roboto-thinitalic-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/robotomono-bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/robotomono-bold-webfont.woff -------------------------------------------------------------------------------- /src/assets/fonts/robotomono-bold-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/robotomono-bold-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/robotomono-bolditalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/robotomono-bolditalic-webfont.woff -------------------------------------------------------------------------------- /src/assets/fonts/robotomono-bolditalic-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/robotomono-bolditalic-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/robotomono-italic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/robotomono-italic-webfont.woff -------------------------------------------------------------------------------- /src/assets/fonts/robotomono-italic-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/robotomono-italic-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/robotomono-light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/robotomono-light-webfont.woff -------------------------------------------------------------------------------- /src/assets/fonts/robotomono-light-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/robotomono-light-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/robotomono-lightitalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/robotomono-lightitalic-webfont.woff -------------------------------------------------------------------------------- /src/assets/fonts/robotomono-lightitalic-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/robotomono-lightitalic-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/robotomono-medium-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/robotomono-medium-webfont.woff -------------------------------------------------------------------------------- /src/assets/fonts/robotomono-medium-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/robotomono-medium-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/robotomono-mediumitalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/robotomono-mediumitalic-webfont.woff -------------------------------------------------------------------------------- /src/assets/fonts/robotomono-mediumitalic-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/robotomono-mediumitalic-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/robotomono-regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/robotomono-regular-webfont.woff -------------------------------------------------------------------------------- /src/assets/fonts/robotomono-regular-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/robotomono-regular-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/robotomono-thin-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/robotomono-thin-webfont.woff -------------------------------------------------------------------------------- /src/assets/fonts/robotomono-thin-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/robotomono-thin-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/robotomono-thinitalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/robotomono-thinitalic-webfont.woff -------------------------------------------------------------------------------- /src/assets/fonts/robotomono-thinitalic-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/fonts/robotomono-thinitalic-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/images/addItemPic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/assets/images/arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/images/fileUpload.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/images/logo.png -------------------------------------------------------------------------------- /src/assets/images/plain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ar5had/trader/4bec083791afc117cbc034bb41d26b572c643106/src/assets/images/plain.png -------------------------------------------------------------------------------- /src/assets/images/user.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/components/AddItemPage/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | 3 | import './styles.sass'; 4 | 5 | const isCurrencyValid = val => ( 6 | val === "₹-INR" || 7 | val === "$-DOLLAR" || 8 | val === "€-EURO" || 9 | val === "£-POUND" 10 | ); 11 | 12 | const isPriceValid = val => (!isNaN(val) && !isNaN(parseInt(val, 10))); 13 | 14 | const scrollElemToTop = (elem) => { 15 | if (elem.scrollTop != 0) { 16 | elem.scrollTop -= 50; 17 | setTimeout(scrollElemToTop, 10, elem); 18 | } 19 | }; 20 | 21 | class AddItemPage extends Component { 22 | constructor(props) { 23 | super(props); 24 | this.state = { 25 | errorMsg: null, 26 | showWaitingMsg: false 27 | }; 28 | } 29 | 30 | componentDidMount() { 31 | setTimeout(() => { 32 | this.modalWrapper.classList.add(this.props.openClass); 33 | }, 50); 34 | } 35 | 36 | close() { 37 | this.modalWrapper.classList.remove(this.props.openClass); 38 | setTimeout(() => { 39 | this.props.close(); 40 | }, 550); 41 | } 42 | 43 | handleNewItemFormSubmit(event) { 44 | event.preventDefault(); 45 | const fd = new FormData(); 46 | let emptyFieldMsg; 47 | [].forEach.call(event.target, (elem) => { 48 | if (elem.getAttribute('type') !== 'submit') { 49 | if (elem.getAttribute('type') === 'file') { 50 | if (!elem.files[0] && !emptyFieldMsg) 51 | emptyFieldMsg = 'Please add an item picture!'; 52 | fd.append(elem.getAttribute('name'), elem.files[0]); 53 | } else { 54 | if (!elem.value) 55 | emptyFieldMsg = `Item ${elem.getAttribute('name').slice(4)} is a required field!`; 56 | fd.append(elem.getAttribute('name'), elem.value); 57 | } 58 | } 59 | }); 60 | const currencyValidity = isCurrencyValid(fd.get('itemCurrency')); 61 | const priceValidity = isPriceValid(fd.get('itemPrice')); 62 | 63 | if (emptyFieldMsg) { 64 | return this.showErrorMessage(emptyFieldMsg); 65 | } 66 | 67 | if (currencyValidity && priceValidity) { 68 | this.setState({ errorMsg: '' }); 69 | this.props.addItem( 70 | fd, 71 | this.close.bind(this), 72 | this.showErrorMessage.bind(this), 73 | this.hideWaitingMsg.bind(this) 74 | ); 75 | this.showWaitingMsg(); 76 | } else { 77 | if (!currencyValidity) { 78 | this.showErrorMessage('Enter correct currency from the given list!'); 79 | } else if (!priceValidity) { 80 | this.showErrorMessage('Enter a valid price value!'); 81 | } 82 | } 83 | } 84 | 85 | showErrorMessage(str) { 86 | scrollElemToTop(document.addItemForm); 87 | this.setState({ errorMsg: str }); 88 | } 89 | 90 | showWaitingMsg() { 91 | this.setState({ showWaitingMsg: true }); 92 | } 93 | 94 | hideWaitingMsg() { 95 | this.setState({ showWaitingMsg: false }); 96 | } 97 | 98 | getWaitingMsg() { 99 | if (!this.state.showWaitingMsg) { 100 | return; 101 | } else { 102 | return ( 103 |
104 |
105 |

Hang on tight!

106 |
107 |
108 |
109 |
110 |
111 | ); 112 | } 113 | } 114 | 115 | getErrorMessage() { 116 | if (this.state.errorMsg) { 117 | return ( 118 |
119 |

{this.state.errorMsg}

120 |
121 | ); 122 | } else { 123 | return; 124 | } 125 | } 126 | 127 | saveItem() { 128 | // triggers form submit 129 | this.submitItemFormBtn.click(); 130 | } 131 | 132 | handleItemImgLoad(event) { 133 | const input = event.target; 134 | const file = input.files[0]; 135 | const fr = new FileReader(); 136 | fr.onload = () => { 137 | this.itemImg.classList.add('imgLoaded'); 138 | this.itemImg.style.background = `url( ${fr.result} )`; 139 | }; 140 | if (file) { 141 | const errorElem = document.querySelector('.imgLoadErrors'); 142 | errorElem.innerText = ""; 143 | 144 | if (file.size > 512000) { 145 | errorElem.innerText = 146 | 'Image size is greater than 500kb!'; 147 | } else if (file.type !== 'image/jpeg' && file.type !== 'image/png' 148 | && file.type !== 'image/gif') { 149 | errorElem.innerText = 150 | 'Wrong Image Format! Choose a jpeg or png or gif image file.'; 151 | } else { 152 | fr.readAsDataURL(file); 153 | } 154 | } 155 | } 156 | 157 | render() { 158 | return ( 159 |
{ this.modalWrapper = node; }}> 160 |
161 |
162 | {this.getWaitingMsg()} 163 |
164 |

Add Item

165 |
166 |
171 | {this.getErrorMessage()} 172 |
173 |
174 |
this.itemImg = node} 176 | onClick={() => this.picInput.click()} /> 177 | this.picInput = node} required /> 181 | 186 |

187 |

188 |
189 |
190 | 191 | 192 |
193 |
194 |
195 | 196 | 197 |
198 |
199 | 200 | 201 | 202 | 207 |
208 |
209 |
210 | 211 |