From 7935edd72f2577e342b2d1c23b833d05648b9966 Mon Sep 17 00:00:00 2001 From: EXPITC Date: Tue, 14 Dec 2021 12:30:48 +0700 Subject: [PATCH] final --- package-lock.json | 360 ++++++++++++++++++ package.json | 6 +- src/App.js | 18 +- src/Context/userContext.js | 38 ++ .../AddProduct/AddProduct.styled.js | 13 +- src/components/AddProduct/index.js | 68 +++- src/components/AddResto/AddResto.styled..js | 78 ++++ src/components/AddResto/index.js | 142 +++++++ src/components/CartPage/CartPage.styled.js | 29 +- src/components/CartPage/index.js | 308 ++++++++++----- .../DetailPage/DetailPage.styled.js | 85 +++++ src/components/DetailPage/index.js | 195 +++++++--- src/components/DropDown/index.js | 27 +- .../EditProfile/EditProfile.styled.js | 13 +- src/components/EditProfile/index.js | 118 +++++- src/components/Header/Header.styled.js | 1 - src/components/Header/index.js | 50 ++- .../LandingPage/LandingPage.styled.js | 61 ++- src/components/LandingPage/index.js | 77 ++-- src/components/Login/Login.styled.js | 27 +- src/components/Login/index.js | 57 ++- src/components/Map/index.js | 350 +++++++++++------ .../ProfilePage/ProfilePage.styled.js | 14 +- src/components/ProfilePage/index.js | 108 +++++- src/components/Register/Register.style.js | 178 ++++++--- src/components/Register/index.js | 87 ++++- src/components/Resto/Resto.styled.js | 26 ++ src/components/Resto/index.js | 35 ++ src/components/RouterSetup.js | 60 ++- .../TransactionPage/TransactionPage.styled.js | 9 +- src/components/TransactionPage/index.js | 215 ++++------- src/config/api.js | 30 ++ src/img/disabled.png | Bin 0 -> 9553 bytes src/img/shop.png | Bin 0 -> 15699 bytes src/index.js | 3 +- 35 files changed, 2280 insertions(+), 606 deletions(-) create mode 100644 src/Context/userContext.js create mode 100644 src/components/AddResto/AddResto.styled..js create mode 100644 src/components/AddResto/index.js create mode 100644 src/components/Resto/Resto.styled.js create mode 100644 src/components/Resto/index.js create mode 100644 src/config/api.js create mode 100644 src/img/disabled.png create mode 100644 src/img/shop.png diff --git a/package-lock.json b/package-lock.json index f45bfe2..0eeed1b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,11 +12,15 @@ "@testing-library/jest-dom": "^5.15.0", "@testing-library/react": "^11.2.7", "@testing-library/user-event": "^12.8.3", + "axios": "^0.24.0", + "cors": "^2.8.5", "react": "^17.0.2", "react-dom": "^17.0.2", "react-map-gl": "^6.1.17", "react-router-dom": "^6.0.2", "react-scripts": "4.0.3", + "rupiah-format": "^1.0.0", + "socket.io-client": "^4.4.0", "styled-components": "^5.3.3", "web-vitals": "^1.1.2" } @@ -2938,6 +2942,11 @@ "@sinonjs/commons": "^1.7.0" } }, + "node_modules/@socket.io/component-emitter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.0.0.tgz", + "integrity": "sha512-2pTGuibAXJswAPJjaKisthqS/NOK5ypG4LYT6tEAV0S/mxW0zOIvYvGK0V8w8+SHxAm6vRMSjqSalFXeBAqs+Q==" + }, "node_modules/@surma/rollup-plugin-off-main-thread": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-1.4.2.tgz", @@ -4730,6 +4739,14 @@ "inherits": "2.0.1" } }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "engines": { + "node": "*" + } + }, "node_modules/assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", @@ -4827,6 +4844,14 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz", + "integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==", + "dependencies": { + "follow-redirects": "^1.14.4" + } + }, "node_modules/axobject-query": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", @@ -5732,6 +5757,11 @@ "babylon": "bin/babylon.js" } }, + "node_modules/backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -5765,6 +5795,14 @@ "node": ">=0.10.0" } }, + "node_modules/base64-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.1.tgz", + "integrity": "sha512-vFIUq7FdLtjZMhATwDul5RZWv2jpXQ09Pd6jcVEOvIsqCWTRFD/ONHNfyOS8dA/Ippi5dsIgpyKWKZaAKZltbA==", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -6487,6 +6525,27 @@ "node": ">=4" } }, + "node_modules/chai": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", + "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", + "dependencies": { + "assertion-error": "^1.0.1", + "deep-eql": "^0.1.3", + "type-detect": "^1.0.0" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/chai/node_modules/type-detect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", + "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=", + "engines": { + "node": "*" + } + }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -7012,6 +7071,18 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/cosmiconfig": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", @@ -7635,6 +7706,25 @@ "node": ">=0.10.0" } }, + "node_modules/deep-eql": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", + "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", + "dependencies": { + "type-detect": "0.1.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/deep-eql/node_modules/type-detect": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", + "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=", + "engines": { + "node": "*" + } + }, "node_modules/deep-equal": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", @@ -8268,6 +8358,53 @@ "once": "^1.4.0" } }, + "node_modules/engine.io-client": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.1.1.tgz", + "integrity": "sha512-V05mmDo4gjimYW+FGujoGmmmxRaDsrVr7AXA3ZIfa04MWM1jOfZfUwou0oNqhNwy/votUDvGDt4JA4QF4e0b4g==", + "dependencies": { + "@socket.io/component-emitter": "~3.0.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.0", + "has-cors": "1.1.0", + "parseqs": "0.0.6", + "parseuri": "0.0.6", + "ws": "~8.2.3", + "xmlhttprequest-ssl": "~2.0.0", + "yeast": "0.1.2" + } + }, + "node_modules/engine.io-client/node_modules/ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/engine.io-parser": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.2.tgz", + "integrity": "sha512-wuiO7qO/OEkPJSFueuATIXtrxF7/6GTbAO9QLv7nnbjwZ5tYhLm9zxvLwxstRs0dcT0KUlWTjtIOs1T86jt12g==", + "dependencies": { + "base64-arraybuffer": "~1.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/enhanced-resolve": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", @@ -10648,6 +10785,11 @@ "node": ">=0.10.0" } }, + "node_modules/has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -15634,6 +15776,16 @@ "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" }, + "node_modules/parseqs": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz", + "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==" + }, + "node_modules/parseuri": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz", + "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==" + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -18641,6 +18793,17 @@ "aproba": "^1.1.1" } }, + "node_modules/rupiah-format": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rupiah-format/-/rupiah-format-1.0.0.tgz", + "integrity": "sha1-GWTxA4Ipeg9GQFQVngOD87gVt2U=", + "dependencies": { + "chai": "^3.5.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/rw": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", @@ -19555,6 +19718,34 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "node_modules/socket.io-client": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.4.0.tgz", + "integrity": "sha512-g7riSEJXi7qCFImPow98oT8X++MSsHz6MMFRXkWNJ6uEROSHOa3kxdrsYWMq85dO+09CFMkcqlpjvbVXQl4z6g==", + "dependencies": { + "@socket.io/component-emitter": "~3.0.0", + "backo2": "~1.0.2", + "debug": "~4.3.2", + "engine.io-client": "~6.1.1", + "parseuri": "0.0.6", + "socket.io-parser": "~4.1.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.1.1.tgz", + "integrity": "sha512-USQVLSkDWE5nbcY760ExdKaJxCE65kcsG/8k5FDGZVVxpD1pA7hABYXYkCUvxUuYYh/+uQw0N/fvBzfT8o07KA==", + "dependencies": { + "@socket.io/component-emitter": "~3.0.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/sockjs": { "version": "0.3.21", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.21.tgz", @@ -23673,6 +23864,14 @@ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -23740,6 +23939,11 @@ "node": ">=6" } }, + "node_modules/yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -25825,6 +26029,11 @@ "@sinonjs/commons": "^1.7.0" } }, + "@socket.io/component-emitter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.0.0.tgz", + "integrity": "sha512-2pTGuibAXJswAPJjaKisthqS/NOK5ypG4LYT6tEAV0S/mxW0zOIvYvGK0V8w8+SHxAm6vRMSjqSalFXeBAqs+Q==" + }, "@surma/rollup-plugin-off-main-thread": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-1.4.2.tgz", @@ -27188,6 +27397,11 @@ } } }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==" + }, "assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", @@ -27262,6 +27476,14 @@ "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.5.tgz", "integrity": "sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA==" }, + "axios": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz", + "integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==", + "requires": { + "follow-redirects": "^1.14.4" + } + }, "axobject-query": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", @@ -28027,6 +28249,11 @@ "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -28056,6 +28283,11 @@ } } }, + "base64-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.1.tgz", + "integrity": "sha512-vFIUq7FdLtjZMhATwDul5RZWv2jpXQ09Pd6jcVEOvIsqCWTRFD/ONHNfyOS8dA/Ippi5dsIgpyKWKZaAKZltbA==" + }, "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -28635,6 +28867,23 @@ "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.3.0.tgz", "integrity": "sha512-/4YgnZS8y1UXXmC02xD5rRrBEu6T5ub+mQHLNRj0fzTRbgdBYhsNo2V5EqwgqrExjxsjtF/OpAKAMkKsxbD5XQ==" }, + "chai": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", + "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", + "requires": { + "assertion-error": "^1.0.1", + "deep-eql": "^0.1.3", + "type-detect": "^1.0.0" + }, + "dependencies": { + "type-detect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", + "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=" + } + } + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -29061,6 +29310,15 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, "cosmiconfig": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", @@ -29550,6 +29808,21 @@ "is-obj": "^1.0.0" } }, + "deep-eql": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", + "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", + "requires": { + "type-detect": "0.1.1" + }, + "dependencies": { + "type-detect": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", + "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=" + } + } + }, "deep-equal": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", @@ -30055,6 +30328,38 @@ "once": "^1.4.0" } }, + "engine.io-client": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.1.1.tgz", + "integrity": "sha512-V05mmDo4gjimYW+FGujoGmmmxRaDsrVr7AXA3ZIfa04MWM1jOfZfUwou0oNqhNwy/votUDvGDt4JA4QF4e0b4g==", + "requires": { + "@socket.io/component-emitter": "~3.0.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.0", + "has-cors": "1.1.0", + "parseqs": "0.0.6", + "parseuri": "0.0.6", + "ws": "~8.2.3", + "xmlhttprequest-ssl": "~2.0.0", + "yeast": "0.1.2" + }, + "dependencies": { + "ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "requires": {} + } + } + }, + "engine.io-parser": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.2.tgz", + "integrity": "sha512-wuiO7qO/OEkPJSFueuATIXtrxF7/6GTbAO9QLv7nnbjwZ5tYhLm9zxvLwxstRs0dcT0KUlWTjtIOs1T86jt12g==", + "requires": { + "base64-arraybuffer": "~1.0.1" + } + }, "enhanced-resolve": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", @@ -31851,6 +32156,11 @@ "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=", "peer": true }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -35631,6 +35941,16 @@ "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" }, + "parseqs": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz", + "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==" + }, + "parseuri": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz", + "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==" + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -38049,6 +38369,14 @@ "aproba": "^1.1.1" } }, + "rupiah-format": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rupiah-format/-/rupiah-format-1.0.0.tgz", + "integrity": "sha1-GWTxA4Ipeg9GQFQVngOD87gVt2U=", + "requires": { + "chai": "^3.5.0" + } + }, "rw": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", @@ -38788,6 +39116,28 @@ } } }, + "socket.io-client": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.4.0.tgz", + "integrity": "sha512-g7riSEJXi7qCFImPow98oT8X++MSsHz6MMFRXkWNJ6uEROSHOa3kxdrsYWMq85dO+09CFMkcqlpjvbVXQl4z6g==", + "requires": { + "@socket.io/component-emitter": "~3.0.0", + "backo2": "~1.0.2", + "debug": "~4.3.2", + "engine.io-client": "~6.1.1", + "parseuri": "0.0.6", + "socket.io-parser": "~4.1.1" + } + }, + "socket.io-parser": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.1.1.tgz", + "integrity": "sha512-USQVLSkDWE5nbcY760ExdKaJxCE65kcsG/8k5FDGZVVxpD1pA7hABYXYkCUvxUuYYh/+uQw0N/fvBzfT8o07KA==", + "requires": { + "@socket.io/component-emitter": "~3.0.0", + "debug": "~4.3.1" + } + }, "sockjs": { "version": "0.3.21", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.21.tgz", @@ -42061,6 +42411,11 @@ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" }, + "xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==" + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -42115,6 +42470,11 @@ } } }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + }, "yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 26b5436..13ca52a 100644 --- a/package.json +++ b/package.json @@ -3,15 +3,19 @@ "version": "0.1.0", "private": true, "dependencies": { + "@mapbox/mapbox-gl-directions": "^4.0.3", "@testing-library/jest-dom": "^5.15.0", "@testing-library/react": "^11.2.7", "@testing-library/user-event": "^12.8.3", - "@mapbox/mapbox-gl-directions": "^4.0.3", + "axios": "^0.24.0", + "cors": "^2.8.5", "react": "^17.0.2", "react-dom": "^17.0.2", "react-map-gl": "^6.1.17", "react-router-dom": "^6.0.2", "react-scripts": "4.0.3", + "rupiah-format": "^1.0.0", + "socket.io-client": "^4.4.0", "styled-components": "^5.3.3", "web-vitals": "^1.1.2" }, diff --git a/src/App.js b/src/App.js index 676024f..2c6cb95 100644 --- a/src/App.js +++ b/src/App.js @@ -1,14 +1,20 @@ //style import { GlobalStyles } from './GlobalStyles'; import RouterSetup from './components/RouterSetup'; - - +import { UserContextProvider } from './Context/userContext'; +import {API} from './config/api'; +if (localStorage?.token) { + API.defaults.headers.common['Authorization'] = `Bearer ${localStorage.token}` +} else { + delete API.defaults.headers.common['Authorization'] +} function App() { + return ( - <> - - - + + + + ); } diff --git a/src/Context/userContext.js b/src/Context/userContext.js new file mode 100644 index 0000000..ed4222e --- /dev/null +++ b/src/Context/userContext.js @@ -0,0 +1,38 @@ +import { createContext, useReducer ,useEffect} from 'react' + +export const UserContext = createContext(null); + +const initialState = { + isLogin: false, + user:{} +} + +const reducer = (state, action) => { + const { status, payload } = action; + + switch (status) { + case 'login': + localStorage.setItem('token', payload.token) + return { + isLogin: true, + user: payload + } + case 'logout': + localStorage.removeItem('token') + return { + isLogin: false, + user: {} + } + default: + throw new Error(); + } +} + +export const UserContextProvider = ({ children}) => { + const [state, dispatch] = useReducer(reducer, initialState) + return ( + < UserContext.Provider value={{ state, dispatch }} > + {children} + + ) +} \ No newline at end of file diff --git a/src/components/AddProduct/AddProduct.styled.js b/src/components/AddProduct/AddProduct.styled.js index 299f1d6..f96ce61 100644 --- a/src/components/AddProduct/AddProduct.styled.js +++ b/src/components/AddProduct/AddProduct.styled.js @@ -17,20 +17,23 @@ export const Wrapper = styled.div` padding-left: 10px; } .first { - width :927px; + max-width :927px; + width:100%; height:50px; } .second { font-family: 'Montserrat', sans-serif; - width: 213px; + max-width: 213px; + width:100%; height: 50px; border-radius: 5px; border: 2px solid #766C6C; background: rgba(210, 210, 210, 0.25); } .third { - width: 1157px; + max-width: 1157px; height: 50px; + width:100%; } label{ display:flex; @@ -51,7 +54,8 @@ export const WrapperMain = styled.div` background: #433434; border-radius: 5px; border:0; - width: 260px; + max-width: 260px; + width:100%; height: 40px; font-family: 'Montserrat', sans-serif; font-weight: bold; @@ -71,6 +75,7 @@ export const Flex = styled.div` display:flex; ${props => props.btwn ? ` justify-content:space-between; + gap:1rem; `: null} margin-bottom: 27px; ` \ No newline at end of file diff --git a/src/components/AddProduct/index.js b/src/components/AddProduct/index.js index 1be0c96..2d1961d 100644 --- a/src/components/AddProduct/index.js +++ b/src/components/AddProduct/index.js @@ -1,11 +1,61 @@ -import { React } from 'react'; +import { React ,useContext ,useState} from 'react'; +import { API , handleError} from '../../config/api' +import {UserContext} from '../../Context/userContext' import Header from '../Header'; import Clip from '../../img/clip.svg' import { Wrapper ,WrapperMain ,Flex} from './AddProduct.styled' const AddProduct = () => { - + const { state } = useContext(UserContext) + // const { user } = state + const [form, setForm] = useState({ + title: '', + image: '', + price: '' + }) + let [pre , setPre] = useState(Clip) + const handleChange = (e) => { + setForm({ + ...form, + [e.target.name]: e.target.type === "file" ? e.target.files : e.target.value, + }); + if (e.target.type === "file") { + try { + setPre(URL.createObjectURL(e.target.files[0])); + } catch (e) { + setPre(Clip) + } + } + } + const handleSubmit = async (e) => { + try { + e.preventDefault(); + const config = { + headers: { + 'Content-Type': 'multipart/form-data' + } + } + const formData = new FormData(); + formData.set('title', form.title) + if (form.image) { + formData.set("image", form?.image[0], form?.image[0]?.name); + } + formData.set('price', form.price) + await API.post('/add/product', formData ,config) + setForm({ + title: '', + image: '', + price: '' + }) + setPre(Clip) + } catch (err) { + handleError(err) + } + } + + + return ( <>
@@ -14,13 +64,15 @@ const AddProduct = () => { { type="text" name="price" placeholder="Price" - > + onChange={handleChange} + value= {form.price} + /> - + diff --git a/src/components/AddResto/AddResto.styled..js b/src/components/AddResto/AddResto.styled..js new file mode 100644 index 0000000..03feb7a --- /dev/null +++ b/src/components/AddResto/AddResto.styled..js @@ -0,0 +1,78 @@ +import styled from "styled-components"; + + +export const Wrappper = styled.div` + width:84.8%; + margin:0 auto; + margin-top: 73px; + h1 { + padding-left: 25px; + font-size: 36px; + } + input{ + font-family: 'Montserrat', sans-serif; + border-radius: 5px; + border: 2px solid #766C6C; + background: rgba(210, 210, 210, 0.25); + padding-left: 10px; + max-width:100%; + margin-bottom: 27px; + } + .first { + max-width : 927px; + width:100%; + height:50px; + } + .firsts { + max-width : 903px; + width:100%; + height:50px; + } + .second { + font-family: 'Montserrat', sans-serif; + max-width: 213px; + width:100%; + height: 50px; + border-radius: 5px; + border: 2px solid #766C6C; + background: rgba(210, 210, 210, 0.25); + } + .secondbtn { + padding:0px 40px; + font-weight: bold; + border:none; + color:white; + font-size: 14px; + line-height: 19px; + font-family: 'Montserrat', sans-serif; + display:flex; + justify-content: space-between; + align-items: center; + width: 222px; + height: 50px; + background: #433434; + border-radius: 5px; + } + .third { + width: 1157px; + height: 50px; + } + label{ + display:flex; + justify-content: space-between; + align-items: center; + padding:10px; + img{ + height:30px; + } + } +` + +export const Flexx = styled.div` + display:flex; + ${props => props.btwn ? ` + justify-content:space-between; + gap:1rem; + `: null} + /* margin-bottom: 27px; */ +` \ No newline at end of file diff --git a/src/components/AddResto/index.js b/src/components/AddResto/index.js new file mode 100644 index 0000000..a5864a5 --- /dev/null +++ b/src/components/AddResto/index.js @@ -0,0 +1,142 @@ +import React, { useState, useEffect, useContext } from 'react'; +import { API, handleError } from '../../config/api' +import { Wrappper , Flexx } from './AddResto.styled.' +import { Wrapper ,WrapperMain ,Flex} from '../AddProduct/AddProduct.styled' +import Header from '../Header'; +import Clip from '../../img/clip.svg' +import Map from '../Map' +import map from '../../img/map.svg' +import { UserContext } from '../../Context/userContext' +import axios from 'axios' +import {useNavigate} from 'react-router-dom' + + +const AddResto = () => { + const navigate = useNavigate() + const { state } = useContext(UserContext) + const {user} = state + const [showMap, setShowMap] = useState(false); + const toggle = () => setShowMap(!showMap); + + const [form, setForm] = useState({ + title: '', + img: '', + loc:'' + }) + const [loc, setLoc] = useState(user.location?.split(' ')) + const [address, setAddress] = useState(null) + useEffect(() => { + if (loc) { + try { + axios.get(`https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${loc[0]}&lon=${loc[1]}`) + .then((res) => { setAddress(res.data.display_name) }) + setForm({ + ...form, + loc: loc[0]+' '+loc[1] + }) + } catch (err) { + console.log(err) + } + } + }, [loc]) + let [pre , setPre] = useState(Clip) + const handleChange = (e) => { + setForm({ + ...form, + [e.target.name]: e.target.type === "file" ? e.target.files : e.target.value, + }); + if (e.target.type === "file") { + try { + setPre(URL.createObjectURL(e.target.files[0])); + } catch (e) { + setPre(Clip) + } + } + } + const handleSubmit = async (e) => { + try { + e.preventDefault(); + const config = { + headers: { + 'Content-Type': 'multipart/form-data' + } + } + let formData = new FormData(); + formData.set('title', form.title) + if (form.img) { + formData.set("img", form.img[0], form.img[0].name); + } + formData.set('loc', form.loc) + console.log(formData) + const res = await API.post('/add/resto', formData ,config) + navigate(`/Resto/${res.data.data.resto.response.id}`) + } catch (err) { + handleError(err) + } + } + const handleSubmit2 = async (e) => { + try { + e.preventDefault(); + const config = { + headers: { + 'Content-Type': 'multipart/form-data' + } + } + let formData = new FormData(); + formData.set('title', form.title) + if (form.img) { + formData.set("img", form.img[0], form.img[0].name); + } + formData.set('loc', form.loc) + console.log(formData) + const res = await API.post('/add/resto', formData ,config) + navigate(`/Resto/${res.data.data.resto.response.id}`) + } catch (err) { + handleError(err) + } + } + return ( + <> + {showMap ? : null} +
+ + +

Add Resto

+ + + + + + + + + + + +
+
+ + + ) +} + + +export default AddResto \ No newline at end of file diff --git a/src/components/CartPage/CartPage.styled.js b/src/components/CartPage/CartPage.styled.js index 30ba1ba..63ccf2b 100644 --- a/src/components/CartPage/CartPage.styled.js +++ b/src/components/CartPage/CartPage.styled.js @@ -24,6 +24,7 @@ export const WrapContent = styled.div` width: 100%; height: 47px; display:flex; + gap:1rem; justify-content: space-between; button { @import url('https://fonts.googleapis.com/css2?family=Abhaya+Libre:wght@800&family=Shippori+Antique+B1&display=swap'); @@ -61,13 +62,19 @@ export const WrapContent = styled.div` ` export const WrapOrder = styled.div` display:flex; + /* border:1px solid black; */ + justify-content: space-between; width: 100%; + gap:1rem; height:433px; .over { padding-right: 10px; + /* border:1px solid black; */ overflow-x: hidden; overflow-y: auto; - max-height: 433px; + max-width: 660px; + width:100%; + height: 433px; &::-webkit-scrollbar-track { box-shadow: inset 0 0 6px rgba(0,0,0,0.3); @@ -98,6 +105,7 @@ export const WrapOrder2 = styled.table` export const Flex = styled.td` display:flex; max-width: 660px; + width:100%; height: 119px; border-bottom: 0.1mm solid black; border-top: 0.1mm solid black; @@ -117,8 +125,22 @@ export const Wrap2 = styled.div` display:flex; flex-direction: column; /* border:1px solid black; */ - width: 567px; + width: 550px; + /* width:100%; */ + @media only screen and (max-width: 1000px) { + width:450px; + } + @media only screen and (max-width: 800px) { + width:350px; + } + @media only screen and (max-width: 700px) { + width:250px; + } + @media only screen and (max-width: 600px) { + width:100%; + } height:80px; + justify-content: space-between; ` export const Wrap3 = styled.div` flex:100%; @@ -128,6 +150,7 @@ export const Wrap3 = styled.div` display:flex; padding-top: 10px; align-items: center; + gap:1rem; justify-content: space-between; p { padding-bottom: 10px; @@ -140,6 +163,7 @@ export const Wrap3 = styled.div` background: none; border: none; color:#4F3D31; + cursor: pointer; img { height:25px; width:12px; @@ -166,7 +190,6 @@ export const FlexCollum = styled.div` display:flex; flex-direction: column; width: 30%; - margin-left: 35px; tb { display:flex; flex-direction: column; diff --git a/src/components/CartPage/index.js b/src/components/CartPage/index.js index c44d44a..b994c71 100644 --- a/src/components/CartPage/index.js +++ b/src/components/CartPage/index.js @@ -1,4 +1,8 @@ -import { React, useState, useEffect } from 'react'; +import { React, useState, useEffect ,useContext} from 'react'; +import { API, handleError } from '../../config/api' +import convertRupiah from 'rupiah-format'; +import { UserContext } from '../../Context/userContext'; +import {io} from 'socket.io-client' import { Wrapper ,WrapContent , WrapOrder ,Orderbtn , Pp , WrapOrder2, Flex , FlexCollum , Wrap1 , Wrap2 , Wrap3} from './CartPage.styled' import map from '../../img/map.svg' @@ -7,28 +11,195 @@ import min from '../../img/-.svg' import trash from '../../img/Trash.svg' import Header from '../Header'; import Map from '../Map'; -const CartPage = ({ U}) => { +import { useNavigate } from 'react-router'; + + +let socket; +const CartPage = () => { const [open, setOpen] = useState(false) const openMap = () => setOpen(!open) const [far, setFar] = useState(false) const openMapFar = () => setFar(!far) - const [val, setVal] = useState(1); - const add = () => setVal(val + 1); - const remove = () => setVal(val - 1); - const [order, setOrder] = useState(false); - useEffect(()=> { - if(val <1) {setVal(1);} - },[val]) + const [orderMap, setOrderMap] = useState(false); + const navigate = useNavigate() + + + const { state, dispatch } = useContext(UserContext) + const { user } = state + + const [form, setForm] = useState({ + location: user.location, + }) + + const [total, letTotal] = useState(null) + const [order, setOrder] = useState([]) + const [resto, setResto] = useState() + const [transaction, setTransaction] = useState(null) + const [address, setAddress] = useState(null) + const [loc, setLoc] = useState(user.location?.split(' ')) + const [refresh, setReresh] = useState(false) + useEffect(async () => { + await API.get('/order/count') + .then(res => letTotal(res.data.total)) + .catch(err => handleError(err)) + await API.get('/transaction/active') + .then(res => {setOrder(res.data.data.transactions[0].product); setTransaction(res.data.data.transactions[0]) }) + .catch(err => handleError(err)) + }, [refresh]) + const start = transaction?.seller.location.split(' ') + useEffect(async()=>{ + await API.get(`/last/resto/${transaction?.sellerId}`) + .then(res => setResto(res?.data?.data)) + .catch(err => handleError(err)) + }, [transaction]) + console.log('////////////////////') + console.log(order) + console.log(transaction?.sellerId) + console.log(resto) + console.log('////////////////////') + useEffect(() => { + if (transaction?.status === 'Waiting Approve' ||transaction?.status === 'On The Way') { + console.log(transaction?.status) + setOrderMap(true) + setFar(true) + } + }, [transaction]) + useEffect(() => { + socket = io('http://localhost:5000', { + auth: { + token: localStorage.getItem("token") + }, + query: { + id: state.user.id + } + }) + socket.on('connect', () => { + console.log(socket); + }) + socket.on("connect_error", (err) => { + console.error(err.message); + }); + return () => { + socket.disconnect() + } + },[]) + const handleOrder = async () => { + socket.emit('new transaction',12) + socket.emit("order",transaction.id) + const config = { + headers: { + 'Content-Type': 'application/json' + } + } + await API.patch(`/transaction/${transaction.id}`, {address: address.display_name.split(',')[0] }, config) + setOrderMap(true) + } + const handleConfirm = () => { + socket.emit('new transaction',12) + socket.emit("confirm",transaction.id) + setOrderMap(true) + openMapFar() + // console.log('|\\\|\|\\\||') + // console.log() + navigate(`/profile`) + } + const orderDelete = async (x) => { + try { + console.log(x) + const res = await API.delete(`/order/${x}`) + console.log(res) + setReresh(!refresh) + } catch (err) { + handleError(err) + } + } + useEffect( async () => { + if (loc) { + try { + + await API.get(`https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${loc[0]}&lon=${loc[1]}`) + .then((res) => { setAddress(res.data) }) + setForm({ + ...form, + location: loc[0]+' '+loc[1] + }) + // console.log* + + } catch (err) { + console.log(err) + } + } + }, [loc]) + const updateloc = async () => { + try { + const config = { + headers: { + 'Content-Type': 'application/json' + } + } + await API.patch('/userData', form, config) + const response = await API.get('/login') + await dispatch({ + status: 'login', + payload: response.data + }) + } catch (err) { + handleError(err) + } + } + // console.log(transaction.id) + + const addHandle = async (x) => { + try { + const config = { + headers: { + 'Content-Type': 'application/json' + } + } + let res = { + transactionId: transaction.id, + productId: x, + qty: 1 + } + res = JSON.stringify(res) + console.log(res) + await API.post('/add/order', res, config) + setReresh(!refresh) + } + catch (err) { + handleError(err) + } + } + const lessHandle = async (x) => { + try { + const config = { + headers: { + 'Content-Type': 'application/json' + } + } + let res = { + transactionId: transaction.id, + productId: x, + qty: 1 + } + res = JSON.stringify(res) + await API.post('/less/order', res, config) + setReresh(!refresh) + } + catch (err) { + handleError(err) + } + } return ( <> - {open? : null } - {far ? : null} -
+ {open? : null } + {far ? : null} +
-

Geprek Bensu, Menus

+

{resto?.resto?.title}, Menus

Delivery Location

-

Yogyakarta, Sleman, Condong catur

+

{address?.display_name}

Review Your Order

@@ -36,91 +207,44 @@ const CartPage = ({ U}) => {
{/* TC~REPEAT */} - - - - - -

Paket Geprek

-

Rp.15.000

-
- -
- -

{ val}

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

Paket Geprek

-

Rp.15.000

-
- -
- -

{ val}

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

Paket Geprek

-

Rp.15.000

-
- -
- -

{ val}

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

Paket Geprek

-

Rp.15.000

-
- -
- -

{ val}

- -
- -
-
-
-
+ {total === 0 ? + resto?.resto?.id === undefined ? + navigate(`/resto`) : + navigate(`/resto/${resto.resto.id}`) : null} + {order.map(x =>{ + return ( + + + + + +

{x.title}

+

{convertRupiah.convert(x.order.qty * x.price)}

+
+ +
+ +

{x.order.qty}

+ +
+ +
+
+
+
+ ) + })}
Subtotal - Rp.35.000 + {convertRupiah.convert(transaction?.price)} Qty - 2 + {total} Ongkir @@ -129,12 +253,12 @@ const CartPage = ({ U}) => { TOTAL - Rp.10.000 + {convertRupiah.convert(transaction?.price + 10000)} - {order ?:} + {orderMap ? : }
diff --git a/src/components/DetailPage/DetailPage.styled.js b/src/components/DetailPage/DetailPage.styled.js index c958bb4..ec2dbe8 100644 --- a/src/components/DetailPage/DetailPage.styled.js +++ b/src/components/DetailPage/DetailPage.styled.js @@ -15,6 +15,14 @@ export const Wrapper = styled.div` width: 100%; } ` +export const Dis = styled.img` + margin:0 auto !important; + display: flex; + align-self: center; + width:25px !important; + height: 25px !important; + background: transparent !important; +` export const WrapCard = styled.div` /* border:1px solid black; */ display:flex; @@ -23,6 +31,20 @@ export const WrapCard = styled.div` justify-content: space-between; flex-wrap: wrap; flex-grow: 1; + gap:1rem; + h4{ + margin:0px; + width:100%; + font-size: 18px; + opacity: 0.5; + } + h5{ + font-family: "Helvetica Neue",Helvetica; + opacity: 0.5; + margin:0px; + width:100%; + font-size: 14px; + } ` export const CardMenu = styled.div` margin-bottom: 42px; @@ -79,4 +101,67 @@ export const CardMenu = styled.div` background:#433434; } } +` + +export const Modal = styled.div` + margin-top:-60px; + width: 100%; + padding:0px 20px 0px 20px; + display:flex; + /* justify-content:center; */ + background: rgba(0, 0 ,0 ,0.5); + /* position:absolute; */ + margin-top:-20px; + /* border:1px solid black; */ + align-items:center; + border-radius: 0px 0px 10px 10px; + height: 50px; + justify-content:space-between; + gap:1rem; + animation: ani 1s ease forwards; + @keyframes ani { + from { + margin-top:-60px; + }to{ + margin-top:0px; + } + } + .modal-left { + display:flex; + color:white; + font-size: 18px; + font-family: 'Shippori Antique B1', sans-serif; + gap:1rem; + align-items:center; + } + span { + font-size: 18px; + font-family: 'Shippori Antique B1', sans-serif; + background-color: red; + padding:4px; + font-weight: bold; + border-radius:4px; + + } + button { + margin:0 auto; + border:none; + width: 100px; + height: 40px; + background: #FFC700; + border-radius: 5px; + font-weight: 800; + font-size: 14px; + line-height: 19px; + text-align: center; + color: #433434; + &:hover { + color:#FFC700; + background:none; + border:1px solid #FFC700; + } + font-family: 'Shippori Antique B1', sans-serif; + + } + ` \ No newline at end of file diff --git a/src/components/DetailPage/index.js b/src/components/DetailPage/index.js index 334154a..82d5d6d 100644 --- a/src/components/DetailPage/index.js +++ b/src/components/DetailPage/index.js @@ -1,74 +1,149 @@ import { React, useEffect, useState } from 'react'; - +import { API ,handleError} from '../../config/api'; import Header from '../Header'; +import convertRupiah from 'rupiah-format' +import { Wrapper, WrapCard , CardMenu ,Dis , Modal} from './DetailPage.styled' +import { useParams } from 'react-router'; +import Disable from '../../img/disabled.png' -import { Wrapper, WrapCard , CardMenu} from './DetailPage.styled' -import Pizza from '../../img/pizza.svg'; -// check new this -const near = [ - { - id:1, - food: 'Geprek Bensu', - img: 'https://upload.wikimedia.org/wikipedia/commons/2/24/Ayam_geprek.png', - distance: '0,2 KM' - }, - { - id:2, - food: 'Nasi Goreng Mas Roni', - img: 'https://upload.wikimedia.org/wikipedia/commons/thumb/e/e5/Nasi_Goreng.jpg/800px-Nasi_Goreng.jpg', - distance: '0,6 KM' - }, - { id:3, - food: 'Pecel Ayam Prambanan', - img: 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/a1/Pecel_Solo.JPG/800px-Pecel_Solo.JPG', - distance: '0,6 KM' - }, - { id:4, - food: 'Kopi Kenangan', - img: 'https://upload.wikimedia.org/wikipedia/commons/thumb/4/45/A_small_cup_of_coffee.JPG/800px-A_small_cup_of_coffee.JPG', - distance: '1,6 KM' - }, - { id:5, - food: 'Geprek Bensu', - img: 'https://upload.wikimedia.org/wikipedia/commons/2/24/Ayam_geprek.png', - distance: '0,2 KM' - }, - { id:6, - food: 'Nasi Goreng Mas Roni', - img: 'https://upload.wikimedia.org/wikipedia/commons/thumb/e/e5/Nasi_Goreng.jpg/800px-Nasi_Goreng.jpg', - distance: '0,6 KM' - }, - { id:7, - food: 'Pecel Ayam Prambanan', - img: 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/a1/Pecel_Solo.JPG/800px-Pecel_Solo.JPG', - distance: '0,6 KM' - }, - { id:8, - food: 'Kopi Kenangan', - img: 'https://upload.wikimedia.org/wikipedia/commons/thumb/4/45/A_small_cup_of_coffee.JPG/800px-A_small_cup_of_coffee.JPG', - distance: '1,6 KM' - }, -] -const DetailPage = () => { +const DetailPage = (req,res) => { + const { id } = useParams() + const [resto, setResto] = useState([]) + const [menu, setMenu] = useState([]) + const [transaction, setTransaction] = useState(null) + const [transactionID, setTransactionID] = useState(null) + const [transactionLast, setTransactionLast] = useState(null) + const [lastResto, setLastResto] = useState(null) + const [modalConfirmation, setModalConfirmation] = useState(false) + useEffect(async() => { + await API.get(`/resto/${id}` ) + .then((res) => { setResto(res.data.data.resto.data); setMenu(res.data.data.resto.menu) }) + .catch((err) => { handleError(err) }) + await API.get('/transaction/user') + .then((res) => { setTransaction(res.data.data.status)}) + .catch((err) => { handleError(err) }) + await API.get('/transaction/user/order') + .then(res => { setTransactionID(res.data.data.sellerId);setTransactionLast(res.data.data) }) + .catch((err) => { handleError(err) }) + + }, []) + useEffect(async () => { + const res = await API.get('/transaction/user/order') + if (res?.data?.data?.sellerId === undefined) { + console.log('undefined') + setTransactionID(null) + }else{ + console.log('not undefined') + } + },[modalConfirmation]) + useEffect(async () => { + await API.get(`/last/resto/${transactionLast?.sellerId}`) + .then((res) => setLastResto(res.data.data.resto)) + .catch((err) => handleError(err)) + },[transactionLast]) + // console.log(resto.ownerId) + console.log(transactionID) + // console.log(transaction) + console.log(transactionLast) + // console.log(lastResto) + // console.log(menu) + const [form, setForm] = useState({}) + const [trigHead, setTrigHead] = useState(false) + const handleOrder = (x) => { + setForm({ + sellerId : resto.ownerId, + product: [ + { + productId: x, + qty: 1 + } + ] + }) + } + const [fristhold, setFristhold] = useState(false) + useEffect(() => { + if (fristhold === true) { + if (resto.ownerId === transactionID || transactionID === null) { + order() + } else { + console.log(' u still have order on resto ' + lastResto.title) + console.log('after this if use want to change resto then update transaction status cancel ') + setModalConfirmation(true) + } + } else { + setFristhold(true) + } + }, [form]) + const order = async () => { + try { + const config = { + headers: { + 'Content-Type': 'application/json' + } + } + console.log(form.sellerId) + + const body = JSON.stringify(form) + console.log(body) + let res = await API.post('/add/transaction', form, config) + console.log(res) + if(res.status === 201) { + console.log('///////////////////') + console.log(res) + res = { + transactionId: res.data.thenTransaction.id, + ...form.product[0], + } + console.log('///////////////////') + console.log(res) + res = JSON.stringify(res) + await API.post('/add/order', res, config) + } + setTrigHead(!trigHead) + } catch (err) { + handleError(err) + } + } - const [val, setVal] = useState(false); - const add = () => setVal(val + 1); - const remove = () => setVal(val + 1); return ( <> -
+
+ {modalConfirmation ? + +
+ {' u still have order on resto ' + lastResto.title} +
+
+ Do you want to Cancel the last Order? + + +
+
: null} -

Geprek Bensu, Menus

- {near.map((near) => { +

{resto.title}, Menus

+ {transaction ?<> +

You can't order right now, you have transaction {transaction}

+
please wait until your order finish.
+ : null} + {menu.map((menu) => { return ( - - -

{near.food}

-

Rp.45.000

- + + {menu.img} +

{menu.title}

+

{convertRupiah.convert(menu.price)}

+ {transaction ? : }
) })} diff --git a/src/components/DropDown/index.js b/src/components/DropDown/index.js index 7a8ddd7..788b7a4 100644 --- a/src/components/DropDown/index.js +++ b/src/components/DropDown/index.js @@ -1,4 +1,5 @@ -import { React, useEffect, useState } from 'react'; +import { React, useEffect, useState, useContext } from 'react'; +import { UserContext } from '../../Context/userContext'; import { Wrapper ,Wrapper2 ,Icon , JustWrap ,Logout} from './DropDown.styled'; import userIcon from '../../img/user.svg'; @@ -8,12 +9,24 @@ import Transaction from '../../img/transaction.svg'; import { Link } from 'react-router-dom'; const DropDown = ({U , LogoutSwitch , set, logout}) => { // x = false; - const val = !U + const { state, dispatch } = useContext(UserContext) + const handleLogout = () => { + dispatch({ + status: 'logout' + }) + console.log(state) + } + const {user} = state + let isOwner = false + if (user?.role === 'owner') { + isOwner = true + } return ( <> - {val ?<> + {isOwner ?<> + @@ -36,13 +49,13 @@ const DropDown = ({U , LogoutSwitch , set, logout}) => { {logout ? - +

Logout

: - +

Logout

} @@ -62,13 +75,13 @@ const DropDown = ({U , LogoutSwitch , set, logout}) => { {logout ? - +

Logout

: - +

Logout

} diff --git a/src/components/EditProfile/EditProfile.styled.js b/src/components/EditProfile/EditProfile.styled.js index ca818ba..742a2a7 100644 --- a/src/components/EditProfile/EditProfile.styled.js +++ b/src/components/EditProfile/EditProfile.styled.js @@ -15,19 +15,23 @@ export const Wrapper = styled.div` border: 2px solid #766C6C; background: rgba(210, 210, 210, 0.25); padding-left: 10px; + max-width:100%; margin-bottom: 27px; } .first { - width : 927px; + max-width : 927px; + width:100%; height:50px; } .firsts { - width : 903px; + max-width : 903px; + width:100%; height:50px; } .second { font-family: 'Montserrat', sans-serif; - width: 213px; + max-width: 213px; + width:100%; height: 50px; border-radius: 5px; border: 2px solid #766C6C; @@ -64,7 +68,7 @@ export const Wrapper = styled.div` } ` -export const WrapperMain = styled.div` +export const WrapperMain = styled.form` margin-top:40px; width:100%; button{ @@ -92,6 +96,7 @@ export const Flex = styled.div` display:flex; ${props => props.btwn ? ` justify-content:space-between; + gap:1rem; `: null} /* margin-bottom: 27px; */ ` \ No newline at end of file diff --git a/src/components/EditProfile/index.js b/src/components/EditProfile/index.js index 91558f0..dd87c7a 100644 --- a/src/components/EditProfile/index.js +++ b/src/components/EditProfile/index.js @@ -1,39 +1,126 @@ -import { React ,useState,useEffect} from 'react'; +import { React ,useState, useContext ,useEffect} from 'react'; import Header from '../Header'; import Clip from '../../img/clip.svg' import map from '../../img/map.svg' import Map from '../Map' -import { Wrapper ,WrapperMain ,Flex} from './EditProfile.styled' - - +import { Wrapper, WrapperMain, Flex } from './EditProfile.styled' +import { API ,handleError } from '../../config/api' +import axios from 'axios' +import { UserContext } from '../../Context/userContext'; +import {useNavigate} from 'react-router-dom' const EditProfile = ({ U }) => { + const navigate = useNavigate() const [showMap, setShowMap] = useState(false); const toggle = () => setShowMap(!showMap); - const which = U + const { state, dispatch } = useContext(UserContext) + const { user } = state + let isOwner = false + if (user?.role === 'owner') { + isOwner = true + } const data = [ { - Title1 : (which ? 'Edit Profile' : 'Edit Profile Partner'), - Title2 : (which ? 'Full Name' : 'Name Partner') + Title1 : (isOwner ? 'Edit Profile Partner':'Edit Profile'), + Title2 : (isOwner ? 'Name Partner' : 'Full Name' ) } ] + let [pre , setPre] = useState(user?.image === null? Clip : user.image) + const [form, setForm] = useState({ + fullname: user.fullname, + image: user.image, + email: user.email, + phone: user.phone, + location: user.location, + }) + + const [response, setResponse] = useState(null) + const [loc, setLoc] = useState(user.location?.split(' ')) + + useEffect(() => { + if (loc) { + try { + axios.get(`https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${loc[0]}&lon=${loc[1]}`) + .then((res) => { setResponse(res.data) }) + setForm({ + ...form, + location: loc[0]+' '+loc[1] + }) + } catch (err) { + console.log(err) + } + } + }, [loc]) + + + const handleChange = (e) => { + setForm({ + ...form, + [e.target.name]: e.target.type === "file" ? e.target.files : e.target.value, + }) + if (e.target.type === "file") { + try { + setPre(URL.createObjectURL(e.target.files[0])); + } catch (e) { + setPre(Clip) + } + } + console.log(form) + } + const handleSubmit = async (e) => { + try { + + e.preventDefault(); + const config = { + headers: { + 'Content-Type': 'multipart/form-data' + } + } + // const config2 = { + // headers: { + // 'Content-Type': 'application/json' + // } + // } + const formData = new FormData(); + if (form.image) { + formData.set("image", form?.image[0], form?.image[0]?.name); + } else ( + formData.set('image', form.image) + ) + formData.set('fullname', form.fullname) + formData.set('email', form.email) + formData.set('phone', form.phone) + formData.set('location', form.location) + await API.patch('/user', formData, config) + const response = await API.get('/login') + await dispatch({ + status: 'login', + payload: response.data + }) + navigate('/Profile') + } catch (err) { + handleError(err) + } + } return ( <> - {showMap ? : null} + {showMap ? : null}

{data[0].Title1}

{ type="text" name="email" placeholder="Email" + value={form.email} + onChange={handleChange} > - +
diff --git a/src/components/Header/Header.styled.js b/src/components/Header/Header.styled.js index e34e67d..fd5533a 100644 --- a/src/components/Header/Header.styled.js +++ b/src/components/Header/Header.styled.js @@ -19,7 +19,6 @@ export const TopFlex = styled.div` justify-content: space-between; align-items: center; width:95%; - .shake { @keyframes shakes { 0%{ diff --git a/src/components/Header/index.js b/src/components/Header/index.js index 9731e99..f864e88 100644 --- a/src/components/Header/index.js +++ b/src/components/Header/index.js @@ -1,18 +1,39 @@ -import { React, useEffect, useState } from 'react'; +import { React, useEffect, useState ,useContext} from 'react'; import { Link } from 'react-router-dom'; +import { UserContext } from '../../Context/userContext'; +import {API, handleError} from '../../config/api' import Icon from '../../img/Icon.svg'; import Trolly from '../../img/Trolly.svg'; -import Pizza from '../../img/pizza.svg'; +import Shop from '../../img/shop.png'; import poly from '../../img/poly.svg'; import { Head, TopFlex, Wrap ,Polyy ,Specialdrop} from './Header.styled'; import DropDown from '../DropDown'; -const Header = ({ val , U ,noTroll}) => { +const Header = ({ trigger ,noTroll}) => { let [show, setShow] = useState(false); + const {state, dispatch} = useContext(UserContext) const toggle = () => (setShow(!show)); - + const { user } = state + let isOwner = false + if (user.role === 'owner') { + isOwner = true + } + const [total, letTotal] = useState(null) + useEffect(async() => { + await API.get('/order/count') + .then(res => letTotal(res.data.total)) + .catch(err => handleError(err)) + }, [trigger]) + const [resto, setResto] = useState(null) + // const [restoId, setRestoId] = useState(null) + useEffect(async () => { + await API.get(`/resto` ) + .then((res) => { setResto(res.data.data.resto.data)}) + .catch((err) => { handleError(err) }) + }, []) + console.log(resto) return ( <> @@ -21,12 +42,19 @@ const Header = ({ val , U ,noTroll}) => { - {val ?

{val}

: null} - {noTroll ? null : - - - } - + {isOwner ? + + : + noTroll ? null : + <> + {total ?

{total}

: null} + + + + + } + +
{show ? <> @@ -36,7 +64,7 @@ const Header = ({ val , U ,noTroll}) => { - + : null} diff --git a/src/components/LandingPage/LandingPage.styled.js b/src/components/LandingPage/LandingPage.styled.js index f74bfe5..6fb8cdf 100644 --- a/src/components/LandingPage/LandingPage.styled.js +++ b/src/components/LandingPage/LandingPage.styled.js @@ -17,6 +17,33 @@ export const WrapperYellow = styled.div` } }; ` +export const Polyy = styled.div` + position:absolute; + right:175px; + top: 90px; + .poly { + opacity:0; + position:absolute; + animation: a 1s ease-out forwards; + animation-delay: 0.3s; + @keyframes a { + 0%{ + opacity:0; + transform: translateX(60px)translateY(0px); + } + 80%{ + transform: translateX(60px)translateY(0px); + } + 90%{ + opacity:0.3; + } + 100% { + transform: translateX(60px)translateY(-30px); + opacity:1; + } + } + } +` export const OneLineFlexTop = styled.div` @import url('https://fonts.googleapis.com/css2?family=Shippori+Antique+B1&display=swap'); padding-top: 27px; @@ -33,7 +60,25 @@ export const OneLineFlexTop = styled.div` /* border:1px solid black; */ justify-content: space-between; align-items: center; - .poly { + &:hover{ + p { + opacity: 0.5; + } + } + p{ + background:red; + height:15px; + width:15px; + border-radius: 50%; + font-size: 12px; + color:white; + text-align:center; + /* margin-top: 0px; */ + margin-left: 20px !important; + z-index:99 !important; + position:absolute !important; + } + /* .poly { opacity:0; position:absolute; animation: a 1s ease-out forwards; @@ -54,7 +99,7 @@ export const OneLineFlexTop = styled.div` opacity:1; } } - } + } */ button { width: 100px; height: 30px; @@ -76,9 +121,11 @@ export const OneLineFlexTop = styled.div` export const TextAndPizza = styled.div` display:flex; position: absolute; - width: 966px; + max-width: 1066px; height: 393px; - bottom: 40px; + padding-left:20px; + padding-right:20px; + bottom: 60px; /* border:1px solid black; */ ` export const Text = styled.div` @@ -141,6 +188,8 @@ export const WrapFlex2 = styled.div` display:flex; flex-direction: row; justify-content: space-between; + flex-wrap: wrap; + gap:1rem; margin-bottom: 91px; .nonee{ text-decoration: none !important; @@ -149,6 +198,8 @@ export const WrapFlex2 = styled.div` export const WrapFlex3 = styled.div` display:flex; flex-direction: row; + flex-wrap: wrap; + gap:1rem; justify-content: space-between; ` export const WrapMain = styled.div` @@ -174,7 +225,7 @@ export const CardResto = styled.div` border-radius: 5px; display:flex; align-items: center; - + h2 { font-family: Abhaya Libre ExtraBold; font-style: normal; diff --git a/src/components/LandingPage/index.js b/src/components/LandingPage/index.js index 21557ee..96915b9 100644 --- a/src/components/LandingPage/index.js +++ b/src/components/LandingPage/index.js @@ -1,5 +1,7 @@ -import { React, useState } from 'react'; +import { React, useState ,useContext , useEffect} from 'react'; import { Link } from 'react-router-dom'; +import { API, handleError } from '../../config/api' + //components import Login from '../Login'; @@ -11,7 +13,9 @@ import poly from '../../img/poly.svg'; import Pizza from '../../img/pizza.svg'; import Icon from '../../img/Icon.svg'; import Trolly from '../../img/Trolly.svg'; -import { WrapperYellow , OneLineFlexTop , TextAndPizza , WrapFlex , WrapFlex2 , WrapFlex3 , CardNear , Text ,ImgPizza , ImgProfile , ImgTrolly, WrapMain , CardResto} from './LandingPage.styled'; +import {WrapperYellow , OneLineFlexTop , TextAndPizza , WrapFlex , WrapFlex2 , WrapFlex3 , CardNear , Text ,ImgPizza , ImgProfile , ImgTrolly, WrapMain , CardResto, Polyy} from './LandingPage.styled'; + +import { UserContext } from '../../Context/userContext'; // TC~Dummy @@ -57,24 +61,42 @@ const near = [ ] const LandingPage = ({ U ,sett ,setf }) => { - const [which ,setWhich] = useState(false); + // const [which ,setWhich] = useState(false); let [show, setShow] = useState(false); let [showR, setShowR] = useState(false); - const [isLogin, setLogin] = useState(false); const [drop, setDrop] = useState(false); const drops = () => (setDrop(!drop),setShow(false),setShowR(false)); - const reg = () => (setLogin(!isLogin),setDrop(false),setWhich(!which)); - const login = () => (setLogin(!isLogin),setDrop(false),setWhich(false)); + // const reg = () => (setDrop(false),setWhich(!which)); + // const login = () => (setDrop(false),setWhich(false)); const toggle = () => (setShow(!show), setShowR(false)); const toggleR = () => (setShowR(!showR), setShow(false)); const Cancel = () => setShowR(!showR); const CancelL = () => setShow(!show); + + const { state, dispatch } = useContext(UserContext) + const { isLogin, user } = state + let which = true + if (user.role === 'owner') { + which = false + } + const [total, letTotal] = useState(null) + useEffect(async() => { + await API.get('/order/count') + .then(res => letTotal(res.data.total)) + .catch(err => handleError(err)) + }, []) + const [restos, setRestos] = useState([]) + useEffect(async() => { + await API.get('/restos') + .then((res) => { setRestos(res.data.data.restos) }) + },[]) + return ( <> {isLogin ? null : <> - {show ? () : null} - {showR ? () : null} + {show ? () : null} + {showR ? () : null} } {/*
*/} @@ -83,17 +105,22 @@ const LandingPage = ({ U ,sett ,setf }) => { icon
{isLogin ? <> + {which ? - {which? : } - - + {total ?

{total}

: null} + + : null} + {drop ? <> -
- -
- {which ? : }: null} + +
+ +
+
+ + : null} : <> @@ -120,16 +147,16 @@ const LandingPage = ({ U ,sett ,setf }) => {

Popular Restaurant

{/* TODO: REPEAT */} - {resto.map((resto) => { - return( - - - {resto.name} -

{resto.name}

-
- - ) - })} + {restos.map((resto) => { + return( + + + {resto.name} +

{resto.title}

+
+ + ) + })}

Restaurant Near You

diff --git a/src/components/Login/Login.styled.js b/src/components/Login/Login.styled.js index b768d85..c1af6c5 100644 --- a/src/components/Login/Login.styled.js +++ b/src/components/Login/Login.styled.js @@ -24,7 +24,7 @@ export const Wrapper = styled.div` position: fixed; background: white; z-index: 998; - border:1px solid black; + /* border:1px solid black; */ border-radius: 100; width: 100vw; height: 100vh; @@ -35,7 +35,7 @@ export const Wrapper = styled.div` animation: ani 0.6s ease-out forwards; transition: 0.6s ease-out; background:#ffff; - + /* border:1px solid red; */ /* background-position: 50%; */ /* transform: skewY(-50%); */ display: flex; @@ -60,25 +60,28 @@ export const Wrapper = styled.div` /* margin: 10px solid black; */ } form { - + /* border:1px solid black; */ display: flex; flex-direction: column; + width: 90%; /* margin-top: 30%; */ justify-self: center; align-items: center; position: sticky; + gap:0.3rem; } form input { @import url('https://fonts.googleapis.com/css2?family=Abhaya+Libre:wght@800&family=Shippori+Antique+B1&display=swap'); font-family: 'Shippori Antique B1', sans-serif; margin-bottom: 20px; - background-color: transparent; + /* background-color: transparent; */ display: block; + max-width: 350px; width: 100%; - border: none; - border-bottom: 2px solid #433434; -; - min-width: 250px; + height: 50px; + background: rgba(210, 210, 210, 0.25); + border: 2px solid #D2D2D2; + border-radius: 5px; padding-left: 5px; outline: none; color: #433434 @@ -86,8 +89,9 @@ export const Wrapper = styled.div` form input::placeholder { @import url('https://fonts.googleapis.com/css2?family=Abhaya+Libre:wght@800&family=Shippori+Antique+B1&display=swap'); font-family: 'Shippori Antique B1', sans-serif; - text-align: center; - color: #433434; + text-align: left; + color: #B1B1B1; + font-size: 18px; } h2 { @import url('https://fonts.googleapis.com/css2?family=Abhaya+Libre:wght@800&family=Shippori+Antique+B1&display=swap'); @@ -119,7 +123,9 @@ export const Wrapper = styled.div` font-weight: bold; } .login-cointainer button { + margin-top: 3%; + margin-bottom: 0px; width: 20vw; } @@ -135,6 +141,7 @@ export const Wrapper = styled.div` font-family: nunito,roboto,proxima-nova,"proxima nova",sans-serif; font-size: 16px; font-weight: 800; + width:95%; line-height: 16px; min-height: 40px; outline: 0; diff --git a/src/components/Login/index.js b/src/components/Login/index.js index 8f42bd3..c32fd63 100644 --- a/src/components/Login/index.js +++ b/src/components/Login/index.js @@ -1,18 +1,61 @@ -import React ,{useState ,useEffect} from 'react'; +import React, { useState, useEffect, useContext} from 'react'; +import { useNavigate } from 'react-router-dom' +import { UserContext } from '../../Context/userContext'; +import {API, handleError} from '../../config/api' import Xbtns from '../../img/close.png'; import { Wrapper , Bg} from './Login.styled'; -const Login = ({show , Cancel, toggle , LoginSwitch}) => { - // console.log(active); - +const Login = ({ show, Cancel, toggle,}) => { + const navigate = useNavigate() + const {state, dispatch} = useContext(UserContext) const holder = show; const [active, setActive] = useState(holder); useEffect(() => { setActive(!active); }, [holder]) + const [Form, setForm] = useState({ + email: '', + password: '', + }) + const handelChange = (e) => { + setForm({ + ...Form, + [e.target.name]: e.target.value + }) + } + useEffect(() => { + console.log(state) + },[state]) + const handelLogin = async (e) => { + try { + e.preventDefault() + const config = { + headers: { + 'Content-Type': 'application/json' + } + } + const body = JSON.stringify(Form) + const response = await API.post("/login", body, config); + console.log(response.data.role) + if (response?.status === 200) { + dispatch({ + status: 'login', + payload: response.data + }) + } + if (response.data?.role === 'owner') { + navigate('/Transaction') + } + } catch (err) { + handleError(err) + if (err.response?.status === 400) { + alert(err.response.data.message) + } + } + } return ( <> @@ -21,9 +64,9 @@ const Login = ({show , Cancel, toggle , LoginSwitch}) => {

Login

- - - + + +

Don't have an account ? Klik Here

diff --git a/src/components/Map/index.js b/src/components/Map/index.js index e6b63fd..d8dcffd 100644 --- a/src/components/Map/index.js +++ b/src/components/Map/index.js @@ -1,18 +1,39 @@ -import { React, useState, useEffect ,useRef} from 'react'; +import { React, useState, useEffect , useContext} from 'react'; import ReactMapGL, { Marker , Layer} from 'react-map-gl'; -import Dir from './costumDirect'; import 'mapbox-gl/dist/mapbox-gl.css' +import { UserContext } from '../../Context/userContext'; +import {API, handleError} from '../../config/api' +import {io} from 'socket.io-client' import close from '../../img/close.png' -import marker from '../../img/marker.png' import maponloc from '../../img/onloc.svg' import { Wrapper, Bg, Card } from './Map.styled'; -const Map = ({toggle , far}) => { +// https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=?&lon=? +let socket; +const Map = ({toggle , far ,setLocEdit ,updateLoc ,startLoc , open ,cart}) => { const [viewport, setViewport] = useState({}) console.log(far) - const start = [110.37100225029263, -7.7931344997599465] - const end = [110.35160451469888, -7.755886216995117] + const {state, dispatch} = useContext(UserContext) + const {user} = state + // const [loc, setLoc] = useState(user.location?.split(' ')) + let hold2 = open + let end = user?.location?.split(' ') + end = [end[1],end[0]] + // if (hold2){ + // } else { + // end = [10.81273,-7.81623] + // } + let start = user?.location?.split(' ') + console.log(startLoc) + console.log(start) + let hold = startLoc + if (hold) { + start = [parseFloat(startLoc[1]), parseFloat(startLoc[0])] + } + console.log(start) + // hold ? start = [start[1], start[0]] : start = [0, 1] + // let start = [startLoc[1],startLoc[0]] useEffect(() => { setTimeout(() => { setViewport({ @@ -22,106 +43,181 @@ const Map = ({toggle , far}) => { height: '100%', zoom:11 }) - }, 2000) + }, 1000) }, []) const [routeLayer, setRouteLayer] = useState({}) - - - async function getRoute(end) { - // make a directions request using cycling profile - // an arbitrary start will always be the same - // only the end or destination will change - const query = await fetch( - `https://api.mapbox.com/directions/v5/mapbox/cycling/${start[0]},${start[1]};${end[0]},${end[1]}?steps=true&geometries=geojson&access_token=${process.env.REACT_APP_MAPBOX_TOKEN}`, - { method: 'GET' } - ); - const json = await query.json(); - const data = json.routes[0]; - const route = data.geometry.coordinates; - const geojson = { - type: 'Feature', - properties: {}, - geometry: { - type: 'LineString', - coordinates: route - } - }; - setRouteLayer({ - id: 'route', - type: 'line', - source: { - type: 'geojson', - data: geojson - }, - layout: { - 'line-join': 'round', - 'line-cap': 'round' - }, - paint: { - 'line-color': '#3887be', - 'line-width': 5, - 'line-opacity': 0.75 - } - }) + const [address, setAddress] = useState(null) + const [form, setForm] = useState({ + location: user.location, +}) + let [loc, setLoc] = useState(false) + // console.log(`https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${end[1]}&lon=${end[0]}`) + useEffect( async() => { + if (far) { + try { + API.get(`https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${end[1]}&lon=${end[0]}`) + .then((res) => { setAddress(res?.data)}) + setForm({ + ...form, + location: loc[0]+' '+loc[1] + }) + } catch (err) { + console.log(err) + } + } + }, []) + async function getAddress(lat,lon) { + API.get(`https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${lat}&lon=${lon}`) + .then((res) => { setAddress(res?.data) }) + .catch((err) => { handleError(err) }) } + console.log(address) + const nameAddress = address?.display_name?.split(',') - - let [loc, setLoc] = useState(false) - let [startLayer, setStartLayer] = useState({ - id: 'point', - type: 'circle', + const [data, setData] = useState(null) + + // console.log(`https://api.mapbox.com/directions/v5/mapbox/driving-traffic/${start[0]},${start[1]};${end[0]},${end[1]}?steps=true&geometries=geojson&access_token=${process.env.REACT_APP_MAPBOX_TOKEN}`) + async function getRoute(end) { + // make a directions request using cycling profile + // an arbitrary start will always be the same + // only the end or destination will change + try { + const query = await fetch( + `https://api.mapbox.com/directions/v5/mapbox/driving-traffic/${start[0]},${start[1]};${end[0]},${end[1]}?steps=true&geometries=geojson&access_token=${process.env.REACT_APP_MAPBOX_TOKEN}`, + { method: 'GET' } + ); + const json = await query.json(); + console.log(json) + const data = await json.routes[0]; + setData(data) + const route = data.geometry.coordinates; + const geojson = { + type: 'Feature', + geometry: { + type: 'LineString', + coordinates: route + } + }; + setRouteLayer({ + id: 'route', + type: 'line', source: { type: 'geojson', - data: { - type: 'FeatureCollection', - features: [ - { - type: 'Feature', - properties: {}, - geometry: { - type: 'Point', - coordinates: start - } - } - ] - } + data: geojson + }, + layout: { + 'line-join': 'round', + 'line-cap': 'round' }, paint: { - 'circle-radius': 10, - 'circle-color': '#3887be' + 'line-color': '#3887be', + 'line-width': 5, + 'line-opacity': 0.75 } - }) - const [endLayer, setEndLayer] = useState({ - id: 'end', - type: 'circle', - source: { - type: 'geojson', - data: { - type: 'FeatureCollection', - features: [ - { - type: 'Feature', - properties: {}, - geometry: { - type: 'Point', - coordinates: end - } - } - ] + }) + } catch (err) { + handleError(err) + } +} +useEffect(() => { + getRoute(end) +},[]) +let [startLayer, setStartLayer] = useState({ + id: 'point', + type: 'circle', + source: { + type: 'geojson', + data: { + type: 'FeatureCollection', + features: [ + { + type: 'Feature', + properties: {}, + geometry: { + type: 'Point', + coordinates: start } - }, - paint: { - 'circle-radius': 10, - 'circle-color': '#f30' } - }) - + ] + } + }, + paint: { + 'circle-radius': 10, + 'circle-color': '#3887be' + } +}) +const [endLayer, setEndLayer] = useState({ + id: 'end', + type: 'circle', + source: { + type: 'geojson', + data: { + type: 'FeatureCollection', + features: [ + { + type: 'Feature', + properties: {}, + geometry: { + type: 'Point', + coordinates: end + } + } + ] + } + }, + paint: { + 'circle-radius': 10, + 'circle-color': '#f30' + } +}) const [val, setVal] = useState(false) - const mapRef = useRef() + // const mapRef = useRef() const doit = () => { setVal(false) setTimeout(() =>{toggle()},100) + } + function toMinutes(e) { + let m = Math.floor(e % 3600 / 60).toString().padStart(2, '0'); + let s = Math.floor(e % 60).toString().padStart(2, '0'); + return m + ':' + s + } + const [otwOrder, setOtwOrder] = useState(null) + useEffect(async () => { + socket = io('http://localhost:5000', { + auth: { + token: localStorage.getItem("token") + }, + query: { + id: state.user.id + } + }) + + socket.on('connect', () => { + console.log(socket); + }) + socket.on('otw' , ()=>{ + socket.emit('onTheWay', state.user.id) + otw() + }) + + otw() + socket.on("connect_error", (err) => { + console.error(err.message); + }); + return () => { + socket.disconnect() } + },[otwOrder]) + + const otw = () => { + socket.emit('onTheWay', state.user.id) + socket.on('otwData', (data) => { + setOtwOrder(data) + }) + } + console.log('/\/\/\\\//\/\/\/\/') + console.log(otwOrder) + console.log(state.user.id) return ( { rel="stylesheet" /> - + + {far ? <> + { + setViewport(viewport); + }} + mapStyle='mapbox://styles/mapbox/streets-v11' + > + + + + + marker + + + : + <> + { - const [long, lat] = e.lngLat + const [long, lat] = e.lngLat + setLocEdit([ lat, long]) setLoc([long, lat]) + // setStart([long, lat]) + getAddress(lat,long) console.log(e) - getRoute(end) }} - ref={mapRef} {...viewport} mapboxApiAccessToken={process.env.REACT_APP_MAPBOX_TOKEN} mapStyle="mapbox://styles/expitc/ckw66dojb2fye14lcysxs3mcb" @@ -146,25 +270,24 @@ const Map = ({toggle , far}) => { setViewport(viewport); }} > - - - - {loc ? <> - marker : null} + + } {loc ? <> @@ -173,31 +296,34 @@ const Map = ({toggle , far}) => {
onloc
-
Harbour Building
-

Jl. Elang IV No.48, Sawah Lama, Kec. Ciputat, Kota - Tangerang Selatan, Banten 15413, Indonesia

+
{nameAddress?nameAddress[0]:'not found'}
+

{address?.display_name}

- + {cart ? + <> + {otwOrder ? + : null} + + : }
: null} {far? -

Select delivery location

+

delivery location

onloc
-
Harbour Building
-

Jl. Elang IV No.48, Sawah Lama, Kec. Ciputat, Kota - Tangerang Selatan, Banten 15413, Indonesia

+
{nameAddress?nameAddress[0]:'not found'}
+

{address?.display_name}

Delivery Time

-

10 - 15 Minutes

- +

{toMinutes(data?.duration)} Minutes

+
: null} diff --git a/src/components/ProfilePage/ProfilePage.styled.js b/src/components/ProfilePage/ProfilePage.styled.js index 7db8dd0..eaa433c 100644 --- a/src/components/ProfilePage/ProfilePage.styled.js +++ b/src/components/ProfilePage/ProfilePage.styled.js @@ -7,9 +7,12 @@ export const Wrapper = styled.div` display: flex; justify-content: space-between; margin-top: 73px; + gap:1rem; + flex-wrap: wrap; ` export const FlexCollum = styled.div` display:flex; + gap:1rem; flex-direction: column; /* border:1px solid black; */ ${props => props.btwn ? 'justify-content: space-between;' : null} @@ -57,14 +60,14 @@ export const Buttons = styled.div` border:none; width: 112px !important; height: 19px !important; - background: #E6FFF2 !important; + background: ${props => props.c ? '#f23535!important;' : '#E6FFF2!important;'} border-radius: 2px !important; font-family: 'Montserrat', sans-serif; text-align: center !important; padding-top: 3px; line-height: 14px; font-size: 10px !important; - color: #00FF47 !important; + color: ${props => props.c ? '#ffFF!important;': '#00FF47!important;'} margin-left:10%; ` export const Pp = styled.p` @@ -83,6 +86,11 @@ export const Flex = styled.div` display:flex; ${props => props.w ? - ('width: 419px; height: 101px;background: #FFFFFF;padding:16px 20px;justify-content: space-between;') + (` + width:419px; + min-height: 101px; + background: #FFFFFF; + padding:16px 20px; + justify-content: space-between;`) : null} ` \ No newline at end of file diff --git a/src/components/ProfilePage/index.js b/src/components/ProfilePage/index.js index 50ad275..11b1897 100644 --- a/src/components/ProfilePage/index.js +++ b/src/components/ProfilePage/index.js @@ -1,30 +1,84 @@ -import { React } from 'react'; +import { React ,useContext, useState ,useEffect } from 'react'; import {Link} from 'react-router-dom' +import { UserContext } from '../../Context/userContext' +import { API , handleError} from '../../config/api'; +import {io} from 'socket.io-client' +import convertRupiah from 'rupiah-format' import Header from '../Header' import Icon from '../../img/Icon.svg' import { Wrapper ,FlexCollum, Flex ,Pp , Buttons} from './ProfilePage.styled'; -const ProfilePage = ({U}) => { - const which = U; +let socket; +const ProfilePage = () => { + + const { state, dispatch } = useContext(UserContext) + const { user } = state + let isOwner = false + if (user?.role === 'owner') { + isOwner = true + } + const [refresh,setRefresh] = useState() + const [historyTransaction,setHistoryTransaction] = useState([]) + const [transaction, setTransaction] = useState() + useEffect(() => { + API.get('/transaction/active') + .then(res => setTransaction(res)) + .catch(err => handleError(err)) + }, [refresh]) + console.log(transaction) const data = [ { - title1: (which?'My Profile' : 'Profile Partner'), - title2: (which?'History Transaction': 'History Order'), - titleName: (which?'Full Name':'Name Partner'), - img: (which?'profile':'Partner'), - history: (which?'Geprek Bensu': 'Andi') + title1: (isOwner? 'Profile Partner' : 'My Profile'), + title2: (isOwner? 'History Order' :'History Transaction'), + titleName: (isOwner?'Name Partner':'Full Name'), + img: (isOwner?'Partner':'profile'), + history: (isOwner? 'Andi' :'Geprek Bensu') } ] + + useEffect(() =>{ + socket = io('http://localhost:5000', { + auth: { + token: localStorage.getItem("token") + }, + query: { + id: state.user.id + } + }) + + socket.on('connect', () => { + console.log(socket); + }) + socket.on('new transaction' , ()=>{ + socket.emit("load transaction",state.user.id) + }) + socket.emit("load transaction",state.user.id) + loadTrans() + socket.on("connect_error", (err) => { + console.error(err.message); + }); + return () => { + socket.disconnect() + } + }, [historyTransaction]) + + const loadTrans = () => { + socket.emit("load transaction",state.user.id) + socket.on("transaction", (data) => { + setHistoryTransaction(data) + }) + } + return ( <> -
+

{data[0].title1}

- {data[0].img}/ + @@ -32,15 +86,15 @@ const ProfilePage = ({U}) => {
{data[0].titleName} - Andi + {user.fullname}
Email - xxx@company.com + {user.email}
Phone - 08xxxx + {user.phone}
@@ -48,21 +102,33 @@ const ProfilePage = ({U}) => {

{data[0].title2}

{/* Loop */} - + {historyTransaction.map((x) => { + return ( + <> +
- {data[0].history} + {isOwner? {x.buyer.fullname} : {x.seller.restos.title} } Saturday, 12 March 2021
- Total : Rp 45.000 + Total : {convertRupiah.convert(x.price)}
+ {x.status === 'Cancel' ? + + + {x.status} + : - - Finished - -
- + + {x.status} +
+ + } + + + ) + })}
diff --git a/src/components/Register/Register.style.js b/src/components/Register/Register.style.js index 6028e0a..5b956f6 100644 --- a/src/components/Register/Register.style.js +++ b/src/components/Register/Register.style.js @@ -33,17 +33,7 @@ export const Wrapper = styled.div` top:5%; } } - .singup2-cointainer { - background:white; - display: flex; - width: 416px; - height: 694px; - border-radius: 10px; - flex-direction: column; - align-items: center; - - /* margin: 10px solid black; */ - } + h2 { @import url('https://fonts.googleapis.com/css2?family=Abhaya+Libre:wght@800&family=Shippori+Antique+B1&display=swap'); font-family: 'Shippori Antique B1', sans-serif; @@ -54,52 +44,145 @@ export const Wrapper = styled.div` margin-right: 40%; color: #FFC700; } - form { + @media only screen and (max-width:1450px) { + h2 { @import url('https://fonts.googleapis.com/css2?family=Abhaya+Libre:wght@800&family=Shippori+Antique+B1&display=swap'); font-family: 'Shippori Antique B1', sans-serif; + font-style: normal; + font-weight: 900; + margin-top:60px; + font-size: 36px; + line-height: 19px; + margin-right: 40%; + color: #FFC700; + } + .singup2-cointainer { + background:white; + display: flex; + width: 416px; + height: 584px; + border-radius: 10px; + flex-direction: column; + align-items: center; + border:1px solid green; + flex-wrap: wrap; + + /* margin: 10px solid black; */ + } + form { + @import url('https://fonts.googleapis.com/css2?family=Abhaya+Libre:wght@800&family=Shippori+Antique+B1&display=swap'); + font-family: 'Shippori Antique B1', sans-serif; + height: 284% !important; + /* overflow: auto; */ + /* gap: 1rem */ + width: 80%; + justify-self: center; + align-items: center; + position: sticky; + + /* border:1px solid black; */ + } + form input { + @import url('https://fonts.googleapis.com/css2?family=Abhaya+Libre:wght@800&family=Shippori+Antique+B1&display=swap'); + font-family: 'Shippori Antique B1', sans-serif; + margin-bottom: 10px; + background-color: transparent; + display: block; + width: 100%; + background: rgba(210, 210, 210, 0.25); + border: 2px solid #D2D2D2; + border-radius: 5px; + height: 50px !important; + padding-left: 5px; + outline: none; + color: black; + } + form select { + @import url('https://fonts.googleapis.com/css2?family=Abhaya+Libre:wght@800&family=Shippori+Antique+B1&display=swap'); + font-family: 'Shippori Antique B1', sans-serif; + margin-bottom: 10px; + background-color: transparent; + display: block; + width: 100%; + background: rgba(210, 210, 210, 0.25); + border: 2px solid #D2D2D2; + border-radius: 5px; + height: 50px; + padding-left: 5px; + outline: none; + color: #B1B1B1; + text-align: left; + text-align-last: left; + } + } + p { + margin-top:0px; + text-align: center; + } + @media only screen and (min-width:1451px) { + .singup2-cointainer { + background:white; display: flex; + width: 416px; + height: 694px; + border-radius: 10px; flex-direction: column; - margin-top: 20%; - height: 544px; - justify-self: center; align-items: center; - position: sticky; - /* border:1px solid black; */ - } - form input { - @import url('https://fonts.googleapis.com/css2?family=Abhaya+Libre:wght@800&family=Shippori+Antique+B1&display=swap'); - font-family: 'Shippori Antique B1', sans-serif; - margin-bottom: 30px; - background-color: transparent; - display: block; - width: 100%; - border: none; - border-bottom: 2px solid #433434; - min-width: 250px; - padding-left: 5px; - outline: none; - color: black; + + /* margin: 10px solid black; */ } - form select { - @import url('https://fonts.googleapis.com/css2?family=Abhaya+Libre:wght@800&family=Shippori+Antique+B1&display=swap'); - font-family: 'Shippori Antique B1', sans-serif; - margin-bottom: 20px; - background-color: transparent; - display: block; - width: 100%; - border: none; - border-bottom: 2px solid #433434; - min-width: 250px; - padding-left: 5px; - outline: none; - color: #B1B1B1; - text-align: center; - text-align-last: center; + form { + /* @import url('https://fonts.googleapis.com/css2?family=Abhaya+Libre:wght@800&family=Shippori+Antique+B1&display=swap'); */ + /* font-family: 'Shippori Antique B1', sans-serif; */ + /* display: flex; */ + /* flex-direction: column; */ + /* margin-top: 5%; */ + /* height: 444px; */ + /* gap: 1rem */ + width: 80% !important; + /* justify-self: center; */ + /* align-items: center; */ + /* position: sticky; */ + + /* border:1px solid black; */ + } + form input { + @import url('https://fonts.googleapis.com/css2?family=Abhaya+Libre:wght@800&family=Shippori+Antique+B1&display=swap'); + font-family: 'Shippori Antique B1', sans-serif; + margin-bottom: 30px; + background-color: transparent; + display: block; + width: 100%; + background: rgba(210, 210, 210, 0.25); + border: 2px solid #D2D2D2; + border-radius: 5px; + height: 50px !important; + padding-left: 5px; + outline: none; + color: black; + } + form select { + @import url('https://fonts.googleapis.com/css2?family=Abhaya+Libre:wght@800&family=Shippori+Antique+B1&display=swap'); + font-family: 'Shippori Antique B1', sans-serif; + margin-bottom: 20px; + background-color: transparent; + display: block; + width: 100%; + background: rgba(210, 210, 210, 0.25); + border: 2px solid #D2D2D2; + border-radius: 5px; + height: 50px; + padding-left: 5px; + outline: none; + color: #B1B1B1; + text-align: center; + text-align-last: center; + } } form input::placeholder { @import url('https://fonts.googleapis.com/css2?family=Abhaya+Libre:wght@800&family=Shippori+Antique+B1&display=swap'); font-family: 'Shippori Antique B1', sans-serif; - text-align: center; + text-align: left; color: #B1B1B1; } .singup2-cointainer .x-button-singup2{ @@ -141,6 +224,7 @@ export const Wrapper = styled.div` line-height: 16px; min-height: 40px; outline: 0; + width: 100%; padding: 12px 14px; text-align: center; text-rendering: geometricprecision; diff --git a/src/components/Register/index.js b/src/components/Register/index.js index ef7d2d4..236fc88 100644 --- a/src/components/Register/index.js +++ b/src/components/Register/index.js @@ -1,34 +1,89 @@ -import { React, useState, useEffect } from 'react' - +import { React, useState, useEffect ,useContext } from 'react' +import {API, handleError} from '../../config/api' import { Wrapper ,Bg } from './Register.style' import Xbtns from '../../img/close.png'; +import { UserContext } from '../../Context/userContext'; +import { useNavigate} from 'react-router-dom' const Register = ({ showR , Cancel , toggle , RegisterSwitch ,}) => { + const {state, dispatch} = useContext(UserContext) let holder = showR; let [activeR, setActiveR] = useState(holder); useEffect(() => { setActiveR(!activeR); - },[holder]) - + }, [holder]) + const navigate = useNavigate() + const [Form, setForm] = useState({ + email: '', + password: '', + fullname: '', + gender: '', + phone: '', + role: '', + + }) + const handelChange = (e) => { + setForm({ + ...Form, + [e.target.name]: e.target.value + }) + } + const handelSubmit = async (e) => { + try { + e.preventDefault() + const config = { + headers: { + 'Content-Type': 'application/json' + } + } + const body = JSON.stringify(Form) + const response = await API.post("/register", body, config); + if (response?.status === 201) { + return alert(response.data.message) + } + + if (response?.status === 200) { + dispatch({ + status: 'login', + payload: response.data.data.user + }) + // RegisterSwitch() + } + console.log(response.data.data.user.role) + if (response.data.data.user.role === 'owner') { + navigate('/Transaction') + } + } catch (err) { + handleError(err) + if (err.response?.status === 400) { + alert(err.response.data.messsage) + } + } + } return (
-
+

Register

- - - - - - + + + + + - +

Already have an account ?

diff --git a/src/components/Resto/Resto.styled.js b/src/components/Resto/Resto.styled.js new file mode 100644 index 0000000..cf75774 --- /dev/null +++ b/src/components/Resto/Resto.styled.js @@ -0,0 +1,26 @@ +import styled from 'styled-components' + + +export const Wrapper = styled.div` + margin:0 auto; + display:flex; + /* border:1px solid black; */ + margin-top:70px; + width: 80%; + gap:1rem; + justify-content: space-between; + flex-wrap: wrap; + + h3 { + padding-left: 5%; + width: 100%; + display:block; + font-size: 40px; + margin:0; + font-family: 'Abhaya Libre ExtraBold'; + opacity:0.8; + } + .nonee { + text-decoration: none !important; + } +` \ No newline at end of file diff --git a/src/components/Resto/index.js b/src/components/Resto/index.js new file mode 100644 index 0000000..e5a5332 --- /dev/null +++ b/src/components/Resto/index.js @@ -0,0 +1,35 @@ +import Header from '../Header' +import {Link} from 'react-router-dom' +import { CardResto } from '../LandingPage/LandingPage.styled' +import { Wrapper } from './Resto.styled' +import { API, handleError } from '../../config/api' +import React,{ useEffect,useState } from 'react' + +const Resto = () => { + const [restos, setRestos] = useState([]) + useEffect(async() => { + await API.get('/restos') + .then((res) => { setRestos(res.data.data.restos) }) + },[]) + + return ( + <> +
+ +

Resto

+ {restos.map((resto) => { + return( + + + {resto.name} +

{resto.title}

+
+ + ) + })} +
+ + ) +} + +export default Resto \ No newline at end of file diff --git a/src/components/RouterSetup.js b/src/components/RouterSetup.js index f7e352d..a15ad27 100644 --- a/src/components/RouterSetup.js +++ b/src/components/RouterSetup.js @@ -1,4 +1,4 @@ -import React ,{useState,useEffect} from 'react'; +import React ,{useState,useEffect,useContext} from 'react'; //React router import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; @@ -11,24 +11,60 @@ import CartPage from './CartPage'; import AddProduct from './AddProduct'; import LandingPage from './LandingPage'; import Header from './Header'; +import Resto from './Resto'; +import AddResto from './AddResto' +import {API,setAuthToken, handleError} from '../config/api' +import { UserContext } from '../Context/userContext'; const RouterSetup = () => { - const [u, setU] = useState(false) - const sett = () => { setU(true) }; - const setf = () => { setU(false)}; - useEffect(() => {console.log(u)},[u]) + + const {state, dispatch} = useContext(UserContext) + const check = async () => { + try { + const res = await API.get('/login') + dispatch({ + status: 'login', + payload: res.data + }) + } catch (err) { + handleError(err) + } + } + useEffect(() => { + check() + }, []) + const { isLogin, user } = state + let isOwner = false + if (user?.role === 'owner') { + isOwner = true + } return ( - }/> - } /> - }/> - }/> + {isLogin ? + <> + }/> + }/> + }/> + {/* }/> */} + }/> + {isOwner ? + <> }/> - }/> - {u ? null: }/>} -

Error 404

}/> + }/> + }/> + + : + <> + }/> + } /> + + } + + : + } />} +

Error 404

}/> ) diff --git a/src/components/TransactionPage/TransactionPage.styled.js b/src/components/TransactionPage/TransactionPage.styled.js index 0fbccf2..ed2f231 100644 --- a/src/components/TransactionPage/TransactionPage.styled.js +++ b/src/components/TransactionPage/TransactionPage.styled.js @@ -4,7 +4,8 @@ export const Wrapper = styled.div` margin:0 auto; margin-top: 73px; /* border:1px solid black; */ - width: 80%; + max-width: 80%; + width:100%; h1 { font-size: 36px; line-height: 42px; @@ -33,7 +34,8 @@ export const Head = styled.th` ${props => props.n2 ? 'min-width:183px': null}; ${props => props.a ? ' min-width:280px': null}; ${props => props.p ? ' min-width:191px': null}; - ${props => props.s ? ' min-width:160px': null}; + ${props => props.s ? ' min-width:160px' : null}; + width:100%; font-family: 'Montserrat', sans-serif; text-align: ${props => props.m ? 'center' : 'left'}; ` @@ -62,7 +64,8 @@ export const TwoB = styled.button` border:none; color:white; background: ${props => props.a ? '#FF0742 !important' : '#0ACF83 !important'}; - width: 80px; + max-width: 80px; + width:100%; height: 20px; border-radius: 5px; &:hover{ diff --git a/src/components/TransactionPage/index.js b/src/components/TransactionPage/index.js index a8314c8..9701ed0 100644 --- a/src/components/TransactionPage/index.js +++ b/src/components/TransactionPage/index.js @@ -1,79 +1,65 @@ -import { React ,useState ,useEffect} from 'react'; - +import { React ,useState ,useEffect , useContext} from 'react'; +import {io} from 'socket.io-client' import Header from '../Header' import approve from '../../img/approve.svg' import cancel from '../../img/cancel.svg' import { Wrapper ,Head ,Tab ,Special ,TwoB} from './TransactionPage.styled'; +import {UserContext} from '../../Context/userContext' +import {API, handleError} from '../../config/api' + +let socket; const TransactionPage = () => { - const [res, setRes] = useState([ - { - id: 1, - val:true - }, - { - id:2, - val:false - }, - { - id: 3, - val:false - }, - { - id:4, - val:false - } - ]); - const [fin, setFin] = useState([ - { - id:1, - permit: null, - stat: 'w', - status: 'Waiting Approve', - data: { - name: 'Sugeng No Pants', - address: 'Cileungsi', - Product: 'Pkaket Geprek, Paket ke..' - } - }, - { - id:2, - permit: approve, - stat: 's', - status: 'Success', - data: { - name: 'Haris Gams', - address: 'Serang', - Product: 'Pkaket Geprek, Paket ke..' - } - }, - { - id:3, - permit: cancel, - stat: 'c', - status: 'Cancel', - data: { - name: 'Aziz Union', - address: 'Bekasi', - Product: 'Pkaket Geprek, Paket ke..' - } - }, - { - id:4, - permit: approve, - stat: 'o', - status: 'On The Way', - data: { - name: 'Lae Tanjung Balai', - address: 'Tanjung Balai', - Product: 'Pkaket Geprek, Paket ke..' - } - }, - - ]); + const { state, dispatch } = useContext(UserContext) + const [refresh, setRefresh] = useState(false) + const [transaction, setTransaction] = useState([]) + const [firstHolder , setFirstHolder] = useState(false) useEffect(() => { - console.log(fin[0],fin[1]) - },[fin]) + socket = io('http://localhost:5000', { + auth: { + token: localStorage.getItem("token") + }, + query: { + id: state.user.id + } + }) + socket.on('connect', () => { + console.log(socket); + }) + // socket.on('new transaction', (x) => { + // console.log(x) + // socket.emit('transaction') + // Transaction() + // }) + if (firstHolder === false) { + setFirstHolder(true) + } + socket.emit('transaction') + socket.on("connect_error", (err) => { + console.error(err.message); + }); + Transaction() + return () => { + socket.disconnect() + } + }, [transaction]) + + const Approve = (x) => { + socket.emit('otw') + socket.emit('accept', x) + setRefresh(!refresh) + } + const Cancel = (x) => { + socket.emit('cancel', x) + setRefresh(!refresh) + } + const Transaction = () => { + socket.on('transactionData', (data) => { + setTransaction(data) + console.log(data) + }) + } + let count = 0 return ( <>
@@ -89,75 +75,34 @@ const TransactionPage = () => { Action {/* TC~REPEAT */} - {fin.map((_) => { - const id = _.id - 1 - console.log(id) + {transaction.map((_) => { + count = count + 1 return ( - - {_.id} - {_.data.name} - {_.data.address} - {_.data.Product} - {_.stat === `w`? {_.status} : null} - {_.stat === `s`? {_.status} : null} - {_.stat === `c`? {_.status} : null} - {_.stat === `o`? {_.status} : null} - - - {res[id].val ? ( - <> - { - setFin(fin.map((x) => { - if (x.id === 1) { - return { - ...x, - permit: cancel, - stat: 'c', - status: 'Cancel' - } - } else {return {...x}} - })) - setRes(res.map((x) => { - if(x.id === 1){ - return { - ...x , - val:false - } - } else {return {...x}} - }) - ) - }} - a>Cancel - { - setFin(fin.map((x) => { - if (x.id === 1) { - return { - ...x, - permit: approve, - stat: 's', - status: 'Complete' - } - } else {return {...x}} - })) - setRes(res.map((x) => { - if(x.id === 1){ - return { - ...x , - val:false - } - } else {return {...x}} - }) - ) - }}>Aprove - - ) - : {`${_.permit}`} - } - - + + {count} + {_.buyer.fullname} + {_.address} + {_.product.map((x) => { + return(x.title+',') + })} + {_.status === `Waiting Approve`? {_.status} : null} + {_.status === `Success`? {_.status} : null} + {_.status === `Cancel`? {_.status} : null} + {_.status === `On The Way`? {_.status} : null} + + {_.status === `Waiting Approve` ? + <> + {Cancel(_.id)}}a>Cancel + {Approve(_.id)}}>Aprove + + : <> + {_.status === `Cancel`? {`${cancel}`} :{`${approve}`} } + + } + + ) })} - diff --git a/src/config/api.js b/src/config/api.js new file mode 100644 index 0000000..98fbd9c --- /dev/null +++ b/src/config/api.js @@ -0,0 +1,30 @@ +import axios from 'axios'; + +export const API = axios.create({ + baseURL: "http://localhost:5000/api/v1/", +}) + +// export const setAuthToken = (token) => { +// if (token) { +// API.defaults.headers.common['Authorization'] = `Bearer ${token}` +// } else { +// delete API.defaults.headers.common['Authorization'] +// } +// } + +export const handleError = (err) => { + if (err.response) { + console.log(err.response.data) + console.log(err.response.data.message) + console.log(err.response.status) + } + if (err.response?.status === 401) { + alert(err.response.data.err) + } + if (err.response === 404) { + console.log('page not found') + } else if (err.request) { + console.error(err.request) + console.error(err.massage) + } +} \ No newline at end of file diff --git a/src/img/disabled.png b/src/img/disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..d598e115ed0beb1a80f68d6bf9d61374d13b00c5 GIT binary patch literal 9553 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 ar-0f=s#kcY7d!wBz;7C8R@|_C@;?CWydh`+ literal 0 HcmV?d00001 diff --git a/src/index.js b/src/index.js index 4135be0..c3db5ff 100644 --- a/src/index.js +++ b/src/index.js @@ -4,9 +4,10 @@ import './index.css'; import App from './App'; + ReactDOM.render( - + , document.getElementById('root') );