diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index 873f5d3d2..6f1a8d91c 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -1,9 +1,10 @@ /* eslint-disable max-lines */ require('./editPage.less'); +require('../../styles/nav-item-error-container.less'); const React = require('react'); const createClass = require('create-react-class'); const _ = require('lodash'); -const request = require('superagent'); +const request = require('../../utils/request-middleware.js'); const { Meta } = require('vitreum/headtags'); const Nav = require('naturalcrit/nav/nav.jsx'); @@ -45,7 +46,7 @@ const EditPage = createClass({ alertLoginToTransfer : false, saveGoogle : this.props.brew.googleId ? true : false, confirmGoogleTransfer : false, - errors : null, + error : null, htmlErrors : Markdown.validate(this.props.brew.text), url : '', autoSave : true, @@ -60,7 +61,6 @@ const EditPage = createClass({ url : window.location.href }); - this.savedBrew = JSON.parse(JSON.stringify(this.props.brew)); //Deep copy this.setState({ autoSave: JSON.parse(localStorage.getItem('AUTOSAVE_ON')) ?? true }, ()=>{ @@ -157,7 +157,10 @@ const EditPage = createClass({ this.setState((prevState)=>({ confirmGoogleTransfer : !prevState.confirmGoogleTransfer })); - this.clearErrors(); + this.setState({ + error : null, + isSaving : false + }); }, closeAlerts : function(event){ @@ -173,24 +176,16 @@ const EditPage = createClass({ this.setState((prevState)=>({ saveGoogle : !prevState.saveGoogle, isSaving : false, - errors : null + error : null }), ()=>this.save()); }, - clearErrors : function(){ - this.setState({ - errors : null, - isSaving : false - - }); - }, - save : async function(){ if(this.debounceSave && this.debounceSave.cancel) this.debounceSave.cancel(); this.setState((prevState)=>({ isSaving : true, - errors : null, + error : null, htmlErrors : Markdown.validate(prevState.brew.text) })); @@ -205,8 +200,9 @@ const EditPage = createClass({ .send(brew) .catch((err)=>{ console.log('Error Updating Local Brew'); - this.setState({ errors: err }); + this.setState({ error: err.response }); }); + if(!res) return; this.savedBrew = res.body; history.replaceState(null, null, `/edit/${this.savedBrew.editId}`); @@ -266,75 +262,8 @@ const EditPage = createClass({ }, renderSaveButton : function(){ - if(this.state.errors){ - let errMsg = ''; - try { - errMsg += `${this.state.errors.toString()}\n\n`; - errMsg += `\`\`\`\n${this.state.errors.stack}\n`; - errMsg += `${JSON.stringify(this.state.errors.response.error, null, ' ')}\n\`\`\``; - console.log(errMsg); - } catch (e){} - - // if(this.state.errors.status == '401'){ - // return - // Oops! - //
- // You must be signed in to a Google account - // to save this to
Google Drive!
- // - //
- // Sign In - //
- //
- //
- // Not Now - //
- //
- //
; - // } - - if(this.state.errors.response.req.url.match(/^\/api.*Google.*$/m)){ - return - Oops! -
- Looks like your Google credentials have - expired! Visit our log in page to sign out - and sign back in with Google, - then try saving again! - -
- Sign In -
-
-
- Not Now -
-
-
; - } - - if(this.state.errors.response.error.status === 409) { - const message = this.state.errors.response.body?.message; - return - Oops! -
- {message ? message : 'Conflict: please refresh to get latest changes'} -
-
; - } - - return - Oops! -
- Looks like there was a problem saving.
- Report the issue - here - . -
-
; + if(this.state.error){ + return require('../../utils/render-error-nav-item.js')(this, this.state.error); } if(this.state.autoSaveWarning && this.hasChanges()){ diff --git a/client/homebrew/pages/editPage/editPage.less b/client/homebrew/pages/editPage/editPage.less index 9d3f69221..2eb212f3f 100644 --- a/client/homebrew/pages/editPage/editPage.less +++ b/client/homebrew/pages/editPage/editPage.less @@ -26,74 +26,4 @@ padding : 0px; margin : -5px; } - .errorContainer{ - animation-name: glideDown; - animation-duration: 0.4s; - position : absolute; - top : 100%; - left : 50%; - z-index : 500; - width : 140px; - padding : 3px; - color : white; - background-color : #333; - border : 3px solid #444; - border-radius : 5px; - transform : translate(-50% + 3px, 10px); - text-align : center; - font-size : 10px; - font-weight : 800; - text-transform : uppercase; - a{ - color : @teal; - } - &:before { - content: ""; - width: 0px; - height: 0px; - position: absolute; - border-left: 10px solid transparent; - border-right: 10px solid transparent; - border-top: 10px solid transparent; - border-bottom: 10px solid #444; - left: 53px; - top: -23px; - } - &:after { - content: ""; - width: 0px; - height: 0px; - position: absolute; - border-left: 10px solid transparent; - border-right: 10px solid transparent; - border-top: 10px solid transparent; - border-bottom: 10px solid #333; - left: 53px; - top: -19px; - } - .deny { - width : 48%; - margin : 1px; - padding : 5px; - background-color : #333; - display : inline-block; - border-left : 1px solid #666; - .animate(background-color); - &:hover{ - background-color : red; - } - } - .confirm { - width : 48%; - margin : 1px; - padding : 5px; - background-color : #333; - display : inline-block; - color : white; - .animate(background-color); - &:hover{ - background-color : teal; - } - } - } } diff --git a/client/homebrew/pages/homePage/homePage.jsx b/client/homebrew/pages/homePage/homePage.jsx index 7e9d9c3b4..228a406d7 100644 --- a/client/homebrew/pages/homePage/homePage.jsx +++ b/client/homebrew/pages/homePage/homePage.jsx @@ -1,9 +1,10 @@ require('./homePage.less'); +require('../../styles/nav-item-error-container.less'); const React = require('react'); const createClass = require('create-react-class'); const _ = require('lodash'); const cx = require('classnames'); -const request = require('superagent'); +const request = require('../../utils/request-middleware.js'); const { Meta } = require('vitreum/headtags'); const Nav = require('naturalcrit/nav/nav.jsx'); @@ -31,14 +32,18 @@ const HomePage = createClass({ getInitialState : function() { return { brew : this.props.brew, - welcomeText : this.props.brew.text + welcomeText : this.props.brew.text, + error : undefined }; }, handleSave : function(){ request.post('/api') .send(this.state.brew) .end((err, res)=>{ - if(err) return; + if(err) { + this.setState({ error: err.response }); + return; + } const brew = res.body; window.location = `/edit/${brew.editId}`; }); @@ -51,9 +56,16 @@ const HomePage = createClass({ brew : { ...prevState.brew, text: text } })); }, + renderSaveError : function(){ + if(this.state.error) { + return require('../../utils/render-error-nav-item.js')(this, this.state.error); + } + return null; + }, renderNavbar : function(){ return + {this.renderSaveError()} diff --git a/client/homebrew/pages/homePage/homePage.less b/client/homebrew/pages/homePage/homePage.less index 719e89f22..b0320d8d2 100644 --- a/client/homebrew/pages/homePage/homePage.less +++ b/client/homebrew/pages/homePage/homePage.less @@ -40,4 +40,15 @@ right : 350px; } } + + .navItem.save{ + background-color: @orange; + &:hover{ + background-color: @green; + } + &.error{ + position : relative; + background-color : @red; + } + } } diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx index cd197f5fb..8f9fc7649 100644 --- a/client/homebrew/pages/newPage/newPage.jsx +++ b/client/homebrew/pages/newPage/newPage.jsx @@ -1,9 +1,10 @@ /*eslint max-lines: ["warn", {"max": 300, "skipBlankLines": true, "skipComments": true}]*/ require('./newPage.less'); +require('../../styles/nav-item-error-container.less'); const React = require('react'); const createClass = require('create-react-class'); const _ = require('lodash'); -const request = require('superagent'); +const request = require('../../utils/request-middleware.js'); const Markdown = require('naturalcrit/markdown.js'); @@ -39,7 +40,7 @@ const NewPage = createClass({ brew : brew, isSaving : false, saveGoogle : (global.account && global.account.googleId ? true : false), - errors : null, + error : null, htmlErrors : Markdown.validate(brew.text) }; }, @@ -122,14 +123,6 @@ const NewPage = createClass({ })); }, - clearErrors : function(){ - this.setState({ - errors : null, - isSaving : false - - }); - }, - save : async function(){ this.setState({ isSaving : true @@ -152,7 +145,7 @@ const NewPage = createClass({ .send(brew) .catch((err)=>{ console.log(err); - this.setState({ isSaving: false, errors: err }); + this.setState({ isSaving: false, error: err.response }); }); if(!res) return; @@ -164,65 +157,8 @@ const NewPage = createClass({ }, renderSaveButton : function(){ - if(this.state.errors){ - let errMsg = ''; - try { - errMsg += `${this.state.errors.toString()}\n\n`; - errMsg += `\`\`\`\n${this.state.errors.stack}\n`; - errMsg += `${JSON.stringify(this.state.errors.response.error, null, ' ')}\n\`\`\``; - console.log(errMsg); - } catch (e){} - - // if(this.state.errors.status == '401'){ - // return - // Oops! - //
- // You must be signed in to a Google account - // to save this to
Google Drive!
- // - //
- // Sign In - //
- //
- //
- // Not Now - //
- //
- //
; - // } - - if(this.state.errors.response.req.url.match(/^\/api.*Google.*$/m)){ - return - Oops! -
- Looks like your Google credentials have - expired! Visit our log in page to sign out - and sign back in with Google, - then try saving again! - -
- Sign In -
-
-
- Not Now -
-
-
; - } - - return - Oops! -
- Looks like there was a problem saving.
- Report the issue - here - . -
-
; + if(this.state.error){ + return require('../../utils/render-error-nav-item.js')(this, this.state.error); } if(this.state.isSaving){ diff --git a/client/homebrew/pages/newPage/newPage.less b/client/homebrew/pages/newPage/newPage.less index 4f39e626d..eb80cad38 100644 --- a/client/homebrew/pages/newPage/newPage.less +++ b/client/homebrew/pages/newPage/newPage.less @@ -9,74 +9,4 @@ background-color : @red; } } - .errorContainer{ - animation-name: glideDown; - animation-duration: 0.4s; - position : absolute; - top : 100%; - left : 50%; - z-index : 100000; - width : 140px; - padding : 3px; - color : white; - background-color : #333; - border : 3px solid #444; - border-radius : 5px; - transform : translate(-50% + 3px, 10px); - text-align : center; - font-size : 10px; - font-weight : 800; - text-transform : uppercase; - a{ - color : @teal; - } - &:before { - content: ""; - width: 0px; - height: 0px; - position: absolute; - border-left: 10px solid transparent; - border-right: 10px solid transparent; - border-top: 10px solid transparent; - border-bottom: 10px solid #444; - left: 53px; - top: -23px; - } - &:after { - content: ""; - width: 0px; - height: 0px; - position: absolute; - border-left: 10px solid transparent; - border-right: 10px solid transparent; - border-top: 10px solid transparent; - border-bottom: 10px solid #333; - left: 53px; - top: -19px; - } - .deny { - width : 48%; - margin : 1px; - padding : 5px; - background-color : #333; - display : inline-block; - border-left : 1px solid #666; - .animate(background-color); - &:hover{ - background-color : red; - } - } - .confirm { - width : 48%; - margin : 1px; - padding : 5px; - background-color : #333; - display : inline-block; - color : white; - .animate(background-color); - &:hover{ - background-color : teal; - } - } - } } diff --git a/client/homebrew/styles/nav-item-error-container.less b/client/homebrew/styles/nav-item-error-container.less new file mode 100644 index 000000000..2161208c2 --- /dev/null +++ b/client/homebrew/styles/nav-item-error-container.less @@ -0,0 +1,72 @@ +.navItem { + .errorContainer{ + animation-name: glideDown; + animation-duration: 0.4s; + position : absolute; + top : 100%; + left : 50%; + z-index : 500; + width : 140px; + padding : 3px; + color : white; + background-color : #333; + border : 3px solid #444; + border-radius : 5px; + transform : translate(-50% + 3px, 10px); + text-align : center; + font-size : 10px; + font-weight : 800; + text-transform : uppercase; + a{ + color : @teal; + } + &:before { + content: ""; + width: 0px; + height: 0px; + position: absolute; + border-left: 10px solid transparent; + border-right: 10px solid transparent; + border-top: 10px solid transparent; + border-bottom: 10px solid #444; + left: 53px; + top: -23px; + } + &:after { + content: ""; + width: 0px; + height: 0px; + position: absolute; + border-left: 10px solid transparent; + border-right: 10px solid transparent; + border-top: 10px solid transparent; + border-bottom: 10px solid #333; + left: 53px; + top: -19px; + } + .deny { + width : 48%; + margin : 1px; + padding : 5px; + background-color : #333; + display : inline-block; + border-left : 1px solid #666; + .animate(background-color); + &:hover{ + background-color : red; + } + } + .confirm { + width : 48%; + margin : 1px; + padding : 5px; + background-color : #333; + display : inline-block; + color : white; + .animate(background-color); + &:hover{ + background-color : teal; + } + } + } +} \ No newline at end of file diff --git a/client/homebrew/utils/render-error-nav-item.js b/client/homebrew/utils/render-error-nav-item.js new file mode 100644 index 000000000..bf3960a29 --- /dev/null +++ b/client/homebrew/utils/render-error-nav-item.js @@ -0,0 +1,71 @@ +const React = require('react'); +const Nav = require('naturalcrit/nav/nav.jsx'); + +module.exports = function(component, error){ + const clearError = ()=>{ + const state = { + error : null + }; + if(component.state.isSaving) { + state.isSaving = false; + } + component.setState(state); + }; + + const status = error.status; + const message = error.body?.message; + let errMsg = ''; + try { + errMsg += `${error.toString()}\n\n`; + errMsg += `\`\`\`\n${error.stack}\n`; + errMsg += `${JSON.stringify(error.error, null, ' ')}\n\`\`\``; + console.log(errMsg); + } catch (e){} + + if(status === 409) { + return + Oops! +
+ {message ?? 'Conflict: please refresh to get latest changes'} +
+
; + } else if(status === 412) { + return + Oops! +
+ {message ?? 'Your client is out of date. Please save your changes elsewhere and refresh.'} +
+
; + } + + if(error.req.url.match(/^\/api.*Google.*$/m)){ + return + Oops! +
+ Looks like your Google credentials have + expired! Visit our log in page to sign out + and sign back in with Google, + then try saving again! + +
+ Sign In +
+
+
+ Not Now +
+
+
; + } + + return + Oops! +
+ Looks like there was a problem saving.
+ Report the issue + here + . +
+
; +}; \ No newline at end of file diff --git a/client/homebrew/utils/request-middleware.js b/client/homebrew/utils/request-middleware.js new file mode 100644 index 000000000..441218521 --- /dev/null +++ b/client/homebrew/utils/request-middleware.js @@ -0,0 +1,12 @@ +const request = require('superagent'); + +const addHeader = (request)=>request.set('Homebrewery-Version', sessionStorage.getItem('version')); + +const requestMiddleware = { + get : (path)=>addHeader(request.get(path)), + put : (path)=>addHeader(request.put(path)), + post : (path)=>addHeader(request.post(path)), + delete : (path)=>addHeader(request.delete(path)), +}; + +module.exports = requestMiddleware; \ No newline at end of file diff --git a/client/template.js b/client/template.js index cab4790b9..a36a04f12 100644 --- a/client/template.js +++ b/client/template.js @@ -22,6 +22,9 @@ const template = async function(name, title='', props = {}){
${require(`../build/${name}/ssr.js`)(props)}
+ diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 550da0ddd..e108a3946 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -336,6 +336,7 @@ If you believe you should have access to this brew, ask the file owner to invite } }; +router.use('/api', require('./middleware.js').versionMismatch); router.post('/api', asyncHandler(api.newBrew)); router.put('/api/:id', asyncHandler(api.getBrew('edit', true)), asyncHandler(api.updateBrew)); router.put('/api/update/:id', asyncHandler(api.getBrew('edit', true)), asyncHandler(api.updateBrew)); diff --git a/server/middleware.js b/server/middleware.js new file mode 100644 index 000000000..2d40d7263 --- /dev/null +++ b/server/middleware.js @@ -0,0 +1,17 @@ +const middleware = { + versionMismatch : (req, res, next)=>{ + const userVersion = req.get('Homebrewery-Version'); + const version = require('./../package.json').version; + + if(userVersion != version) { + console.warn(`Version mismatch -- expected: ${version}, actual: ${userVersion}`); + return res.status(412).send({ + message : `Client version ${userVersion} is out of date. Please save your changes elsewhere and refresh to pick up client version ${version}.` + }); + } + + next(); + } +}; + +module.exports = middleware; \ No newline at end of file