Email sending framework in place with nodemailer. Some rendering is happening dynamically, but i todesn't bring in most styles.

This commit is contained in:
Patrick Fic
2020-02-18 17:32:43 -08:00
parent dbf5c38752
commit 81e3ea622f
13 changed files with 277 additions and 16 deletions

View File

@@ -1,4 +1,4 @@
import { Input, Table, Button } from "antd";
import { Button, Input, Table } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
@@ -123,8 +123,9 @@ export default function JobLinesComponent({
{record.allocations && record.allocations.length > 0
? record.allocations.map(item => (
<div
key={item.id}
>{`${item.employee.first_name} ${item.employee.last_name} (${item.hours})`}</div>
key={
item.id
}>{`${item.employee.first_name} ${item.employee.last_name} (${item.hours})`}</div>
))
: null}
<AllocationsAssignmentContainer
@@ -184,8 +185,7 @@ export default function JobLinesComponent({
/>
<Button
disabled={selectedLines.length > 0 ? false : true}
onClick={() => setPartsModalVisible(true)}
>
onClick={() => setPartsModalVisible(true)}>
{t("parts.actions.order")}
</Button>
</div>
@@ -193,7 +193,7 @@ export default function JobLinesComponent({
}}
{...formItemLayout}
loading={loading}
size="small"
size='small'
pagination={{ position: "bottom", defaultPageSize: 50 }}
rowSelection={{
// selectedRowKeys: selectedLines,
@@ -201,7 +201,7 @@ export default function JobLinesComponent({
setSelectedLines(selectedRows)
}}
columns={columns.map(item => ({ ...item }))}
rowKey="id"
rowKey='id'
dataSource={jobLines}
onChange={handleTableChange}
/>

View File

@@ -56,6 +56,10 @@ export default connect(
data: linesToOrder.reduce((acc, value) => {
acc.push({
line_desc: value.line_desc,
oem_partno: value.oem_partno,
db_price: value.db_price,
act_price: value.act_price,
line_remarks: "Alalala",
joblineid: value.joblineid,
status:
bodyshop.md_order_statuses.default_ordered || "Ordered*"

View File

@@ -9,3 +9,47 @@ export const INSERT_NEW_PARTS_ORDERS = gql`
}
}
`;
export const REPORT_QUERY_PARTS_ORDER_BY_PK = gql`
query REPORT_QUERY_PARTS_ORDER_BY_PK($id: uuid!) {
parts_orders_by_pk(id: $id) {
job {
id
vehicle {
id
v_model_desc
v_make_desc
v_model_yr
v_vin
}
ro_number
est_number
}
id
deliver_by
parts_order_lines {
id
db_price
act_price
line_desc
line_remarks
oem_partno
status
}
status
user_email
}
bodyshops(where: { associations: { active: { _eq: true } } }) {
id
address1
address2
city
email
federal_tax_id
state
shopname
zip_post
logo_img_path
}
}
`;

View File

@@ -1,9 +1,42 @@
import React from 'react'
import { Button } from "antd";
import axios from "axios";
import React from "react";
import { useApolloClient } from "react-apollo";
import ReactDOMServer from "react-dom/server";
import { REPORT_QUERY_PARTS_ORDER_BY_PK } from "../../graphql/parts-orders.queries";
import ReportPartsOrder from "../../reports/pages/parts-order/parts-order.component";
export default function ManageRootPageComponent() {
return (
<div>
Temporary Home Page.
</div>
)
const client = useApolloClient();
return (
<div>
<Button
onClick={() => {
client
.query({
query: REPORT_QUERY_PARTS_ORDER_BY_PK,
variables: { id: "ebe0fb6b-6ec4-4ae0-8fdc-49bdf1e37ff3" },
fetchPolicy: "network-only"
})
.then(response => {
axios.post("/sendemail", {
from: { name: "Kavia Autobody" },
to: "snaptsoft@gmail.com",
replyTo: "patrickwf@gmail.com",
subject: "Sending Email using Node.js",
text: "Plaintext version of the message",
html: ReactDOMServer.renderToStaticMarkup(
<ReportPartsOrder
order={response.data.parts_orders_by_pk}
bodyshop={response.data.bodyshops[0]}
/>
)
});
});
}}>
Test Email
</Button>
<div>Testing Section-Report</div>
</div>
);
}

View File

@@ -0,0 +1,6 @@
import React from "react";
import { ApolloProvider } from "react-apollo";
export default function ReportEmailWrapper({ client, children }) {
return <ApolloProvider client={client}>{children}</ApolloProvider>;
}

View File

@@ -0,0 +1,26 @@
import React from "react";
import { Row, Col, Typography } from "antd";
export default function RcShopHeaderComponent({ bodyshop }) {
if (!bodyshop) return null;
return (
<Row>
<Col span={8}>
{bodyshop.logo_img_path ? (
<img
alt='Shop Logo'
src={bodyshop.logo_img_path}
style={{ height: "80px" }}
/>
) : null}
</Col>
<Col span={16}>
<Row>
<Typography.Title>{`${bodyshop.shopname}`}</Typography.Title>
</Row>
<Row>{`${bodyshop.address1 || ""} ${bodyshop.address2 ||
""}, ${bodyshop.city || ""}, ${bodyshop.state ||
""} ${bodyshop.zip_post || ""}`}</Row>
</Col>
</Row>
);
}

View File

@@ -0,0 +1,73 @@
import React from "react";
import { Row, Col, Table } from "antd";
import CurrencyFormatter from "../../../utils/CurrencyFormatter";
import { useTranslation } from "react-i18next";
export default function ReportPartsOrderComponent({ order, bodyshop }) {
const { t } = useTranslation();
const columns = [
{
title: t("joblines.fields.line_desc"),
dataIndex: "line_desc",
key: "line_desc"
},
{
title: t("joblines.fields.oem_partno"),
dataIndex: "oem_partno",
key: "oem_partno",
render: (text, record) => (
<span>
{record.oem_partno ? record.oem_partno : record.op_code_desc}
</span>
)
},
{
title: t("joblines.fields.line_remarks"),
dataIndex: "line_remarks",
key: "line_remarks"
},
{
title: t("joblines.fields.db_price"),
dataIndex: "db_price",
key: "db_price",
render: (text, record) => (
<CurrencyFormatter>{record.db_price}</CurrencyFormatter>
)
},
{
title: t("joblines.fields.act_price"),
dataIndex: "act_price",
key: "act_price",
render: (text, record) => (
<CurrencyFormatter>{record.act_price}</CurrencyFormatter>
)
}
];
return (
<div>
<Row>
<Col span={4}>
<div>{`PO Number: ${order.po_number || ""}`}</div>
<div>{`Delivery By: ${order.deliver_by || ""}`}</div>
<div>{`Ordered By: ${order.user_email || ""}`}</div>
</Col>
<Col span={4}>
<div>{`Vehicle Description: ${order.job.vehicle.v_model_yr ||
""} ${order.job.vehicle.v_make_desc || ""} ${order.job.vehicle
.v_model_desc || ""}`}</div>
<div>{`VIN: ${order.job.vehicle.v_vin || ""}`}</div>
</Col>
</Row>
<Row>
<Table
size='small'
columns={columns.map(item => ({ ...item }))}
pagination={false}
rowKey='id'
dataSource={order.parts_order_lines ? order.parts_order_lines : null}
/>
</Row>
</div>
);
}

View File

@@ -0,0 +1,24 @@
import React from "react";
import { useQuery } from "react-apollo";
import AlertComponent from "../../../components/alert/alert.component";
import LoadingSpinner from "../../../components/loading-spinner/loading-spinner.component";
import { REPORT_QUERY_PARTS_ORDER_BY_PK } from "../../../graphql/parts-orders.queries";
import RcShopHeaderComponent from "../../components/shop-header/shop-header.component";
import ReportPartsOrderComponent from "./parts-order.component";
export default function ReportPartsOrderContainer({ orderId }) {
const { loading, error, data } = useQuery(REPORT_QUERY_PARTS_ORDER_BY_PK, {
variables: { id: orderId },
fetchPolicy: "network-only",
});
if (loading) return <LoadingSpinner />;
if (error) return <AlertComponent message={error.message} type='error' />;
return (
<div>
<RcShopHeaderComponent bodyshop={data ? data.bodyshops[0] : null} />
<ReportPartsOrderComponent
order={data ? data.parts_orders_by_pk : null}
/>
</div>
);
}