diff --git a/client/public/editor.js b/client/public/editor.js index 8fdef23aa..26893c6a1 100644 --- a/client/public/editor.js +++ b/client/public/editor.js @@ -1,112 +1,95 @@ -unlayer.registerPropertyEditor({ - name: "my_color_picker", - layout: "bottom", - Widget: unlayer.createWidget({ - render(value) { - return ` - - - - - `; - }, - mount(node, value, updateValue) { - var input = node.getElementsByClassName("color-value")[0]; - input.onchange = function (event) { - updateValue(event.target.value); - }; +// unlayer.registerPropertyEditor({ +// name: "field_name", +// layout: "bottom", +// Widget: unlayer.createWidget({ +// render(value) { +// return ` +// +// `; +// }, +// mount(node, value, updateValue) { +// var input = node.getElementsByClassName("field")[0]; +// input.onchange = function (event) { +// updateValue(event.target.value); +// }; +// }, +// }), +// }); - var redButton = node.getElementsByClassName("red")[0]; - redButton.onclick = function () { - updateValue("#f00"); - }; +// unlayer.registerTool({ +// type: "whatever", +// category: "contents", +// label: "Begin Repeat", +// icon: "fa-smile", +// values: {}, +// options: { +// default: { +// title: null, +// }, +// text: { +// title: "Field", +// position: 1, +// options: { +// field: { +// label: "Field", +// defaultValue: "", +// widget: "field_name", +// }, +// }, +// }, +// }, +// renderer: { +// Viewer: unlayer.createViewer({ +// render(values) { +// console.log(values); +// return ` +//
{{#each ${values.field}}}
+// `; +// }, +// }), +// exporters: { +// web: function () {}, +// email: function () {}, +// }, +// }, +// }); - var greenButton = node.getElementsByClassName("green")[0]; - greenButton.onclick = function () { - updateValue("#0f0"); - }; - - var blueButton = node.getElementsByClassName("blue")[0]; - blueButton.onclick = function () { - updateValue("#00f"); - }; - }, - }), -}); - -unlayer.registerTool({ - type: "whatever", - category: "contents", - label: "My Tool", - icon: "fa-smile", - values: {}, - options: { - default: { - title: null, - }, - text: { - title: "Text", - position: 1, - options: { - color: { - label: "Color", - defaultValue: "#000", - widget: "my_color_picker", - }, - }, - }, - }, - renderer: { - Viewer: unlayer.createViewer({ - render(values) { - return ` -
I am a custom tool.
- `; - }, - }), - exporters: { - web: function () {}, - email: function () {}, - }, - }, -}); +// unlayer.registerTool({ +// type: "whatever", +// category: "contents", +// label: "End Repeat", +// icon: "fa-smile", +// values: {}, +// options: { +// default: { +// title: null, +// }, +// text: { +// title: "Field", +// position: 1, +// options: { +// field: { +// label: "Field", +// defaultValue: "", +// widget: "field_name", +// }, +// }, +// }, +// }, +// renderer: { +// Viewer: unlayer.createViewer({ +// render(values) { +// return ` +//
{{ /each }}
+// `; +// }, +// }), +// exporters: { +// web: function () {}, +// email: function () {}, +// }, +// }, +// }); unlayer.registerColumns([2, 2, 2, 2, 2, 2]); unlayer.registerColumns([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]); - -unlayer.registerTool({ - type: "whatever", - category: "contents", - label: "Begin Repeater", - icon: "fa-smile", - values: {}, - options: { - default: { - title: "BeginRepeater", - }, - text: { - title: "Text", - position: 1, - options: { - field: { - label: "Field", - defaultValue: "Field Name...", - widget: "my_color_picker", - }, - }, - }, - }, - renderer: { - Viewer: unlayer.createViewer({ - render(values) { - return ` -
{{${values.field}}}
- `; - }, - }), - exporters: { - web: function () {}, - email: function () {}, - }, - }, -}); diff --git a/client/public/render-styles.css b/client/public/render-styles.css new file mode 100644 index 000000000..a58cf2b3f --- /dev/null +++ b/client/public/render-styles.css @@ -0,0 +1,85 @@ +/* body { + font-family: "Open Sans", sans-serif; + line-height: 1.25; +} */ + +table { + border: 1px solid #ccc; + border-collapse: collapse; + margin: 0; + padding: 0; + width: 100%; + table-layout: fixed; +} + +table caption { + font-size: 1.5em; + margin: 0.5em 0 0.75em; +} + +table tr { + background-color: #f8f8f8; + border: 1px solid #ddd; + padding: 0.35em; +} + +table th, +table td { + padding: 0.625em; + text-align: center; +} + +table th { + font-size: 0.85em; + letter-spacing: 0.1em; + text-transform: uppercase; +} + +@media screen and (max-width: 600px) { + table { + border: 0; + } + + table caption { + font-size: 1.3em; + } + + table thead { + border: none; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; + } + + table tr { + border-bottom: 3px solid #ddd; + display: block; + margin-bottom: 0.625em; + } + + table td { + border-bottom: 1px solid #ddd; + display: block; + font-size: 0.8em; + text-align: right; + } + + table td::before { + /* + * aria-label has no advantage, it won't be read inside a table + content: attr(aria-label); + */ + content: attr(data-label); + float: left; + font-weight: bold; + text-transform: uppercase; + } + + table td:last-child { + border-bottom: 0; + } +} diff --git a/client/src/App/App.container.jsx b/client/src/App/App.container.jsx index 3d002b53e..e15528449 100644 --- a/client/src/App/App.container.jsx +++ b/client/src/App/App.container.jsx @@ -18,9 +18,25 @@ import App from "./App"; import { ConfigProvider } from "antd"; import enLocale from "antd/es/locale/en_US"; import moment from "moment"; +import axios from "axios"; moment.locale("en-US"); +axios.interceptors.request.use( + async (config) => { + if (!config.headers.Authorization) { + const token = + auth.currentUser && (await auth.currentUser.getIdToken(true)); + if (token) { + config.headers.Authorization = `Bearer ${token}`; + } + } + + return config; + }, + (error) => Promise.reject(error) +); + if (process.env.NODE_ENV === "production") LogRocket.init("gvfvfw/bodyshopapp"); const httpLink = new HttpLink({ diff --git a/client/src/components/shop-template-editor-save-button/shop-template-editor-save-button.component.jsx b/client/src/components/shop-template-editor-save-button/shop-template-editor-save-button.component.jsx index bcd239c3f..bf94201fc 100644 --- a/client/src/components/shop-template-editor-save-button/shop-template-editor-save-button.component.jsx +++ b/client/src/components/shop-template-editor-save-button/shop-template-editor-save-button.component.jsx @@ -18,9 +18,11 @@ export default function ShopTemplateSaveButton({ logImEXEvent("shop_template_update"); emailEditorRef.current.exportHtml(async (data) => { + console.log("RAW", data.html); inlineCss(data.html, { - url: `${window.location.protocol}://${window.location.host}`, + url: `${window.location.protocol}://${window.location.host}/`, }).then(async function (inlineHtml) { + console.log("Inline :>> ", inlineHtml); const result = await updateTemplate({ variables: { templateId: templateId, diff --git a/client/src/components/shop-template-editor/shop-template-editor.component.jsx b/client/src/components/shop-template-editor/shop-template-editor.component.jsx index e4e4c537a..367b1dbf9 100644 --- a/client/src/components/shop-template-editor/shop-template-editor.component.jsx +++ b/client/src/components/shop-template-editor/shop-template-editor.component.jsx @@ -14,8 +14,9 @@ export default function ShopTemplateEditorComponent({ const emailEditorRef = useRef(null); useEffect(() => { - if (json && Object.keys(json).length > 0) + if (json && Object.keys(json).length > 0 && emailEditorRef.current) { emailEditorRef.current.loadDesign(json); + } }, [json, emailEditorRef]); useEffect(() => { @@ -46,6 +47,12 @@ export default function ShopTemplateEditorComponent({ { res.sendStatus(200); }; + +exports.validateFirebaseIdToken = async (req, res, next) => { + console.log("Check if request is authorized with Firebase ID token"); + + if ( + (!req.headers.authorization || + !req.headers.authorization.startsWith("Bearer ")) && + !(req.cookies && req.cookies.__session) + ) { + console.error("Unauthorized attempt. No authorization provided."); + res.status(403).send("Unauthorized"); + return; + } + + let idToken; + if ( + req.headers.authorization && + req.headers.authorization.startsWith("Bearer ") + ) { + // console.log('Found "Authorization" header'); + // Read the ID Token from the Authorization header. + idToken = req.headers.authorization.split("Bearer ")[1]; + } else if (req.cookies) { + //console.log('Found "__session" cookie'); + // Read the ID Token from cookie. + idToken = req.cookies.__session; + } else { + // No cookie + console.error("Unauthorized attempt. No cookie provided."); + + res.status(403).send("Unauthorized"); + return; + } + + try { + const decodedIdToken = await admin.auth().verifyIdToken(idToken); + //console.log("ID Token correctly decoded", decodedIdToken); + req.user = decodedIdToken; + next(); + return; + } catch (error) { + console.error("Error while verifying Firebase ID token:", error); + res.status(403).send("Unauthorized"); + return; + } +};