Resolved bulk printing & status for printing items. IO-690
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import { MailOutlined, PrinterOutlined } from "@ant-design/icons";
|
import { MailOutlined, PrinterOutlined } from "@ant-design/icons";
|
||||||
import React from "react";
|
import { Spin } from "antd";
|
||||||
|
import React, { useState } from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { setEmailOptions } from "../../redux/email/email.actions";
|
import { setEmailOptions } from "../../redux/email/email.actions";
|
||||||
@@ -22,8 +23,10 @@ export function PrintCenterItemComponent({
|
|||||||
bodyshop,
|
bodyshop,
|
||||||
disabled,
|
disabled,
|
||||||
}) {
|
}) {
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
const { context } = printCenterModal;
|
const { context } = printCenterModal;
|
||||||
const renderToNewWindow = async () => {
|
const renderToNewWindow = async () => {
|
||||||
|
setLoading(true);
|
||||||
await GenerateDocument(
|
await GenerateDocument(
|
||||||
{
|
{
|
||||||
name: item.key,
|
name: item.key,
|
||||||
@@ -32,6 +35,7 @@ export function PrintCenterItemComponent({
|
|||||||
{},
|
{},
|
||||||
"p"
|
"p"
|
||||||
);
|
);
|
||||||
|
setLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (disabled) return <li className="print-center-item">{item.title} </li>;
|
if (disabled) return <li className="print-center-item">{item.title} </li>;
|
||||||
@@ -51,6 +55,7 @@ export function PrintCenterItemComponent({
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
{loading && <Spin size="small" />}
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { Button, List, Typography } from "antd";
|
import { Button, List, Typography } from "antd";
|
||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import { GenerateDocument } from "../../utils/RenderTemplate";
|
import { GenerateDocuments } from "../../utils/RenderTemplate";
|
||||||
import { TemplateList } from "../../utils/TemplateConstants";
|
import { TemplateList } from "../../utils/TemplateConstants";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
@@ -16,26 +16,19 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export function PrintCenterSpeedPrint({ bodyshop, jobId }) {
|
export function PrintCenterSpeedPrint({ bodyshop, jobId }) {
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
const { speedprint } = bodyshop;
|
const { speedprint } = bodyshop;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const renderTemplate = async (templateKey) => {
|
const renderAllTemplates = async (templateKeys) => {
|
||||||
logImEXEvent("speed_print_template_render");
|
|
||||||
|
|
||||||
GenerateDocument(
|
|
||||||
{
|
|
||||||
name: templateKey,
|
|
||||||
variables: { id: jobId },
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
"p"
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderAllTemplates = (templateKeys) => {
|
|
||||||
logImEXEvent("speed_print_render_all_templates");
|
logImEXEvent("speed_print_render_all_templates");
|
||||||
|
setLoading(true);
|
||||||
templateKeys.forEach((templateKey) => renderTemplate(templateKey));
|
await GenerateDocuments(
|
||||||
|
templateKeys.map((key) => {
|
||||||
|
return { name: key, variables: { id: jobId } };
|
||||||
|
})
|
||||||
|
);
|
||||||
|
setLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -50,7 +43,10 @@ export function PrintCenterSpeedPrint({ bodyshop, jobId }) {
|
|||||||
renderItem={(sp) => (
|
renderItem={(sp) => (
|
||||||
<List.Item
|
<List.Item
|
||||||
actions={[
|
actions={[
|
||||||
<Button onClick={() => renderAllTemplates(sp.templates)}>
|
<Button
|
||||||
|
loading={loading}
|
||||||
|
onClick={() => renderAllTemplates(sp.templates)}
|
||||||
|
>
|
||||||
Print All
|
Print All
|
||||||
</Button>,
|
</Button>,
|
||||||
]}
|
]}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export function ShopTemplateTestRender({
|
|||||||
view: inlineHtml.data,
|
view: inlineHtml.data,
|
||||||
context: { ...contextData, bodyshop: bodyshop },
|
context: { ...contextData, bodyshop: bodyshop },
|
||||||
});
|
});
|
||||||
displayTemplateInWindowNoprint(renderResponse.data);
|
// displayTemplateInWindowNoprint(renderResponse.data);
|
||||||
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
import React from "react";
|
import { Button, List, Space, Statistic, Typography } from "antd";
|
||||||
import { Statistic, Space, List, Button, Typography } from "antd";
|
|
||||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import RenderTemplate, {
|
import React from "react";
|
||||||
displayTemplateInWindow,
|
import { useTranslation } from "react-i18next";
|
||||||
} from "../../utils/RenderTemplate";
|
|
||||||
import { TemplateList } from "../../utils/TemplateConstants";
|
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import { onlyUnique } from "../../utils/arrayHelper";
|
import { onlyUnique } from "../../utils/arrayHelper";
|
||||||
|
import { GenerateDocument } from "../../utils/RenderTemplate";
|
||||||
|
import { TemplateList } from "../../utils/TemplateConstants";
|
||||||
|
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -68,15 +66,14 @@ export function TimeTicketsSummaryEmployees({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const handlePrintEmployeeTicket = async (empId) => {
|
const handlePrintEmployeeTicket = async (empId) => {
|
||||||
alert("Missing Key!");
|
GenerateDocument(
|
||||||
const html = await RenderTemplate(
|
|
||||||
{
|
{
|
||||||
name: TemplateList().time_tickets_by_employee.key,
|
name: TemplateList().time_tickets_by_employee.key,
|
||||||
variables: { id: empId, start: startDate, end: endDate },
|
variables: { id: empId, start: startDate, end: endDate },
|
||||||
},
|
},
|
||||||
bodyshop
|
{},
|
||||||
|
"p"
|
||||||
);
|
);
|
||||||
displayTemplateInWindow(html);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { notification } from "antd";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import gql from "graphql-tag";
|
import gql from "graphql-tag";
|
||||||
import jsreport from "jsreport-browser-client-dist";
|
import jsreport from "jsreport-browser-client-dist";
|
||||||
@@ -5,16 +6,149 @@ import { auth } from "../firebase/firebase.utils";
|
|||||||
import { setEmailOptions } from "../redux/email/email.actions";
|
import { setEmailOptions } from "../redux/email/email.actions";
|
||||||
import { store } from "../redux/store";
|
import { store } from "../redux/store";
|
||||||
import client from "../utils/GraphQLClient";
|
import client from "../utils/GraphQLClient";
|
||||||
|
import { TemplateList } from "./TemplateConstants";
|
||||||
|
|
||||||
const server = process.env.REACT_APP_REPORTS_SERVER_URL;
|
const server = process.env.REACT_APP_REPORTS_SERVER_URL;
|
||||||
jsreport.serverUrl = server;
|
jsreport.serverUrl = server;
|
||||||
|
|
||||||
|
const Templates = TemplateList();
|
||||||
|
|
||||||
export default async function RenderTemplate(
|
export default async function RenderTemplate(
|
||||||
templateObject,
|
templateObject,
|
||||||
bodyshop,
|
bodyshop,
|
||||||
renderAsHtml = false
|
renderAsHtml = false
|
||||||
) {
|
) {
|
||||||
//Query assets that match the template name. Must be in format <<templateName>>.query
|
//Query assets that match the template name. Must be in format <<templateName>>.query
|
||||||
|
let { contextData, useShopSpecificTemplate } = await fetchContextData(
|
||||||
|
templateObject
|
||||||
|
);
|
||||||
|
|
||||||
|
let reportRequest = {
|
||||||
|
template: {
|
||||||
|
name: useShopSpecificTemplate
|
||||||
|
? `/${bodyshop.imexshopid}/${templateObject.name}`
|
||||||
|
: `/${templateObject.name}`,
|
||||||
|
...(renderAsHtml ? {} : { recipe: "chrome-pdf" }),
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
...contextData,
|
||||||
|
...templateObject.variables,
|
||||||
|
...templateObject.context,
|
||||||
|
headerpath: `/${bodyshop.imexshopid}/header.html`,
|
||||||
|
bodyshop: bodyshop,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const render = await jsreport.renderAsync(reportRequest);
|
||||||
|
if (!renderAsHtml) {
|
||||||
|
render.download(Templates[templateObject.name].title || "");
|
||||||
|
} else {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
resolve(render.toString());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
notification["error"]({ message: JSON.stringify(error) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function RenderTemplates(
|
||||||
|
templateObjects,
|
||||||
|
bodyshop,
|
||||||
|
renderAsHtml = false
|
||||||
|
) {
|
||||||
|
//Query assets that match the template name. Must be in format <<templateName>>.query
|
||||||
|
let templateAndData = [];
|
||||||
|
let proms = [];
|
||||||
|
templateObjects.forEach((template) => {
|
||||||
|
proms.push(
|
||||||
|
(async () => {
|
||||||
|
let { contextData, useShopSpecificTemplate } = await fetchContextData(
|
||||||
|
template
|
||||||
|
);
|
||||||
|
templateAndData.push({
|
||||||
|
templateObject: template,
|
||||||
|
contextData,
|
||||||
|
useShopSpecificTemplate,
|
||||||
|
});
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
await Promise.all(proms);
|
||||||
|
let rootTemplate = templateAndData.shift();
|
||||||
|
|
||||||
|
let reportRequest = {
|
||||||
|
template: {
|
||||||
|
name: rootTemplate.useShopSpecificTemplate
|
||||||
|
? `/${bodyshop.imexshopid}/${rootTemplate.templateObject.name}`
|
||||||
|
: `/${rootTemplate.templateObject.name}`,
|
||||||
|
...(renderAsHtml ? {} : { recipe: "chrome-pdf" }),
|
||||||
|
pdfOperations: templateAndData.map((template) => {
|
||||||
|
return {
|
||||||
|
template: {
|
||||||
|
name: template.useShopSpecificTemplate
|
||||||
|
? `/${bodyshop.imexshopid}/${template.templateObject.name}`
|
||||||
|
: `/${template.templateObject.name}`,
|
||||||
|
...(renderAsHtml ? {} : { recipe: "chrome-pdf" }),
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
...template.contextData,
|
||||||
|
...template.templateObject.variables,
|
||||||
|
...template.templateObject.context,
|
||||||
|
headerpath: `/${bodyshop.imexshopid}/header.html`,
|
||||||
|
bodyshop: bodyshop,
|
||||||
|
},
|
||||||
|
type: "append",
|
||||||
|
mergeWholeDocument: true,
|
||||||
|
renderForEveryPage: true,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
...rootTemplate.contextData,
|
||||||
|
...rootTemplate.templateObject.variables,
|
||||||
|
...rootTemplate.templateObject.context,
|
||||||
|
headerpath: `/${bodyshop.imexshopid}/header.html`,
|
||||||
|
bodyshop: bodyshop,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log("reportRequest", reportRequest);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const render = await jsreport.renderAsync(reportRequest);
|
||||||
|
if (!renderAsHtml) {
|
||||||
|
render.download("Speed Print");
|
||||||
|
} else {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
resolve(render.toString());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
notification["error"]({ message: JSON.stringify(error) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GenerateDocument = async (template, messageOptions, sendType) => {
|
||||||
|
const bodyshop = store.getState().user.bodyshop;
|
||||||
|
if (sendType === "e") {
|
||||||
|
store.dispatch(
|
||||||
|
setEmailOptions({
|
||||||
|
messageOptions,
|
||||||
|
template,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await RenderTemplate(template, bodyshop);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const GenerateDocuments = async (templates) => {
|
||||||
|
const bodyshop = store.getState().user.bodyshop;
|
||||||
|
await RenderTemplates(templates, bodyshop);
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchContextData = async (templateObject) => {
|
||||||
jsreport.headers["Authorization"] =
|
jsreport.headers["Authorization"] =
|
||||||
"Bearer " + (await auth.currentUser.getIdToken());
|
"Bearer " + (await auth.currentUser.getIdToken());
|
||||||
|
|
||||||
@@ -44,7 +178,7 @@ export default async function RenderTemplate(
|
|||||||
"There are too many queries to choose from. Please ensure there are no conflicting keys."
|
"There are too many queries to choose from. Please ensure there are no conflicting keys."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let contextData;
|
let contextData = {};
|
||||||
if (templateQueryToExecute) {
|
if (templateQueryToExecute) {
|
||||||
const { data } = await client.query({
|
const { data } = await client.query({
|
||||||
query: gql(templateQueryToExecute),
|
query: gql(templateQueryToExecute),
|
||||||
@@ -54,83 +188,37 @@ export default async function RenderTemplate(
|
|||||||
contextData = data;
|
contextData = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
let reportRequest = {
|
return { contextData, useShopSpecificTemplate };
|
||||||
template: {
|
|
||||||
name: useShopSpecificTemplate
|
|
||||||
? `/${bodyshop.imexshopid}/${templateObject.name}`
|
|
||||||
: `/${templateObject.name}`,
|
|
||||||
...(renderAsHtml ? {} : { recipe: "chrome-pdf" }),
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
...(templateQueryToExecute ? contextData : {}),
|
|
||||||
...templateObject.variables,
|
|
||||||
...templateObject.context,
|
|
||||||
headerpath: `/${bodyshop.imexshopid}/header.html`,
|
|
||||||
bodyshop: bodyshop,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const render = await jsreport.renderAsync(reportRequest);
|
|
||||||
|
|
||||||
if (!renderAsHtml) {
|
|
||||||
render.download();
|
|
||||||
// var html =
|
|
||||||
// "<html>" +
|
|
||||||
// "<style>html,body {padding:0;margin:0;} iframe {width:100%;height:100%;border:0}</style>" +
|
|
||||||
// "<body>" +
|
|
||||||
// '<iframe type="application/pdf" src="' +
|
|
||||||
// render.toDataURI() +
|
|
||||||
// '"></iframe>' +
|
|
||||||
// "</body></html>";
|
|
||||||
// displayTemplateInWindowNoprint(html);
|
|
||||||
} else {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
resolve(render.toString());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const displayTemplateInWindow = (html) => {
|
|
||||||
try {
|
|
||||||
var newWin = window.open("", "_blank", "toolbar=0,location=0,menubar=0");
|
|
||||||
newWin.document.write(html);
|
|
||||||
|
|
||||||
setTimeout(function () {
|
|
||||||
newWin.document.close();
|
|
||||||
newWin.focus();
|
|
||||||
newWin.print();
|
|
||||||
newWin.close();
|
|
||||||
}, 500);
|
|
||||||
} catch (error) {
|
|
||||||
console.log("Unable to write to new window.", error);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const displayTemplateInWindowNoprint = (html) => {
|
//export const displayTemplateInWindow = (html) => {
|
||||||
try {
|
// try {
|
||||||
var newWin = window.open("", "_blank", "toolbar=0,location=0,menubar=0");
|
// var newWin = window.open("", "_blank", "toolbar=0,location=0,menubar=0");
|
||||||
newWin.document.write(html);
|
// newWin.document.write(html);
|
||||||
|
|
||||||
setTimeout(function () {
|
// setTimeout(function () {
|
||||||
newWin.document.close();
|
// newWin.document.close();
|
||||||
newWin.focus();
|
// newWin.focus();
|
||||||
//newWin.print();
|
// newWin.print();
|
||||||
//newWin.close();
|
// newWin.close();
|
||||||
}, 500);
|
// }, 500);
|
||||||
} catch (error) {
|
// } catch (error) {
|
||||||
console.log("Unable to write to new window.", error);
|
// console.log("Unable to write to new window.", error);
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
export const GenerateDocument = async (template, messageOptions, sendType) => {
|
// export const displayTemplateInWindowNoprint = (html) => {
|
||||||
const bodyshop = store.getState().user.bodyshop;
|
// try {
|
||||||
if (sendType === "e") {
|
// var newWin = window.open("", "_blank", "toolbar=0,location=0,menubar=0");
|
||||||
store.dispatch(
|
// newWin.document.write(html);
|
||||||
setEmailOptions({
|
|
||||||
messageOptions,
|
// setTimeout(function () {
|
||||||
template,
|
// newWin.document.close();
|
||||||
})
|
// newWin.focus();
|
||||||
);
|
// //newWin.print();
|
||||||
} else {
|
// //newWin.close();
|
||||||
await RenderTemplate(template, bodyshop);
|
// }, 500);
|
||||||
}
|
// } catch (error) {
|
||||||
};
|
// console.log("Unable to write to new window.", error);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|||||||
@@ -12,15 +12,6 @@ export const TemplateList = (type, context) => {
|
|||||||
//If there's no type or the type is job, send it back.
|
//If there's no type or the type is job, send it back.
|
||||||
...(!type || type === "job"
|
...(!type || type === "job"
|
||||||
? {
|
? {
|
||||||
estimate_detail: {
|
|
||||||
title: i18n.t("printcenter.jobs.estimate_detail"),
|
|
||||||
description: "Est Detail",
|
|
||||||
subject: `${i18n.t("printcenter.jobs.estimate_detail")} - ${
|
|
||||||
context && context.job && context.job.ro_number
|
|
||||||
}`,
|
|
||||||
key: "estimate_detail",
|
|
||||||
disabled: false,
|
|
||||||
},
|
|
||||||
casl_authorization: {
|
casl_authorization: {
|
||||||
title: i18n.t("printcenter.jobs.casl_authorization"),
|
title: i18n.t("printcenter.jobs.casl_authorization"),
|
||||||
description: "CASL Authorization",
|
description: "CASL Authorization",
|
||||||
@@ -209,7 +200,7 @@ export const TemplateList = (type, context) => {
|
|||||||
title: i18n.t("printcenter.jobs.parts_order"),
|
title: i18n.t("printcenter.jobs.parts_order"),
|
||||||
description: "Parts Order",
|
description: "Parts Order",
|
||||||
key: "parts_order",
|
key: "parts_order",
|
||||||
subject: `${bodyshop.shopname} Parts Order ${
|
subject: `${bodyshop && bodyshop.shopname} Parts Order ${
|
||||||
(context &&
|
(context &&
|
||||||
context &&
|
context &&
|
||||||
context.job &&
|
context.job &&
|
||||||
|
|||||||
Reference in New Issue
Block a user