From af8e39da751122b34c21dd43b0ac7cf9743fef91 Mon Sep 17 00:00:00 2001 From: Patrick Fic <> Date: Fri, 4 Sep 2020 15:03:01 -0700 Subject: [PATCH] Rearranged shop template page to better handle previews & template editor BOD-126 --- .../shop-template-editor.component.jsx | 19 +++-- .../shop-template-editor.container.jsx | 22 ++++-- .../shop-template-test-render.component.jsx | 6 +- .../shop-templates-list.container.jsx | 76 ++++++++++--------- client/src/graphql/schema.js | 1 - .../shop-templates.container.js | 20 ++--- server/job/job-totals.js | 40 +++++----- server/render/renderHandlebars.js | 33 ++++++++ 8 files changed, 129 insertions(+), 88 deletions(-) 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 55fbcfe3c..d6071859d 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 @@ -8,7 +8,7 @@ import "codemirror/lib/codemirror.css"; import "codemirror/theme/material.css"; import "codemirror/addon/hint/show-hint"; -import React, { useEffect, useRef } from "react"; +import React, { useEffect, useRef, useState } from "react"; import { Controlled as CmEditor } from "react-codemirror2"; import EmailEditor from "react-email-editor"; import GqlSchema from "../../graphql/schema"; @@ -32,18 +32,15 @@ export default function ShopTemplateEditorComponent({ editorState, }) { const [editorContent, seteditorContent] = editorState; + const [editorLoaded, setEditorLoaded] = useState(false); const emailEditorRef = useRef(null); useEffect(() => { - if ( - json && - Object.keys(json).length > 0 && - emailEditorRef && - emailEditorRef.current - ) { + if (json && Object.keys(json).length > 0 && editorLoaded) { + console.log(emailEditorRef.current, !!emailEditorRef.current.loadDesign); emailEditorRef.current.loadDesign(json); } - }, [json, emailEditorRef]); + }, [json, emailEditorRef, editorLoaded]); useEffect(() => { seteditorContent((prevstate) => { @@ -58,9 +55,11 @@ export default function ShopTemplateEditorComponent({ gql={editorContent.gql} emailEditorRef={emailEditorRef} /> - setEditorLoaded(true)} options={{ // customCSS: [ // window.location.protocol + @@ -78,6 +77,7 @@ export default function ShopTemplateEditorComponent({ />
- ) ; return ( - +
+ {loading ? ( + + ) : ( + + )} {data && data.templates_by_pk ? data.templates_by_pk.name : ""} - - +
); } diff --git a/client/src/components/shop-template-test-render/shop-template-test-render.component.jsx b/client/src/components/shop-template-test-render/shop-template-test-render.component.jsx index 5287c5977..f57d1b678 100644 --- a/client/src/components/shop-template-test-render/shop-template-test-render.component.jsx +++ b/client/src/components/shop-template-test-render/shop-template-test-render.component.jsx @@ -60,11 +60,11 @@ export function ShopTemplateTestRender({ bodyshop, query, emailEditorRef }) { return (
-
setVariables(e)} /> +
); diff --git a/client/src/components/shop-templates-list/shop-templates-list.container.jsx b/client/src/components/shop-templates-list/shop-templates-list.container.jsx index 5ac937140..c012c2296 100644 --- a/client/src/components/shop-templates-list/shop-templates-list.container.jsx +++ b/client/src/components/shop-templates-list/shop-templates-list.container.jsx @@ -1,5 +1,5 @@ import { useQuery } from "@apollo/react-hooks"; -import { List, Button } from "antd"; +import { List, Button, Drawer } from "antd"; import React from "react"; import { QUERY_CUSTOM_TEMPLATES } from "../../graphql/templates.queries"; import AlertComponent from "../alert/alert.component"; @@ -11,7 +11,8 @@ import { TemplateList } from "../../utils/TemplateConstants"; import ShopTemplateAdd from "../shop-template-add/shop-template-add.component"; import ShopTemplateDeleteComponent from "../shop-template-delete/shop-template-delete.component"; -export default function ShopTemplatesListContainer() { +export default function ShopTemplatesListContainer({ visibleState }) { + const [visible, setVisible] = visibleState; const { loading, error, data, refetch } = useQuery(QUERY_CUSTOM_TEMPLATES); const { t } = useTranslation(); const search = queryString.parse(useLocation().search); @@ -31,37 +32,44 @@ export default function ShopTemplatesListContainer() { }; return ( -
-
{t("bodyshop.labels.customtemplates")}
- - ( - handleEdit(item)}> - {t("general.actions.edit")} - , - , - ]} - > - -
-
{TemplateList[item.name].title}
-
{TemplateList[item.name].description}
-
-
-
- )} - /> -
+ setVisible(false)} + > +
+
{t("bodyshop.labels.customtemplates")}
+ + ( + handleEdit(item)}> + {t("general.actions.edit")} + , + , + ]} + > + +
+
{TemplateList[item.name].title}
+
{TemplateList[item.name].description}
+
+
+
+ )} + /> +
+
); } diff --git a/client/src/graphql/schema.js b/client/src/graphql/schema.js index a0a22895e..02ab07838 100644 --- a/client/src/graphql/schema.js +++ b/client/src/graphql/schema.js @@ -1,4 +1,3 @@ -import { gql } from "@apollo/client"; import { buildSchema } from "graphql"; export default buildSchema(` diff --git a/client/src/pages/shop-templates/shop-templates.container.js b/client/src/pages/shop-templates/shop-templates.container.js index 06809802c..8de467f11 100644 --- a/client/src/pages/shop-templates/shop-templates.container.js +++ b/client/src/pages/shop-templates/shop-templates.container.js @@ -1,5 +1,5 @@ -import { Col, Row } from "antd"; -import React, { useEffect } from "react"; +import { Button } from "antd"; +import React, { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; @@ -18,6 +18,7 @@ const mapDispatchToProps = (dispatch) => ({ export function ShopTemplatesContainer({ setBreadcrumbs, bodyshop }) { const { t } = useTranslation(); + const drawerVisibility = useState(false); useEffect(() => { document.title = t("titles.shop-templates"); setBreadcrumbs([ @@ -31,16 +32,11 @@ export function ShopTemplatesContainer({ setBreadcrumbs, bodyshop }) { return ( - - - - - -
- -
- -
+
+ + + +
); } diff --git a/server/job/job-totals.js b/server/job/job-totals.js index c9744a634..5a4cea537 100644 --- a/server/job/job-totals.js +++ b/server/job/job-totals.js @@ -86,86 +86,86 @@ function CalculateRatesTotals(ratesList, shoprates) { la1: { hours: jobLines .filter((item) => item.mod_lbr_ty === "LA1") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), + .reduce((acc, value) => acc + value.mod_lb_hrs, 0), rate: ratesList.rate_la1 || 0, }, la2: { hours: jobLines .filter((item) => item.mod_lbr_ty === "LA2") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), + .reduce((acc, value) => acc + value.mod_lb_hrs, 0), rate: ratesList.rate_la2 || 0, }, la3: { rate: ratesList.rate_la3 || 0, hours: jobLines .filter((item) => item.mod_lbr_ty === "LA3") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), + .reduce((acc, value) => acc + value.mod_lb_hrs, 0), }, la4: { rate: ratesList.rate_la4 || 0, hours: jobLines .filter((item) => item.mod_lbr_ty === "LA4") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), + .reduce((acc, value) => acc + value.mod_lb_hrs, 0), }, laa: { rate: ratesList.rate_laa || 0, hours: jobLines .filter((item) => item.mod_lbr_ty === "LAA") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), + .reduce((acc, value) => acc + value.mod_lb_hrs, 0), }, lab: { rate: ratesList.rate_lab || 0, hours: jobLines .filter((item) => item.mod_lbr_ty === "LAB") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), + .reduce((acc, value) => acc + value.mod_lb_hrs, 0), }, lad: { rate: ratesList.rate_lad || 0, hours: jobLines .filter((item) => item.mod_lbr_ty === "LAD") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), + .reduce((acc, value) => acc + value.mod_lb_hrs, 0), }, lae: { rate: ratesList.rate_lae || 0, hours: jobLines .filter((item) => item.mod_lbr_ty === "LAE") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), + .reduce((acc, value) => acc + value.mod_lb_hrs, 0), }, laf: { rate: ratesList.rate_laf || 0, hours: jobLines .filter((item) => item.mod_lbr_ty === "LAF") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), + .reduce((acc, value) => acc + value.mod_lb_hrs, 0), }, lag: { rate: ratesList.rate_lag || 0, hours: jobLines .filter((item) => item.mod_lbr_ty === "LAG") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), + .reduce((acc, value) => acc + value.mod_lb_hrs, 0), }, lam: { rate: ratesList.rate_lam || 0, hours: jobLines .filter((item) => item.mod_lbr_ty === "LAM") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), + .reduce((acc, value) => acc + value.mod_lb_hrs, 0), }, lar: { rate: ratesList.rate_lar || 0, hours: jobLines .filter((item) => item.mod_lbr_ty === "LAR") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), + .reduce((acc, value) => acc + value.mod_lb_hrs, 0), }, las: { rate: ratesList.rate_las || 0, hours: jobLines .filter((item) => item.mod_lbr_ty === "LAS") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), + .reduce((acc, value) => acc + value.mod_lb_hrs, 0), }, lau: { rate: ratesList.rate_lau || 0, hours: jobLines .filter((item) => item.mod_lbr_ty === "LAU") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), + .reduce((acc, value) => acc + value.mod_lb_hrs, 0), }, atp: { rate: shoprates.rate_atp || 0, @@ -184,29 +184,29 @@ function CalculateRatesTotals(ratesList, shoprates) { item.mod_lbr_ty !== "LAS" && item.mod_lbr_ty !== "LAA" ) - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0) + .reduce((acc, value) => acc + value.mod_lb_hrs, 0) : 0, }, mapa: { rate: ratesList.rate_mapa || 0, hours: jobLines .filter((item) => item.mod_lbr_ty === "LAR") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), + .reduce((acc, value) => acc + value.mod_lb_hrs, 0), }, mash: { rate: ratesList.rate_mash || 0, hours: jobLines .filter((item) => item.mod_lbr_ty !== "LAR") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), + .reduce((acc, value) => acc + value.mod_lb_hrs, 0), }, }; let subtotal = Dinero({ amount: 0 }); let rates_subtotal = Dinero({ amount: 0 }); for (const property in ret) { - ret[property].total = Dinero({ amount: ret[property].rate * 100 }) - .multiply(ret[property].hours) - .divide(10); + ret[property].total = Dinero({ amount: ret[property].rate * 100 }).multiply( + ret[property].hours + ); subtotal = subtotal.add(ret[property].total); if ( property !== "mapa" && diff --git a/server/render/renderHandlebars.js b/server/render/renderHandlebars.js index 6347ca915..7ae644b6e 100644 --- a/server/render/renderHandlebars.js +++ b/server/render/renderHandlebars.js @@ -8,9 +8,42 @@ require("dotenv").config({ }); var _ = require("lodash"); const Handlebars = require("handlebars"); +var Dinero = require("dinero.js"); +Dinero.defaultCurrency = "CAD"; +Dinero.globalLocale = "en-CA"; //Usage: {{moment appointments_by_pk.start format="dddd, DD MMMM YYYY"}} +Handlebars.registerHelper("dinerof", function (context, block) { + if (context && context.hash) { + block = _.cloneDeep(context); + context = undefined; + } + var amount = Dinero(context); + if (context) { + return amount.toFormat(); + } + return ""; +}); + +Handlebars.registerHelper("objectKeys", function (obj, block) { + var accum = ""; + + Object.keys(obj).map((key) => { + accum += block.fn({ key, value: obj[key] }); + }); + return accum; +}); + +Handlebars.registerHelper("dinero", function (context, block) { + if (context && context.hash) { + block = _.cloneDeep(context); + context = undefined; + } + var amount = Dinero({ amount: Math.round((context || 0) * 100) }); + return amount.toFormat(); +}); + Handlebars.registerHelper("moment", function (context, block) { if (context && context.hash) { block = _.cloneDeep(context);