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
@@ -33399,6 +33399,27 @@
</translation>
</translations>
</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>
<name>invoice_customer_payable</name>
<definition_loaded>false</definition_loaded>

View File

@@ -1,15 +1,71 @@
import { UploadOutlined } from "@ant-design/icons";
import { Divider, Form, Input, Select, Tabs, Upload } from "antd";
import { UploadOutlined, UserAddOutlined } from "@ant-design/icons";
import {
Divider,
Form,
Input,
Select,
Tabs,
Upload,
Space,
Menu,
Dropdown,
} from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
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 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 (
<div>
<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"
rules={[
{

View File

@@ -3,17 +3,17 @@ import { notification } from "antd";
import React, { useState } from "react";
//import SpinComponent from "../../components/loading-spinner/loading-spinner.component";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import AlertComponent from "../../components/alert/alert.component";
import { logImEXEvent } from "../../firebase/firebase.utils";
import {
DELETE_NOTE,
QUERY_NOTES_BY_JOB_PK,
} from "../../graphql/notes.queries";
import JobNotesComponent from "./jobs.notes.component";
import { insertAuditTrail } from "../../redux/application/application.actions";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
import JobNotesComponent from "./jobs.notes.component";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
@@ -63,6 +63,7 @@ export function JobNotesContainer({ jobId, insertAuditTrail }) {
refetch={refetch}
deleteLoading={deleteLoading}
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 { setModalContext } from "../../redux/modals/modals.actions";
import { DateTimeFormatter } from "../../utils/DateFormatter";
import { TemplateList } from "../../utils/TemplateConstants";
import NoteUpsertModal from "../note-upsert-modal/note-upsert-modal.container";
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
const mapStateToProps = createStructuredSelector({
jobRO: selectJobReadOnly,
@@ -33,8 +35,12 @@ export function JobNotesComponent({
jobId,
setNoteUpsertContext,
deleteLoading,
ro_number,
}) {
const { t } = useTranslation();
const Templates = TemplateList("job_special", {
ro_number,
});
const columns = [
{
@@ -107,6 +113,18 @@ export function JobNotesComponent({
>
<EditFilled />
</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>
),
},

View File

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

View File

@@ -100,6 +100,7 @@ export const QUERY_BODYSHOP = gql`
pbs_serialnumber
md_filehandlers
employees {
user_email
id
active
first_name
@@ -201,6 +202,7 @@ export const UPDATE_SHOP = gql`
last_name
employee_number
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!) {
jobs_by_pk(id: $id) {
id
ro_number
notes {
created_at
created_by

View File

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

View File

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

View File

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

View File

@@ -451,6 +451,15 @@ export const TemplateList = (type, context) => {
subject: i18n.t("printcenter.jobs.csi_invitation_action"),
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"