Modified render styles to improve printability

This commit is contained in:
Patrick Fic
2020-09-10 15:55:25 -07:00
parent a0bb07abfd
commit 984c001bd8
15 changed files with 187 additions and 92 deletions

View File

@@ -15213,6 +15213,27 @@
<folder_node> <folder_node>
<name>labels</name> <name>labels</name>
<children> <children>
<concept_node>
<name>additionaltotal</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>allocations</name> <name>allocations</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>

BIN
client/public/kavia.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -1,9 +1,37 @@
/* body { body {
font-family: "Open Sans", sans-serif; font-family: "Open Sans", sans-serif;
line-height: 1.25; 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: 1px solid #ccc;
border-collapse: collapse; border-collapse: collapse;
margin: 0; margin: 0;
@@ -12,74 +40,25 @@ table {
table-layout: fixed; table-layout: fixed;
} }
table caption { table.imex-table caption {
font-size: 1.5em; font-size: 1.5em;
margin: 0.5em 0 0.75em; margin: 0.5em 0 0.75em;
} }
table tr { table.imex-table tr {
background-color: #f8f8f8; background-color: #f8f8f8;
border: 1px solid #ddd; border: 1px solid #ddd;
padding: 0.35em; padding: 0.1rem;
} }
table th, table.imex-table th,
table td { table.imex-table td {
padding: 0.625em; padding: 0.3rem;
text-align: center; text-align: center;
} }
table th { table.imex-table th {
font-size: 0.85em; font-size: 0.85em;
letter-spacing: 0.1em; letter-spacing: 0.1em;
text-transform: uppercase; 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;
}
}

View File

@@ -1,5 +1,7 @@
import { Col, Result, Row, Statistic, Typography } from "antd"; import { Col, Result, Row, Statistic, Typography } from "antd";
import Dinero from "dinero.js"; import Dinero from "dinero.js";
import { JsonEditor as Editor } from "jsoneditor-react";
import "jsoneditor-react/es/editor.min.css";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
@@ -218,7 +220,7 @@ export function JobsTotalsTableComponent({ bodyshop, job }) {
<tr> <tr>
<td>{t("jobs.labels.additionaltotal")}</td> <td>{t("jobs.labels.additionaltotal")}</td>
<td className="currency"> <td className="currency">
{Dinero(job.job_totals.parts.additional).toFormat()} {Dinero(job.job_totals.additional).toFormat()}
</td> </td>
<td></td> <td></td>
</tr> </tr>
@@ -293,6 +295,9 @@ export function JobsTotalsTableComponent({ bodyshop, job }) {
/> />
</div> </div>
<JobCalculateTotals job={job} /> <JobCalculateTotals job={job} />
<Editor
value={{ CIECA: job.cieca_ttl.data, ImEXCalc: job.job_totals }}
/>
</div> </div>
</Col> </Col>
</Row> </Row>

View File

@@ -20,6 +20,7 @@ export default function ShopTemplateSaveButton({
emailEditorRef.current.exportHtml(async (data) => { emailEditorRef.current.exportHtml(async (data) => {
inlineCss(data.html, { inlineCss(data.html, {
url: `${window.location.protocol}://${window.location.host}/`, url: `${window.location.protocol}://${window.location.host}/`,
preserveMediaQueries: true,
}).then(async function (inlineHtml) { }).then(async function (inlineHtml) {
const result = await updateTemplate({ const result = await updateTemplate({
variables: { variables: {

View File

@@ -1,28 +1,16 @@
import "codemirror/addon/hint/show-hint";
import "codemirror/addon/lint/lint";
import "codemirror-graphql/hint"; import "codemirror-graphql/hint";
import "codemirror-graphql/lint"; import "codemirror-graphql/lint";
import "codemirror-graphql/mode"; import "codemirror-graphql/mode";
import "codemirror/addon/hint/show-hint";
import "codemirror/addon/lint/lint";
import "codemirror/lib/codemirror.css"; import "codemirror/lib/codemirror.css";
import "codemirror/theme/material.css"; import "codemirror/theme/material.css";
import "codemirror/addon/hint/show-hint";
import React, { useEffect, useRef, useState } from "react"; import React, { useEffect, useRef, useState } from "react";
import { Controlled as CmEditor } from "react-codemirror2"; import { Controlled as CmEditor } from "react-codemirror2";
import EmailEditor from "react-email-editor"; import EmailEditor from "react-email-editor";
import GqlSchema from "../../graphql/schema"; import GqlSchema from "../../graphql/schema";
import ShopTemplateEditorSaveButton from "../shop-template-editor-save-button/shop-template-editor-save-button.component"; 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"; 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({ export default function ShopTemplateEditorComponent({
templateId, templateId,
@@ -58,7 +46,7 @@ export default function ShopTemplateEditorComponent({
<EmailEditor <EmailEditor
style={{ width: "100%" }} style={{ width: "100%" }}
ref={emailEditorRef} ref={emailEditorRef}
minHeight="800px" minHeight="700px"
onLoad={() => setEditorLoaded(true)} onLoad={() => setEditorLoaded(true)}
options={{ options={{
// customCSS: [ // customCSS: [
@@ -75,9 +63,9 @@ export default function ShopTemplateEditorComponent({
], ],
}} }}
/> />
<div style={{ display: "flex" }}> <div style={{ display: "flex", width: "90vw" }}>
<CmEditor <CmEditor
style={{ width: "30rem" }} style={{ flex: 1 }}
value={editorContent.gql} value={editorContent.gql}
options={{ options={{
mode: "graphql", mode: "graphql",
@@ -94,6 +82,7 @@ export default function ShopTemplateEditorComponent({
}} }}
/> />
<ShopTemplateTestRender <ShopTemplateTestRender
style={{ flex: 1 }}
query={editorContent.gql} query={editorContent.gql}
emailEditorRef={emailEditorRef} emailEditorRef={emailEditorRef}
/> />

View File

@@ -19,7 +19,12 @@ const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language)) //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 [variables, setVariables] = useState({ id: "uuid" });
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const { t } = useTranslation(); const { t } = useTranslation();
@@ -31,6 +36,7 @@ export function ShopTemplateTestRender({ bodyshop, query, emailEditorRef }) {
emailEditorRef.current.exportHtml(async (data) => { emailEditorRef.current.exportHtml(async (data) => {
inlineCss(data.html, { inlineCss(data.html, {
url: `${window.location.protocol}://${window.location.host}/`, url: `${window.location.protocol}://${window.location.host}/`,
removeLinkTags: false,
}).then(async function (inlineHtml) { }).then(async function (inlineHtml) {
try { try {
const { data: contextData } = await client.query({ const { data: contextData } = await client.query({
@@ -59,13 +65,11 @@ export function ShopTemplateTestRender({ bodyshop, query, emailEditorRef }) {
}; };
return ( return (
<div> <div style={style}>
<div style={{ width: "20rem" }}> <Editor value={variables} onChange={(e) => setVariables(e)} />
<Editor value={variables} onChange={(e) => setVariables(e)} /> <Button loading={loading} type="ghost" onClick={handleTestRender}>
<Button loading={loading} type="ghost" onClick={handleTestRender}> {t("bodyshop.actions.testrender")}
{t("bodyshop.actions.testrender")} </Button>
</Button>
</div>
</div> </div>
); );
} }

View File

@@ -64,6 +64,7 @@ export default function ShopTemplatesListContainer({ visibleState }) {
<div style={{ display: "flex", flexDirection: "column" }}> <div style={{ display: "flex", flexDirection: "column" }}>
<div>{TemplateList[item.name].title}</div> <div>{TemplateList[item.name].title}</div>
<div>{TemplateList[item.name].description}</div> <div>{TemplateList[item.name].description}</div>
<div>{TemplateList[item.name].drivingid}</div>
</div> </div>
</Skeleton> </Skeleton>
</List.Item> </List.Item>

View File

@@ -942,6 +942,7 @@
"scheddates": "Schedule Dates" "scheddates": "Schedule Dates"
}, },
"labels": { "labels": {
"additionaltotal": "Additional Total",
"allocations": "Allocations", "allocations": "Allocations",
"appointmentconfirmation": "Send confirmation to customer?", "appointmentconfirmation": "Send confirmation to customer?",
"audit": "Audit Trail", "audit": "Audit Trail",

View File

@@ -942,6 +942,7 @@
"scheddates": "" "scheddates": ""
}, },
"labels": { "labels": {
"additionaltotal": "",
"allocations": "", "allocations": "",
"appointmentconfirmation": "¿Enviar confirmación al cliente?", "appointmentconfirmation": "¿Enviar confirmación al cliente?",
"audit": "", "audit": "",

View File

@@ -942,6 +942,7 @@
"scheddates": "" "scheddates": ""
}, },
"labels": { "labels": {
"additionaltotal": "",
"allocations": "", "allocations": "",
"appointmentconfirmation": "Envoyer une confirmation au client?", "appointmentconfirmation": "Envoyer une confirmation au client?",
"audit": "", "audit": "",

View File

@@ -4,6 +4,14 @@ export const EmailSettings = {
}; };
export const TemplateList = { export const TemplateList = {
//Verified Completed items
estimate_detail: {
title: "Estimate Detail",
description: "Est Detail",
drivingId: "job",
key: "estimate_detail",
},
//Non Completed Items
appointment_reminder: { appointment_reminder: {
title: "Appointment Reminder", title: "Appointment Reminder",
description: "Sent to a customer as a reminder of an upcoming appointment.", description: "Sent to a customer as a reminder of an upcoming appointment.",
@@ -23,12 +31,7 @@ export const TemplateList = {
drivingId: "partsorder", drivingId: "partsorder",
key: "parts_order_confirmation", key: "parts_order_confirmation",
}, },
estimate_detail: {
title: "Estimate Detail Lines",
description: "Est Detail",
drivingId: "job",
key: "estimate_detail",
},
cover_sheet_landscape: { cover_sheet_landscape: {
title: "Cover Sheet - Landscape", title: "Cover Sheet - Landscape",
description: "Cover sheet landscape", description: "Cover sheet landscape",

View File

View File

@@ -41,7 +41,6 @@ function CalculateAdditional(job) {
jl.lbr_op === "OP15" jl.lbr_op === "OP15"
) )
.reduce((acc, val) => { .reduce((acc, val) => {
console.log("val", val);
return acc.add( return acc.add(
Dinero({ amount: Math.round((val.act_price || 0) * 100) }) Dinero({ amount: Math.round((val.act_price || 0) * 100) })
); );

View File

@@ -8,12 +8,25 @@ require("dotenv").config({
}); });
var _ = require("lodash"); var _ = require("lodash");
const Handlebars = require("handlebars"); const Handlebars = require("handlebars");
const phone = require("phone");
var Dinero = require("dinero.js"); var Dinero = require("dinero.js");
Dinero.defaultCurrency = "CAD"; Dinero.defaultCurrency = "CAD";
Dinero.globalLocale = "en-CA"; Dinero.globalLocale = "en-CA";
//Usage: {{moment appointments_by_pk.start format="dddd, DD MMMM YYYY"}} //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) { Handlebars.registerHelper("dinerof", function (context, block) {
if (context && context.hash) { if (context && context.hash) {
block = _.cloneDeep(context); block = _.cloneDeep(context);
@@ -26,6 +39,77 @@ Handlebars.registerHelper("dinerof", function (context, block) {
return ""; 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) { Handlebars.registerHelper("objectKeys", function (obj, block) {
var accum = ""; var accum = "";
@@ -41,7 +125,10 @@ Handlebars.registerHelper("dinero", function (context, block) {
block = _.cloneDeep(context); block = _.cloneDeep(context);
context = undefined; 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(); return amount.toFormat();
}); });
@@ -50,6 +137,9 @@ Handlebars.registerHelper("moment", function (context, block) {
block = _.cloneDeep(context); block = _.cloneDeep(context);
context = undefined; context = undefined;
} }
if (!!!context) return "";
var date = moment(context); var date = moment(context);
if (block.hash.timezone) { if (block.hash.timezone) {