diff --git a/client/package.json b/client/package.json
index bd23011dc..53b892548 100644
--- a/client/package.json
+++ b/client/package.json
@@ -4,6 +4,8 @@
"private": true,
"proxy": "https://localhost:5000",
"dependencies": {
+ "@ckeditor/ckeditor5-build-classic": "^16.0.0",
+ "@ckeditor/ckeditor5-react": "^2.1.0",
"antd": "^3.26.8",
"apollo-boost": "^0.4.4",
"apollo-link-context": "^1.0.19",
@@ -23,6 +25,7 @@
"react-big-calendar": "^0.23.0",
"react-chartjs-2": "^2.9.0",
"react-dom": "^16.12.0",
+ "react-html-email": "^3.0.0",
"react-i18next": "^11.3.1",
"react-icons": "^3.9.0",
"react-image-file-resizer": "^0.2.1",
diff --git a/client/src/components/send-email-button/send-email-button.component.jsx b/client/src/components/send-email-button/send-email-button.component.jsx
new file mode 100644
index 000000000..86187363d
--- /dev/null
+++ b/client/src/components/send-email-button/send-email-button.component.jsx
@@ -0,0 +1,46 @@
+import React from "react";
+import { Input } from "antd";
+import CKEditor from "@ckeditor/ckeditor5-react";
+import ClassicEditor from "@ckeditor/ckeditor5-build-classic";
+
+export default function SendEmailButtonComponent({
+ emailConfig,
+ handleConfigChange,
+ handleHtmlChange
+}) {
+ return (
+
+ THis is where the text editing will happen To
+
+ CC
+
+ Subject
+
+ {
+ // You can store the "editor" and use when it is needed.
+ console.log("Editor is ready to use!", editor);
+ }}
+ onChange={(event, editor) => {
+ const data = editor.getData();
+ console.log({ event, editor, data });
+ handleHtmlChange(data);
+ }}
+ />
+
+ );
+}
diff --git a/client/src/components/send-email-button/send-email-button.container.jsx b/client/src/components/send-email-button/send-email-button.container.jsx
new file mode 100644
index 000000000..23be75fb3
--- /dev/null
+++ b/client/src/components/send-email-button/send-email-button.container.jsx
@@ -0,0 +1,72 @@
+import { Button, Modal } from "antd";
+import axios from "axios";
+import React, { useState } from "react";
+import { useQuery } from "react-apollo";
+//Message options has the to & from details
+//Query Config is what can get popped into UseQuery(QUERY_NAME, {variables: {vars}, fetchonly})
+//Template Which template should be used to send the email.
+import ReactDOMServer from "react-dom/server";
+import { renderEmail } from "react-html-email";
+import LoadingSpinner from "../loading-spinner/loading-spinner.component";
+import SendEmailButtonComponent from "./send-email-button.component";
+export default function SendEmail({
+ MessageOptions,
+ QueryConfig,
+ Template,
+ ...otherProps
+}) {
+ const [modalVisible, setModalVisible] = useState(false);
+ const [emailConfig, setEmailConfig] = useState({ ...MessageOptions });
+ const [gqlQuery, vars] = QueryConfig;
+
+ const { loading, data } = useQuery(gqlQuery, {
+ ...vars,
+ fetchPolicy: "network-only",
+ skip: !modalVisible
+ });
+ if (data && !emailConfig.html) {
+ console.log(ReactDOMServer.renderToStaticMarkup( ));
+ setEmailConfig({
+ ...emailConfig,
+ //html: ReactDOMServer.renderToStaticMarkup( )
+ html: renderEmail( )
+ });
+ }
+
+ const handleConfigChange = event => {
+ const { name, value } = event.target;
+ setEmailConfig({ ...emailConfig, [name]: value });
+ };
+
+ const handleHtmlChange = text => {
+ setEmailConfig({ ...emailConfig, html: text });
+ };
+
+ const sendEmail = () => {
+ axios.post("/sendemail", emailConfig).then(response => {
+ alert(JSON.stringify(response));
+ });
+ };
+ return (
+
+ setModalVisible(false)}>
+
+
+
+
+
+ setModalVisible(true)}>
+ {otherProps.children}
+
+
+ );
+}
diff --git a/client/src/emails/components/grid/grid.component.jsx b/client/src/emails/components/grid/grid.component.jsx
new file mode 100644
index 000000000..ae632e913
--- /dev/null
+++ b/client/src/emails/components/grid/grid.component.jsx
@@ -0,0 +1,46 @@
+import React from "react";
+
+function Cell({ children }) {
+ return {children} ;
+}
+
+function Row({ children }) {
+ return (
+
+ {React.Children.map(children, el => {
+ if (el.type === Cell) return el;
+
+ return {el} ;
+ })}
+
+ );
+}
+
+function Grid({ children }) {
+ return (
+
+
+ {React.Children.map(children, el => {
+ if (!el) return;
+
+ if (el.type === Row) return el;
+
+ if (el.type === Cell) {
+ return {el} ;
+ }
+
+ return (
+
+ {el}
+
+ );
+ })}
+
+
+ );
+}
+
+Grid.Row = Row;
+Grid.Cell = Cell;
+
+export default Grid;
diff --git a/client/src/emails/parts-order/parts-order.email.jsx b/client/src/emails/parts-order/parts-order.email.jsx
new file mode 100644
index 000000000..5121e9346
--- /dev/null
+++ b/client/src/emails/parts-order/parts-order.email.jsx
@@ -0,0 +1,30 @@
+import React from "react";
+import { A, Box, Email, Item, Span } from "react-html-email";
+
+export default function PartsOrderEmail({ data }) {
+ console.log("Data", data);
+ return (
+
+
+ -
+
+ This is an example email made with:
+
+ react-html-email
+
+ .
+
+
+ -
+
+ This is an example email made with:
+
+ react-html-email
+
+ .
+
+
+
+
+ );
+}
diff --git a/client/src/emails/parts-order/parts-order.query.js b/client/src/emails/parts-order/parts-order.query.js
new file mode 100644
index 000000000..77ca87c13
--- /dev/null
+++ b/client/src/emails/parts-order/parts-order.query.js
@@ -0,0 +1,45 @@
+import { gql } from "apollo-boost";
+
+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
+ }
+ }
+`;
diff --git a/client/src/graphql/parts-orders.queries.js b/client/src/graphql/parts-orders.queries.js
index 34eb515e1..b2124383c 100644
--- a/client/src/graphql/parts-orders.queries.js
+++ b/client/src/graphql/parts-orders.queries.js
@@ -9,47 +9,3 @@ 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
- }
- }
-`;
diff --git a/client/src/pages/manage-root/manage-root.page.component.jsx b/client/src/pages/manage-root/manage-root.page.component.jsx
index 4d2ba2c2c..da7be137e 100644
--- a/client/src/pages/manage-root/manage-root.page.component.jsx
+++ b/client/src/pages/manage-root/manage-root.page.component.jsx
@@ -1,42 +1,29 @@
-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";
+import SendEmailButton from "../../components/send-email-button/send-email-button.container";
+import PartsOrderEmail from "../../emails/parts-order/parts-order.email";
+import { REPORT_QUERY_PARTS_ORDER_BY_PK } from "../../emails/parts-order/parts-order.query";
export default function ManageRootPageComponent() {
- const client = useApolloClient();
+ //const client = useApolloClient();
return (
-
{
- 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(
-
- )
- });
- });
- }}>
- Test Email
-
-
Testing Section-Report
+
+ Send an Email in new Window
+
);
}
diff --git a/client/src/pages/manage/manage.page.jsx b/client/src/pages/manage/manage.page.jsx
index 9c04acbec..d194eef59 100644
--- a/client/src/pages/manage/manage.page.jsx
+++ b/client/src/pages/manage/manage.page.jsx
@@ -60,15 +60,13 @@ export default function Manage({ match }) {
+ className='content-container'
+ style={{ padding: "0em 4em 4em" }}>
- }
- >
+ }>
diff --git a/client/src/reports/components/email-wrapper/email-wrapper.component.jsx b/client/src/reports/components/email-wrapper/email-wrapper.component.jsx
deleted file mode 100644
index 3e84c11bf..000000000
--- a/client/src/reports/components/email-wrapper/email-wrapper.component.jsx
+++ /dev/null
@@ -1,6 +0,0 @@
-import React from "react";
-import { ApolloProvider } from "react-apollo";
-
-export default function ReportEmailWrapper({ client, children }) {
- return {children} ;
-}
diff --git a/client/src/reports/components/shop-header/shop-header.component.jsx b/client/src/reports/components/shop-header/shop-header.component.jsx
deleted file mode 100644
index 9561f1853..000000000
--- a/client/src/reports/components/shop-header/shop-header.component.jsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import React from "react";
-import { Row, Col, Typography } from "antd";
-export default function RcShopHeaderComponent({ bodyshop }) {
- if (!bodyshop) return null;
- return (
-
-
- {bodyshop.logo_img_path ? (
-
- ) : null}
-
-
-
- {`${bodyshop.shopname}`}
-
- {`${bodyshop.address1 || ""} ${bodyshop.address2 ||
- ""}, ${bodyshop.city || ""}, ${bodyshop.state ||
- ""} ${bodyshop.zip_post || ""}`}
-
-
- );
-}
diff --git a/client/src/reports/pages/parts-order/parts-order.component.jsx b/client/src/reports/pages/parts-order/parts-order.component.jsx
deleted file mode 100644
index 94864df10..000000000
--- a/client/src/reports/pages/parts-order/parts-order.component.jsx
+++ /dev/null
@@ -1,73 +0,0 @@
-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) => (
-
- {record.oem_partno ? record.oem_partno : record.op_code_desc}
-
- )
- },
- {
- 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) => (
- {record.db_price}
- )
- },
- {
- title: t("joblines.fields.act_price"),
- dataIndex: "act_price",
- key: "act_price",
- render: (text, record) => (
- {record.act_price}
- )
- }
- ];
-
- return (
-
-
-
- {`PO Number: ${order.po_number || ""}`}
- {`Delivery By: ${order.deliver_by || ""}`}
- {`Ordered By: ${order.user_email || ""}`}
-
-
- {`Vehicle Description: ${order.job.vehicle.v_model_yr ||
- ""} ${order.job.vehicle.v_make_desc || ""} ${order.job.vehicle
- .v_model_desc || ""}`}
- {`VIN: ${order.job.vehicle.v_vin || ""}`}
-
-
-
- ({ ...item }))}
- pagination={false}
- rowKey='id'
- dataSource={order.parts_order_lines ? order.parts_order_lines : null}
- />
-
-
- );
-}
diff --git a/client/src/reports/pages/parts-order/parts-order.container.jsx b/client/src/reports/pages/parts-order/parts-order.container.jsx
deleted file mode 100644
index 5ccfc8893..000000000
--- a/client/src/reports/pages/parts-order/parts-order.container.jsx
+++ /dev/null
@@ -1,24 +0,0 @@
-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 ;
- if (error) return ;
- return (
-
-
-
-
- );
-}
diff --git a/client/yarn.lock b/client/yarn.lock
index d0b1a823a..151ec2296 100644
--- a/client/yarn.lock
+++ b/client/yarn.lock
@@ -967,6 +967,18 @@
lodash "^4.17.13"
to-fast-properties "^2.0.0"
+"@ckeditor/ckeditor5-build-classic@^16.0.0":
+ version "16.0.0"
+ resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-build-classic/-/ckeditor5-build-classic-16.0.0.tgz#9141e94ea6765eda4925aaf062448507410bbe70"
+ integrity sha512-gBfZqWg3hmCvhq6/wX5UJp4qwl6gB+NJPpOkya2Y3jWKA0HKf3UdlhIvaHq7dRaqhi4unmqaJZVEk5VpZ1vDOg==
+
+"@ckeditor/ckeditor5-react@^2.1.0":
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-react/-/ckeditor5-react-2.1.0.tgz#f612546a5a328899a436d71b72ffd632600049e8"
+ integrity sha512-rlHjRKhwP9tNK0Yj2UJShL14mRfxLPgJ+Pv6zTv/Mvmd4wrwGnJf+5ybOAGK92S02hP1cXH+9km+PRO1b4V+ng==
+ dependencies:
+ prop-types "^15.6.1"
+
"@cnakazawa/watch@^1.0.3":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.3.tgz#099139eaec7ebf07a27c1786a3ff64f39464d2ef"
@@ -9755,7 +9767,7 @@ prop-types-exact@^1.2.0:
object.assign "^4.1.0"
reflect.ownkeys "^0.2.0"
-prop-types@15.x, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.5.9, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2:
+prop-types@15.x, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.5.9, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@@ -10499,6 +10511,13 @@ react-error-overlay@^6.0.5:
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.5.tgz#55d59c2a3810e8b41922e0b4e5f85dcf239bd533"
integrity sha512-+DMR2k5c6BqMDSMF8hLH0vYKtKTeikiFW+fj0LClN+XZg4N9b8QUAdHC62CGWNLTi/gnuuemNcNcTFrCvK1f+A==
+react-html-email@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/react-html-email/-/react-html-email-3.0.0.tgz#a5a51b78271a33daf9b14638e9e4c5df93f691aa"
+ integrity sha512-eIBmZjqoS1SLAOi/QYTHLnZSmBM5AhP/cScJGhVDHlBJFtMyiR4qBUQYQDCqRtNPDKHWGMbbS/+XHSgD+C2hng==
+ dependencies:
+ prop-types "^15.5.10"
+
react-i18next@^11.3.1:
version "11.3.1"
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.3.1.tgz#9269282c3f566015f0bdf8fdbf46782bbe50f5a7"