diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index 83ba120e0..16f1c57c2 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -15213,6 +15213,27 @@ labels + + additionaltotal + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + allocations false diff --git a/client/public/kavia.png b/client/public/kavia.png new file mode 100644 index 000000000..be947430a Binary files /dev/null and b/client/public/kavia.png differ diff --git a/client/public/render-styles.css b/client/public/render-styles.css index a58cf2b3f..8e7aef8ec 100644 --- a/client/public/render-styles.css +++ b/client/public/render-styles.css @@ -1,9 +1,37 @@ -/* body { +body { font-family: "Open Sans", sans-serif; line-height: 1.25; + /* padding: 10mm 10mm 10mm 10mm !important; */ +} +@page { + size: auto; /* auto is the initial value */ + + /* this affects the margin in the printer settings */ + margin: 25mm 25mm 25mm 25mm; + color: tomato; +} + +/* Unknown whether the below actually gets embedded */ +/* @media print { + @page { + size: Letter; + margin: 0; + } + html, + body { + width: 210mm; + + height: 282mm; + font-size: 11px; + background: #fff; + overflow: visible; + } + body { + padding-top: 15mm; + } } */ -table { +table.imex-table { border: 1px solid #ccc; border-collapse: collapse; margin: 0; @@ -12,74 +40,25 @@ table { table-layout: fixed; } -table caption { +table.imex-table caption { font-size: 1.5em; margin: 0.5em 0 0.75em; } -table tr { +table.imex-table tr { background-color: #f8f8f8; border: 1px solid #ddd; - padding: 0.35em; + padding: 0.1rem; } -table th, -table td { - padding: 0.625em; +table.imex-table th, +table.imex-table td { + padding: 0.3rem; text-align: center; } -table th { +table.imex-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/components/job-totals-table/job-totals-table.component.jsx b/client/src/components/job-totals-table/job-totals-table.component.jsx index da092fc06..988664769 100644 --- a/client/src/components/job-totals-table/job-totals-table.component.jsx +++ b/client/src/components/job-totals-table/job-totals-table.component.jsx @@ -1,5 +1,7 @@ import { Col, Result, Row, Statistic, Typography } from "antd"; import Dinero from "dinero.js"; +import { JsonEditor as Editor } from "jsoneditor-react"; +import "jsoneditor-react/es/editor.min.css"; import React from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; @@ -218,7 +220,7 @@ export function JobsTotalsTableComponent({ bodyshop, job }) { {t("jobs.labels.additionaltotal")} - {Dinero(job.job_totals.parts.additional).toFormat()} + {Dinero(job.job_totals.additional).toFormat()} @@ -293,6 +295,9 @@ export function JobsTotalsTableComponent({ bodyshop, job }) { /> + 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 10fd77f4f..51bab241b 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 @@ -20,6 +20,7 @@ export default function ShopTemplateSaveButton({ emailEditorRef.current.exportHtml(async (data) => { inlineCss(data.html, { url: `${window.location.protocol}://${window.location.host}/`, + preserveMediaQueries: true, }).then(async function (inlineHtml) { const result = await updateTemplate({ variables: { 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 d6071859d..f46845fbd 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 @@ -1,28 +1,16 @@ -import "codemirror/addon/hint/show-hint"; -import "codemirror/addon/lint/lint"; import "codemirror-graphql/hint"; import "codemirror-graphql/lint"; import "codemirror-graphql/mode"; - +import "codemirror/addon/hint/show-hint"; +import "codemirror/addon/lint/lint"; import "codemirror/lib/codemirror.css"; import "codemirror/theme/material.css"; -import "codemirror/addon/hint/show-hint"; - 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"; import ShopTemplateEditorSaveButton from "../shop-template-editor-save-button/shop-template-editor-save-button.component"; import ShopTemplateTestRender from "../shop-template-test-render/shop-template-test-render.component"; -// CodeMirror.fromTextArea(document.getElementById("gqlcm"), { -// mode: "graphql", -// lint: { -// // schema: myGraphQLSchema, -// }, -// hintOptions: { -// // schema: myGraphQLSchema, -// }, -// }); export default function ShopTemplateEditorComponent({ templateId, @@ -58,7 +46,7 @@ export default function ShopTemplateEditorComponent({ setEditorLoaded(true)} options={{ // customCSS: [ @@ -75,9 +63,9 @@ export default function ShopTemplateEditorComponent({ ], }} /> -
+
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 f57d1b678..69f86eead 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 @@ -19,7 +19,12 @@ const mapDispatchToProps = (dispatch) => ({ //setUserLanguage: language => dispatch(setUserLanguage(language)) }); -export function ShopTemplateTestRender({ bodyshop, query, emailEditorRef }) { +export function ShopTemplateTestRender({ + bodyshop, + query, + emailEditorRef, + style, +}) { const [variables, setVariables] = useState({ id: "uuid" }); const [loading, setLoading] = useState(false); const { t } = useTranslation(); @@ -31,6 +36,7 @@ export function ShopTemplateTestRender({ bodyshop, query, emailEditorRef }) { emailEditorRef.current.exportHtml(async (data) => { inlineCss(data.html, { url: `${window.location.protocol}://${window.location.host}/`, + removeLinkTags: false, }).then(async function (inlineHtml) { try { const { data: contextData } = await client.query({ @@ -59,13 +65,11 @@ export function ShopTemplateTestRender({ bodyshop, query, emailEditorRef }) { }; return ( -
-
- setVariables(e)} /> - -
+
+ 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 c012c2296..d435fed47 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 @@ -64,6 +64,7 @@ export default function ShopTemplatesListContainer({ visibleState }) {
{TemplateList[item.name].title}
{TemplateList[item.name].description}
+
{TemplateList[item.name].drivingid}
diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index 5594e7528..0569d44f4 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -942,6 +942,7 @@ "scheddates": "Schedule Dates" }, "labels": { + "additionaltotal": "Additional Total", "allocations": "Allocations", "appointmentconfirmation": "Send confirmation to customer?", "audit": "Audit Trail", diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 952af7924..23e282751 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -942,6 +942,7 @@ "scheddates": "" }, "labels": { + "additionaltotal": "", "allocations": "", "appointmentconfirmation": "¿Enviar confirmación al cliente?", "audit": "", diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index 58f62d391..4142611d4 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -942,6 +942,7 @@ "scheddates": "" }, "labels": { + "additionaltotal": "", "allocations": "", "appointmentconfirmation": "Envoyer une confirmation au client?", "audit": "", diff --git a/client/src/utils/TemplateConstants.js b/client/src/utils/TemplateConstants.js index 023ef4ba9..a902ce478 100644 --- a/client/src/utils/TemplateConstants.js +++ b/client/src/utils/TemplateConstants.js @@ -4,6 +4,14 @@ export const EmailSettings = { }; export const TemplateList = { + //Verified Completed items + estimate_detail: { + title: "Estimate Detail", + description: "Est Detail", + drivingId: "job", + key: "estimate_detail", + }, + //Non Completed Items appointment_reminder: { title: "Appointment Reminder", description: "Sent to a customer as a reminder of an upcoming appointment.", @@ -23,12 +31,7 @@ export const TemplateList = { drivingId: "partsorder", key: "parts_order_confirmation", }, - estimate_detail: { - title: "Estimate Detail Lines", - description: "Est Detail", - drivingId: "job", - key: "estimate_detail", - }, + cover_sheet_landscape: { title: "Cover Sheet - Landscape", description: "Cover sheet landscape", diff --git a/client/templates/helpers.md b/client/templates/helpers.md new file mode 100644 index 000000000..e69de29bb diff --git a/server/job/job-totals.js b/server/job/job-totals.js index e8d790f2a..be08fafd7 100644 --- a/server/job/job-totals.js +++ b/server/job/job-totals.js @@ -41,7 +41,6 @@ function CalculateAdditional(job) { jl.lbr_op === "OP15" ) .reduce((acc, val) => { - console.log("val", val); return acc.add( Dinero({ amount: Math.round((val.act_price || 0) * 100) }) ); diff --git a/server/render/renderHandlebars.js b/server/render/renderHandlebars.js index 79dce7572..65d0b8f8b 100644 --- a/server/render/renderHandlebars.js +++ b/server/render/renderHandlebars.js @@ -8,12 +8,25 @@ require("dotenv").config({ }); var _ = require("lodash"); const Handlebars = require("handlebars"); +const phone = require("phone"); 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("round", function (context, block) { + if (context && context.hash) { + block = _.cloneDeep(context); + context = undefined; + } + try { + return context.toFixed(2); + } catch { + return context; + } +}); + Handlebars.registerHelper("dinerof", function (context, block) { if (context && context.hash) { block = _.cloneDeep(context); @@ -26,6 +39,77 @@ Handlebars.registerHelper("dinerof", function (context, block) { return ""; }); +Handlebars.registerHelper("phonef", function (context, block) { + if (context && context.hash) { + block = _.cloneDeep(context); + context = undefined; + } + var ph = phone(context)[0]; + if (context) { + return ph; + } + return ""; +}); + +Handlebars.registerHelper("partType", function (context, block) { + if (!context) return ""; + + switch (context.toUpperCase()) { + case "PAA": + return "Aftermarket"; + case "PAE": + return "Existing"; + case "PAN": + return "OEM"; + case "PAO": + return "Other"; + case "PAS": + return "Sublet"; + case "PASL": + return "Sublet"; + case "PAL": + return "LKQ"; + case "PAM": + return "Remanufactured"; + case "PAC": + return "Chrome"; + case "PAP": + return "OEM Partial"; + case "PAR": + return "Record"; + default: + return context; + } +}); + +Handlebars.registerHelper("lbrType", function (context, block) { + if (!context) return ""; + + switch (context.toUpperCase()) { + case "LAA": + return "Aluminum"; + case "LAB": + return "Body"; + case "LAD": + return "Diagnostic"; + case "LAF": + return "Frame"; + case "LAG": + return "Glass"; + case "LAM": + return "Mechanical"; + case "LAR": + return "Refinish"; + case "LAS": + return "Structural"; + case "LAU": + return "Detail"; + + default: + return context; + } +}); + Handlebars.registerHelper("objectKeys", function (obj, block) { var accum = ""; @@ -41,7 +125,10 @@ Handlebars.registerHelper("dinero", function (context, block) { block = _.cloneDeep(context); context = undefined; } - var amount = Dinero({ amount: Math.round((context || 0) * 100) }); + var amount = Dinero({ + amount: Math.round((context || 0) * 100), + currency: "CAD", + }); return amount.toFormat(); }); @@ -50,6 +137,9 @@ Handlebars.registerHelper("moment", function (context, block) { block = _.cloneDeep(context); context = undefined; } + + if (!!!context) return ""; + var date = moment(context); if (block.hash.timezone) {