From 68ea655ac78323e0dae8b88fe3c0e68d50903e9f Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Tue, 14 Jan 2020 16:12:51 -0800 Subject: [PATCH] Doc upload in progress. --- .env | 3 + README.MD | 2 +- _business_logic/NewShopSetup.md | 5 + _business_logic/jobs.md | 4 + bodyshop_translations.babel | 21 +++ client/package.json | 1 + .../jobs-documents.container.jsx | 6 + .../jobs-documents/jobs-documents.page.jsx | 158 ++++++++++++++++++ .../jobs-documents/jobs-documents.styles.scss | 10 ++ client/src/pages/manage/manage.page.jsx | 13 +- client/src/translations/en_us/common.json | 1 + client/src/translations/es/common.json | 3 +- client/src/translations/fr/common.json | 3 +- client/yarn.lock | 23 ++- package.json | 1 + s3upload.js | 46 +++++ server.js | 3 + yarn.lock | 81 ++++++++- 18 files changed, 373 insertions(+), 11 deletions(-) create mode 100644 _business_logic/NewShopSetup.md create mode 100644 _business_logic/jobs.md create mode 100644 client/src/pages/jobs-documents/jobs-documents.container.jsx create mode 100644 client/src/pages/jobs-documents/jobs-documents.page.jsx create mode 100644 client/src/pages/jobs-documents/jobs-documents.styles.scss create mode 100644 s3upload.js diff --git a/.env b/.env index e69de29bb..8a928d5fe 100644 --- a/.env +++ b/.env @@ -0,0 +1,3 @@ +AWSAccessKeyId=AKIAJYNXY5KCA25PB2JA +AWSSecretKey=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 +Bucket=bodyshop-app-dev \ No newline at end of file diff --git a/README.MD b/README.MD index a106682e9..832eb149d 100644 --- a/README.MD +++ b/README.MD @@ -6,4 +6,4 @@ Hasura is hosted on another dyno. Several environmental variables are required, ALL CHANGES MUST BE MADE USING LOCAL CONSOLE TO ENSURE DATABASE MIGRATION FILES ARE CREATED. To Start Hasura CLI: -npx hasura console --admin-secret Dev-BodyShopAppBySnaptSoftware! \ No newline at end of file +npx hasura console --admin-secret Dev-BodyShopAppBySnaptSoftware! diff --git a/_business_logic/NewShopSetup.md b/_business_logic/NewShopSetup.md new file mode 100644 index 000000000..ea98e6910 --- /dev/null +++ b/_business_logic/NewShopSetup.md @@ -0,0 +1,5 @@ +**Required items** + + +-Bodyshop Record +-Counter Record - type: ronum \ No newline at end of file diff --git a/_business_logic/jobs.md b/_business_logic/jobs.md new file mode 100644 index 000000000..a9236ee48 --- /dev/null +++ b/_business_logic/jobs.md @@ -0,0 +1,4 @@ +**Jobs Business Logic** + +**Converting to RO** +Job will convert to an RO if the converted flag is set to true, and the RO number is null or empty. It will query the counters table for the type of 'ro_num', increment it, and return the old value to paste into the RO. \ No newline at end of file diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index 8bda8c2cf..89f625184 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -1371,6 +1371,27 @@ + + jobsdocuments + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + profile false diff --git a/client/package.json b/client/package.json index 403dc2141..da73421a8 100644 --- a/client/package.json +++ b/client/package.json @@ -10,6 +10,7 @@ "apollo-link-error": "^1.1.12", "apollo-link-logger": "^1.2.3", "apollo-link-ws": "^1.0.19", + "axios": "^0.19.1", "chart.js": "^2.9.3", "dotenv": "^8.2.0", "firebase": "^7.5.0", diff --git a/client/src/pages/jobs-documents/jobs-documents.container.jsx b/client/src/pages/jobs-documents/jobs-documents.container.jsx new file mode 100644 index 000000000..85329e289 --- /dev/null +++ b/client/src/pages/jobs-documents/jobs-documents.container.jsx @@ -0,0 +1,6 @@ +import React from "react"; +import JobDocuments from "./jobs-documents.page"; + +export default function JobsDocumentsContainer() { + return ; +} diff --git a/client/src/pages/jobs-documents/jobs-documents.page.jsx b/client/src/pages/jobs-documents/jobs-documents.page.jsx new file mode 100644 index 000000000..9c22f963f --- /dev/null +++ b/client/src/pages/jobs-documents/jobs-documents.page.jsx @@ -0,0 +1,158 @@ +import React, { useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { Upload, Modal, Icon } from "antd"; +import axios from "axios"; +import "./jobs-documents.styles.scss"; + +function getBase64(file) { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = () => resolve(reader.result); + reader.onerror = error => reject(error); + }); +} + +function JobsDetailPage({ match, loading, data }) { + //const { jobId } = match.params; + const { t } = useTranslation(); + + useEffect(() => { + document.title = loading + ? "..." + : t("titles.jobsdocuments", { + ro_number: data.jobs_by_pk.ro_number + }); + }, [t, loading, data]); + + const [state, setState] = useState({ + previewVisible: false, + previewImage: "", + fileList: [ + { + uid: "-1", + name: "image.png", + status: "done", + url: + "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" + }, + { + uid: "-2", + name: "image.png", + status: "done", + url: + "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" + }, + { + uid: "-3", + name: "image.png", + status: "done", + url: + "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" + }, + { + uid: "-4", + name: "image.png", + status: "done", + url: + "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" + }, + { + uid: "-5", + name: "image.png", + status: "error" + } + ] + }); + + const handleUpload = ev => { + console.log("Handle Upload.", ev); + let file = ev.file; + // Split the filename to get the name and type + let fileName = ev.file.name; + let fileType = ev.file.type; + console.log("Preparing the upload"); + axios + .post("https://localhost:5000/sign_s3", { + fileName: fileName, + fileType: fileType + }) + .then(response => { + var returnData = response.data.data.returnData; + var signedRequest = returnData.signedRequest; + var url = returnData.url; + this.setState({ url: url }); + console.log("Recieved a signed request " + signedRequest); + + // Put the fileType in the headers for the upload + var options = { + headers: { + "Content-Type": fileType + } + }; + axios + .put(signedRequest, file, options) + .then(result => { + console.log("Response from s3"); + this.setState({ success: true }); + }) + .catch(error => { + alert("ERROR " + JSON.stringify(error)); + }); + }) + .catch(error => { + console.log("Error here."); + alert(JSON.stringify(error)); + }); + }; + + const handleCancel = () => setState({ ...state, previewVisible: false }); + + const handlePreview = async file => { + if (!file.url && !file.preview) { + file.preview = await getBase64(file.originFileObj); + } + + setState({ + ...state, + previewImage: file.url || file.preview, + previewVisible: true + }); + }; + + const handleChange = ({ fileList }) => setState({ ...state, fileList }); + + const { previewVisible, previewImage, fileList } = state; + const uploadButton = ( +
+ +
Upload
+
+ ); + + const transformFile = props => { + console.log("Transforming file.", props); + //Make the image smaller here. + return props; + }; + + return ( +
+ + {fileList.length >= 8 ? null : uploadButton} + + + example + +
+ ); +} +export default JobsDetailPage; diff --git a/client/src/pages/jobs-documents/jobs-documents.styles.scss b/client/src/pages/jobs-documents/jobs-documents.styles.scss new file mode 100644 index 000000000..6df357ffc --- /dev/null +++ b/client/src/pages/jobs-documents/jobs-documents.styles.scss @@ -0,0 +1,10 @@ +/* you can make up upload button and sample style by using stylesheets */ +.ant-upload-select-picture-card i { + font-size: 32px; + color: #999; +} + +.ant-upload-select-picture-card .ant-upload-text { + margin-top: 8px; + color: #666; +} diff --git a/client/src/pages/manage/manage.page.jsx b/client/src/pages/manage/manage.page.jsx index 9d84f3c08..2ad279364 100644 --- a/client/src/pages/manage/manage.page.jsx +++ b/client/src/pages/manage/manage.page.jsx @@ -12,6 +12,9 @@ const WhiteBoardPage = lazy(() => import("../white-board/white-board.page")); const JobsPage = lazy(() => import("../jobs/jobs.page")); const JobsDetailPage = lazy(() => import("../jobs-detail/jobs-detail.page")); const ProfilePage = lazy(() => import("../profile/profile.container.page")); +const JobsDocumentsPage = lazy(() => + import("../jobs-documents/jobs-documents.container") +); const { Header, Content, Footer } = Layout; //This page will handle all routing for the entire application. @@ -31,16 +34,20 @@ export default function Manage({ match }) { TODO: Suspended Loading in Manage Page...} - > + fallback={
TODO: Suspended Loading in Manage Page...
}> - + { + console.log("Hitting bucket: " + S3_BUCKET); + const s3 = new aws.S3(); // Create a new instance of S3 + if (!req.body.fileName || req.body.fileType) { + res.json({ success: false, error: "fileName or fileType missing." }); + console.log("Error: fileName or fileType missing. "); + return; + } + + const fileName = req.body.fileName; + const fileType = req.body.fileType; + // Set up the payload of what we are sending to the S3 api + const s3Params = { + Bucket: S3_BUCKET, + Key: fileName, + Expires: 500, + ContentType: fileType, + ACL: "public-read" + }; + // Make a request to the S3 API to get a signed URL which we can use to upload our file + s3.getSignedUrl("putObject", s3Params, (err, data) => { + if (err) { + console.log(err); + res.json({ success: false, error: err }); + } + // Data payload of what we are sending back, the url of the signedRequest and a URL where we can access the content after its saved. + const returnData = { + signedRequest: data, + url: `https://${S3_BUCKET}.s3.amazonaws.com/${fileName}` + }; + // Send it all back + res.json({ success: true, data: { returnData } }); + }); +}; diff --git a/server.js b/server.js index 8f9070773..617446f39 100644 --- a/server.js +++ b/server.js @@ -31,3 +31,6 @@ app.listen(port, error => { if (error) throw error; console.log("Server running on port " + port); }); + +var s3upload = require("./s3upload"); +app.get("/sign_s3", s3upload.sign_s3); diff --git a/yarn.lock b/yarn.lock index f59bc1770..ee298a6d4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -386,6 +386,21 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= +aws-sdk@^2.603.0: + version "2.603.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.603.0.tgz#0920756d2666f4fcfa7233841ef35cd04da81348" + integrity sha512-+VlskUDLZLQDDlaVa0Tb02aEFEWcKkTfTew1SGYwce9hUrKcR33IX4e9kM6MyI7UeLQAl0v8dagTniP67UrTQw== + dependencies: + buffer "4.9.1" + events "1.1.1" + ieee754 "1.1.13" + jmespath "0.15.0" + querystring "0.2.0" + sax "1.2.1" + url "0.10.3" + uuid "3.3.2" + xml2js "0.4.19" + aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" @@ -527,6 +542,15 @@ buffer-indexof-polyfill@~1.0.0: resolved "https://registry.yarnpkg.com/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.1.tgz#a9fb806ce8145d5428510ce72f278bb363a638bf" integrity sha1-qfuAbOgUXVQoUQznLyeLs2OmOL8= +buffer@4.9.1: + version "4.9.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + integrity sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg= + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + buffer@^5.1.0: version "5.4.3" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.4.3.tgz#3fbc9c69eb713d323e3fc1a895eee0710c072115" @@ -1331,6 +1355,11 @@ event-target-shim@^5.0.0: resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== +events@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ= + execa@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" @@ -1984,7 +2013,7 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -ieee754@^1.1.4: +ieee754@1.1.13, ieee754@^1.1.4: version "1.1.13" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== @@ -2230,7 +2259,7 @@ isarray@0.0.1: resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= -isarray@~1.0.0: +isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= @@ -2250,6 +2279,11 @@ jju@^1.1.0: resolved "https://registry.yarnpkg.com/jju/-/jju-1.4.0.tgz#a3abe2718af241a2b2904f84a625970f389ae32a" integrity sha1-o6vicYryQaKykE+EpiWXDzia4yo= +jmespath@0.15.0: + version "0.15.0" + resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" + integrity sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc= + join-path@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/join-path/-/join-path-1.1.1.tgz#10535a126d24cbd65f7ffcdf15ef2e631076b505" @@ -3179,6 +3213,11 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= + punycode@^1.3.2, punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" @@ -3204,6 +3243,11 @@ qs@~6.5.2: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= + range-parser@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" @@ -3447,6 +3491,16 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +sax@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" + integrity sha1-e45lYZCyKOgaZq6nSEgNgozS03o= + +sax@>=0.6.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + semver-diff@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" @@ -4045,6 +4099,14 @@ url-parse-lax@^1.0.0: dependencies: prepend-http "^1.0.1" +url@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" + integrity sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ= + dependencies: + punycode "1.3.2" + querystring "0.2.0" + util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -4055,6 +4117,11 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= +uuid@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== + uuid@^2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" @@ -4196,7 +4263,15 @@ xdg-basedir@^3.0.0: resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ= -xmlbuilder@^9.0.7: +xml2js@0.4.19: + version "0.4.19" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" + integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q== + dependencies: + sax ">=0.6.0" + xmlbuilder "~9.0.1" + +xmlbuilder@^9.0.7, xmlbuilder@~9.0.1: version "9.0.7" resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=