IO-1530 Email individual note.

This commit is contained in:
Patrick Fic
2021-11-15 11:06:10 -08:00
parent ab38f85d38
commit efc2844d99
11 changed files with 121 additions and 9 deletions

View File

@@ -1,4 +1,4 @@
<babeledit_project be_version="2.7.1" version="1.2"> <babeledit_project version="1.2" be_version="2.7.1">
<!-- <!--
BabelEdit project file BabelEdit project file
@@ -33399,6 +33399,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>individual_job_note</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>invoice_customer_payable</name> <name>invoice_customer_payable</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>

View File

@@ -1,15 +1,71 @@
import { UploadOutlined } from "@ant-design/icons"; import { UploadOutlined, UserAddOutlined } from "@ant-design/icons";
import { Divider, Form, Input, Select, Tabs, Upload } from "antd"; import {
Divider,
Form,
Input,
Select,
Tabs,
Upload,
Space,
Menu,
Dropdown,
} from "antd";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import EmailDocumentsComponent from "../email-documents/email-documents.component"; import EmailDocumentsComponent from "../email-documents/email-documents.component";
import _ from "lodash";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(EmailOverlayComponent);
export default function EmailOverlayComponent({ form, selectedMediaState }) { export function EmailOverlayComponent({ form, selectedMediaState, bodyshop }) {
const { t } = useTranslation(); const { t } = useTranslation();
const handleClick = ({ item, key, keyPath }) => {
const email = item.props.value;
form.setFieldsValue({ to: _.uniq([...form.getFieldValue("to"), email]) });
};
const menu = (
<div>
<Menu onClick={handleClick}>
{bodyshop.employees
.filter((e) => e.user_email)
.map((e, idx) => (
<Menu.Item value={e.user_email} key={idx}>
{`${e.first_name} ${e.last_name}`}
</Menu.Item>
))}
</Menu>
</div>
);
return ( return (
<div> <div>
<Form.Item <Form.Item
label={t("emails.fields.to")} label={
<Space>
{t("emails.fields.to")}
<Dropdown overlay={menu}>
<a
className="ant-dropdown-link"
href=" #"
onClick={(e) => e.preventDefault()}
>
<UserAddOutlined />
</a>
</Dropdown>
</Space>
}
name="to" name="to"
rules={[ rules={[
{ {

View File

@@ -3,17 +3,17 @@ import { notification } from "antd";
import React, { useState } from "react"; import React, { useState } from "react";
//import SpinComponent from "../../components/loading-spinner/loading-spinner.component"; //import SpinComponent from "../../components/loading-spinner/loading-spinner.component";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import AlertComponent from "../../components/alert/alert.component"; import AlertComponent from "../../components/alert/alert.component";
import { logImEXEvent } from "../../firebase/firebase.utils"; import { logImEXEvent } from "../../firebase/firebase.utils";
import { import {
DELETE_NOTE, DELETE_NOTE,
QUERY_NOTES_BY_JOB_PK, QUERY_NOTES_BY_JOB_PK,
} from "../../graphql/notes.queries"; } from "../../graphql/notes.queries";
import JobNotesComponent from "./jobs.notes.component";
import { insertAuditTrail } from "../../redux/application/application.actions"; import { insertAuditTrail } from "../../redux/application/application.actions";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import AuditTrailMapping from "../../utils/AuditTrailMappings"; import AuditTrailMapping from "../../utils/AuditTrailMappings";
import JobNotesComponent from "./jobs.notes.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser //currentUser: selectCurrentUser
@@ -63,6 +63,7 @@ export function JobNotesContainer({ jobId, insertAuditTrail }) {
refetch={refetch} refetch={refetch}
deleteLoading={deleteLoading} deleteLoading={deleteLoading}
handleNoteDelete={handleNoteDelete} handleNoteDelete={handleNoteDelete}
ro_number={data ? data.jobs_by_pk.ro_number : null}
/> />
); );
} }

View File

@@ -13,7 +13,9 @@ import { createStructuredSelector } from "reselect";
import { selectJobReadOnly } from "../../redux/application/application.selectors"; import { selectJobReadOnly } from "../../redux/application/application.selectors";
import { setModalContext } from "../../redux/modals/modals.actions"; import { setModalContext } from "../../redux/modals/modals.actions";
import { DateTimeFormatter } from "../../utils/DateFormatter"; import { DateTimeFormatter } from "../../utils/DateFormatter";
import { TemplateList } from "../../utils/TemplateConstants";
import NoteUpsertModal from "../note-upsert-modal/note-upsert-modal.container"; import NoteUpsertModal from "../note-upsert-modal/note-upsert-modal.container";
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
jobRO: selectJobReadOnly, jobRO: selectJobReadOnly,
@@ -33,8 +35,12 @@ export function JobNotesComponent({
jobId, jobId,
setNoteUpsertContext, setNoteUpsertContext,
deleteLoading, deleteLoading,
ro_number,
}) { }) {
const { t } = useTranslation(); const { t } = useTranslation();
const Templates = TemplateList("job_special", {
ro_number,
});
const columns = [ const columns = [
{ {
@@ -107,6 +113,18 @@ export function JobNotesComponent({
> >
<EditFilled /> <EditFilled />
</Button> </Button>
<PrintWrapperComponent
emailOnly
templateObject={{
name: Templates.individual_job_note.key,
variables: { id: record.id },
}}
messageObject={{
subject: Templates.individual_job_note.subject,
}}
id={record.id}
/>
</Space> </Space>
), ),
}, },

View File

@@ -8,6 +8,7 @@ export default function PrintWrapperComponent({
messageObject = {}, messageObject = {},
children, children,
id, id,
emailOnly = false,
}) { }) {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const handlePrint = async (type) => { const handlePrint = async (type) => {
@@ -19,7 +20,7 @@ export default function PrintWrapperComponent({
return ( return (
<Space> <Space>
{children || null} {children || null}
<PrinterFilled onClick={() => handlePrint("p")} /> {!emailOnly && <PrinterFilled onClick={() => handlePrint("p")} />}
<MailFilled onClick={() => handlePrint("e")} /> <MailFilled onClick={() => handlePrint("e")} />
{loading && <Spin />} {loading && <Spin />}
</Space> </Space>

View File

@@ -100,6 +100,7 @@ export const QUERY_BODYSHOP = gql`
pbs_serialnumber pbs_serialnumber
md_filehandlers md_filehandlers
employees { employees {
user_email
id id
active active
first_name first_name
@@ -201,6 +202,7 @@ export const UPDATE_SHOP = gql`
last_name last_name
employee_number employee_number
rates rates
user_email
} }
} }
} }

View File

@@ -14,6 +14,7 @@ export const QUERY_NOTES_BY_JOB_PK = gql`
query QUERY_NOTES_BY_JOB_PK($id: uuid!) { query QUERY_NOTES_BY_JOB_PK($id: uuid!) {
jobs_by_pk(id: $id) { jobs_by_pk(id: $id) {
id id
ro_number
notes { notes {
created_at created_at
created_by created_by

View File

@@ -1993,6 +1993,7 @@
"fippa_authorization": "FIPPA Authorization", "fippa_authorization": "FIPPA Authorization",
"glass_express_checklist": "Glass Express Checklist", "glass_express_checklist": "Glass Express Checklist",
"guarantee": "Repair Guarantee", "guarantee": "Repair Guarantee",
"individual_job_note": "Job Note RO # {{ro_number}}",
"invoice_customer_payable": "Invoice (Customer Payable)", "invoice_customer_payable": "Invoice (Customer Payable)",
"invoice_total_payable": "Invoice (Total Payable)", "invoice_total_payable": "Invoice (Total Payable)",
"iou_form": "IOU Form", "iou_form": "IOU Form",

View File

@@ -1993,6 +1993,7 @@
"fippa_authorization": "", "fippa_authorization": "",
"glass_express_checklist": "", "glass_express_checklist": "",
"guarantee": "", "guarantee": "",
"individual_job_note": "",
"invoice_customer_payable": "", "invoice_customer_payable": "",
"invoice_total_payable": "", "invoice_total_payable": "",
"iou_form": "", "iou_form": "",

View File

@@ -1993,6 +1993,7 @@
"fippa_authorization": "", "fippa_authorization": "",
"glass_express_checklist": "", "glass_express_checklist": "",
"guarantee": "", "guarantee": "",
"individual_job_note": "",
"invoice_customer_payable": "", "invoice_customer_payable": "",
"invoice_total_payable": "", "invoice_total_payable": "",
"iou_form": "", "iou_form": "",

View File

@@ -451,6 +451,15 @@ export const TemplateList = (type, context) => {
subject: i18n.t("printcenter.jobs.csi_invitation_action"), subject: i18n.t("printcenter.jobs.csi_invitation_action"),
disabled: false, disabled: false,
}, },
individual_job_note: {
title: i18n.t("printcenter.jobs.individual_job_note"),
description: "CSI invite",
key: "individual_job_note",
subject: i18n.t("printcenter.jobs.individual_job_note", {
ro_number: (context && context.ro_number) || "",
}),
disabled: false,
},
} }
: {}), : {}),
...(!type || type === "appointment" ...(!type || type === "appointment"