Added appointment reminder email + gql fragments for emails.
This commit is contained in:
@@ -2,8 +2,10 @@ import React 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";
|
||||||
import T from "../../emails/parts-order/parts-order.email";
|
import T, {
|
||||||
import { REPORT_QUERY_PARTS_ORDER_BY_PK } from "../../emails/parts-order/parts-order.query";
|
Subject
|
||||||
|
} from "../../emails/templates/appointment-confirmation/appointment-confirmation.template";
|
||||||
|
import { EMAIL_APPOINTMENT_CONFIRMATION } from "../../emails/templates/appointment-confirmation/appointment-confirmation.query";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
//currentUser: selectCurrentUser
|
//currentUser: selectCurrentUser
|
||||||
@@ -20,17 +22,19 @@ export default connect(
|
|||||||
onClick={() =>
|
onClick={() =>
|
||||||
setEmailOptions({
|
setEmailOptions({
|
||||||
messageOptions: {
|
messageOptions: {
|
||||||
from: { name: "Kavia Autobdoy", address: "noreply@bodyshop.app" },
|
from: { name: "Kavia Autobody", address: "noreply@bodyshop.app" },
|
||||||
to: "patrickwf@gmail.com",
|
to: "patrickwf@gmail.com",
|
||||||
replyTo: "snaptsoft@gmail.com"
|
replyTo: "snaptsoft@gmail.com",
|
||||||
|
subject: Subject
|
||||||
},
|
},
|
||||||
template: T,
|
template: T,
|
||||||
queryConfig: [
|
queryConfig: [
|
||||||
REPORT_QUERY_PARTS_ORDER_BY_PK,
|
EMAIL_APPOINTMENT_CONFIRMATION,
|
||||||
{ variables: { id: "46f3aa34-c3bd-46c8-83fc-c93b7ce84f46" } }
|
{ variables: { id: "91bb31dd-ea87-4cfc-bbe2-2ec754dcb861" } }
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
}>
|
}
|
||||||
|
>
|
||||||
Set email config.
|
Set email config.
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -13,19 +13,19 @@ export default function EmailOverlayComponent({
|
|||||||
<Input
|
<Input
|
||||||
defaultValue={messageOptions.to}
|
defaultValue={messageOptions.to}
|
||||||
onChange={handleConfigChange}
|
onChange={handleConfigChange}
|
||||||
name='to'
|
name="to"
|
||||||
/>
|
/>
|
||||||
CC
|
CC
|
||||||
<Input
|
<Input
|
||||||
defaultValue={messageOptions.cc}
|
defaultValue={messageOptions.cc}
|
||||||
onChange={handleConfigChange}
|
onChange={handleConfigChange}
|
||||||
name='cc'
|
name="cc"
|
||||||
/>
|
/>
|
||||||
Subject
|
Subject
|
||||||
<Input
|
<Input
|
||||||
defaultValue={messageOptions.subject}
|
defaultValue={messageOptions.subject}
|
||||||
onChange={handleConfigChange}
|
onChange={handleConfigChange}
|
||||||
name='subject'
|
name="subject"
|
||||||
/>
|
/>
|
||||||
<CKEditor
|
<CKEditor
|
||||||
editor={ClassicEditor}
|
editor={ClassicEditor}
|
||||||
|
|||||||
@@ -7,7 +7,10 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { toggleEmailOverlayVisible } from "../../redux/email/email.actions";
|
import { toggleEmailOverlayVisible } from "../../redux/email/email.actions";
|
||||||
import { selectEmailConfig, selectEmailVisible } from "../../redux/email/email.selectors.js";
|
import {
|
||||||
|
selectEmailConfig,
|
||||||
|
selectEmailVisible
|
||||||
|
} from "../../redux/email/email.selectors.js";
|
||||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||||
import EmailOverlayComponent from "./email-overlay.component";
|
import EmailOverlayComponent from "./email-overlay.component";
|
||||||
|
|
||||||
@@ -99,6 +102,14 @@ export default connect(
|
|||||||
messageOptions={messageOptions}
|
messageOptions={messageOptions}
|
||||||
handleHtmlChange={handleHtmlChange}
|
handleHtmlChange={handleHtmlChange}
|
||||||
/>
|
/>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
console.log(messageOptions.html);
|
||||||
|
navigator.clipboard.writeText(messageOptions.html);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Get HTML
|
||||||
|
</button>
|
||||||
</LoadingSpinner>
|
</LoadingSpinner>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
|||||||
0
client/src/components/email-overlay/email-setup.md
Normal file
0
client/src/components/email-overlay/email-setup.md
Normal file
@@ -18,8 +18,8 @@ import {
|
|||||||
setEmailOptions,
|
setEmailOptions,
|
||||||
toggleEmailOverlayVisible
|
toggleEmailOverlayVisible
|
||||||
} from "../../redux/email/email.actions";
|
} from "../../redux/email/email.actions";
|
||||||
import PartsOrderEmailTemplate from "../../emails/parts-order/parts-order.email";
|
import PartsOrderEmailTemplate from "../../emails/templates/parts-order/parts-order.email";
|
||||||
import { REPORT_QUERY_PARTS_ORDER_BY_PK } from "../../emails/parts-order/parts-order.query";
|
import { REPORT_QUERY_PARTS_ORDER_BY_PK } from "../../emails/templates/parts-order/parts-order.query";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
currentUser: selectCurrentUser,
|
currentUser: selectCurrentUser,
|
||||||
@@ -131,7 +131,7 @@ export default connect(
|
|||||||
if (sendType === "e") {
|
if (sendType === "e") {
|
||||||
//Show the email modal and set the data.
|
//Show the email modal and set the data.
|
||||||
|
|
||||||
//TODO Remove some of the options below.
|
//TODO Remove hardcoding
|
||||||
setEmailOptions({
|
setEmailOptions({
|
||||||
messageOptions: {
|
messageOptions: {
|
||||||
from: {
|
from: {
|
||||||
@@ -151,7 +151,7 @@ export default connect(
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
toggleEmailOverlayVisible();
|
//toggleEmailOverlayVisible();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
@@ -173,8 +173,9 @@ export default connect(
|
|||||||
<Modal
|
<Modal
|
||||||
visible={modalVisible}
|
visible={modalVisible}
|
||||||
onCancel={() => setModalVisible(false)}
|
onCancel={() => setModalVisible(false)}
|
||||||
onOk={handleOk}>
|
onOk={handleOk}
|
||||||
{error ? <AlertComponent message={error.message} type='error' /> : null}
|
>
|
||||||
|
{error ? <AlertComponent message={error.message} type="error" /> : null}
|
||||||
<LoadingSpinner loading={loading}>
|
<LoadingSpinner loading={loading}>
|
||||||
<PartsOrderModalComponent
|
<PartsOrderModalComponent
|
||||||
vendorList={(data && data.vendors) || []}
|
vendorList={(data && data.vendors) || []}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import { useTranslation } from "react-i18next";
|
|||||||
import ScheduleDayViewContainer from "../schedule-day-view/schedule-day-view.container";
|
import ScheduleDayViewContainer from "../schedule-day-view/schedule-day-view.container";
|
||||||
import ScheduleExistingAppointmentsList from "../schedule-existing-appointments-list/schedule-existing-appointments-list.component";
|
import ScheduleExistingAppointmentsList from "../schedule-existing-appointments-list/schedule-existing-appointments-list.component";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default function ScheduleJobModalComponent({
|
export default function ScheduleJobModalComponent({
|
||||||
existingAppointments,
|
existingAppointments,
|
||||||
appData,
|
appData,
|
||||||
|
|||||||
18
client/src/emails/components/fragments.queries.js
Normal file
18
client/src/emails/components/fragments.queries.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { gql } from "apollo-boost";
|
||||||
|
|
||||||
|
export const shopAttributes = gql`
|
||||||
|
fragment shopData on query_root {
|
||||||
|
bodyshops(where: { associations: { active: { _eq: true } } }) {
|
||||||
|
id
|
||||||
|
address1
|
||||||
|
address2
|
||||||
|
city
|
||||||
|
email
|
||||||
|
federal_tax_id
|
||||||
|
state
|
||||||
|
shopname
|
||||||
|
zip_post
|
||||||
|
logo_img_path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { gql } from "apollo-boost";
|
||||||
|
import { shopAttributes } from "../../components/fragments.queries";
|
||||||
|
|
||||||
|
export const EMAIL_APPOINTMENT_CONFIRMATION = gql`
|
||||||
|
query EMAIL_APPOINTMENT_CONFIRMATION($id: uuid!) {
|
||||||
|
appointments_by_pk(id: $id) {
|
||||||
|
start
|
||||||
|
title
|
||||||
|
job {
|
||||||
|
ownr_fn
|
||||||
|
ownr_ln
|
||||||
|
ownr_ea
|
||||||
|
}
|
||||||
|
}
|
||||||
|
...shopData
|
||||||
|
}
|
||||||
|
${shopAttributes}
|
||||||
|
`;
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import React from "react";
|
||||||
|
import styled from "styled-components";
|
||||||
|
import Header from "../../components/header/header.component";
|
||||||
|
import { DateTimeFormatter } from "../../../utils/DateFormatter";
|
||||||
|
|
||||||
|
const D = styled.div`
|
||||||
|
table {
|
||||||
|
font-family: arial, sans-serif;
|
||||||
|
border-collapse: collapse;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
td,
|
||||||
|
th {
|
||||||
|
border: 1px solid #dddddd;
|
||||||
|
text-align: left;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:nth-child(even) {
|
||||||
|
background-color: #dddddd;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const Subject = "Appointment Reminder";
|
||||||
|
|
||||||
|
export default function AppointmentConfirmationEmail({ data }) {
|
||||||
|
const appointment = data.appointments_by_pk;
|
||||||
|
console.log("appointment", appointment);
|
||||||
|
return (
|
||||||
|
<D>
|
||||||
|
<Header bodyshop={data.bodyshops[0]} />
|
||||||
|
<strong>Appointment Reminder</strong>
|
||||||
|
<p> Dear {`${appointment.job.ownr_fn} ${appointment.job.ownr_ln}`},</p>
|
||||||
|
<p>
|
||||||
|
You have an appointment at {data.bodyshops[0].shopname} on{" "}
|
||||||
|
<DateTimeFormatter>{appointment.start}</DateTimeFormatter>.
|
||||||
|
</p>
|
||||||
|
<p>Thank you from the team at {data.bodyshops[0].shopname}</p>
|
||||||
|
</D>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import Header from "../components/header/header.component";
|
import Header from "../../components/header/header.component";
|
||||||
|
|
||||||
const D = styled.div`
|
const D = styled.div`
|
||||||
table {
|
table {
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { gql } from "apollo-boost";
|
import { gql } from "apollo-boost";
|
||||||
|
import { shopAttributes } from "../../components/fragments.queries";
|
||||||
|
|
||||||
export const REPORT_QUERY_PARTS_ORDER_BY_PK = gql`
|
export const REPORT_QUERY_PARTS_ORDER_BY_PK = gql`
|
||||||
query REPORT_QUERY_PARTS_ORDER_BY_PK($id: uuid!) {
|
query REPORT_QUERY_PARTS_ORDER_BY_PK($id: uuid!) {
|
||||||
@@ -29,17 +30,7 @@ export const REPORT_QUERY_PARTS_ORDER_BY_PK = gql`
|
|||||||
status
|
status
|
||||||
user_email
|
user_email
|
||||||
}
|
}
|
||||||
bodyshops(where: { associations: { active: { _eq: true } } }) {
|
...shopData
|
||||||
id
|
|
||||||
address1
|
|
||||||
address2
|
|
||||||
city
|
|
||||||
email
|
|
||||||
federal_tax_id
|
|
||||||
state
|
|
||||||
shopname
|
|
||||||
zip_post
|
|
||||||
logo_img_path
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
${shopAttributes}
|
||||||
`;
|
`;
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import DashboardGridComponent from "../../components/dashboard-grid/dashboard-grid.component";
|
import DashboardGridComponent from "../../components/dashboard-grid/dashboard-grid.component";
|
||||||
|
import Test from "../../components/_test/test.component";
|
||||||
export default function ManageRootPageComponent() {
|
export default function ManageRootPageComponent() {
|
||||||
//const client = useApolloClient();
|
//const client = useApolloClient();
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
<Test />
|
||||||
<DashboardGridComponent />
|
<DashboardGridComponent />
|
||||||
{
|
{
|
||||||
// <SendEmailButton
|
// <SendEmailButton
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ const emailReducer = (state = INITIAL_STATE, action) => {
|
|||||||
case EmailActionTypes.SET_EMAIL_OPTIONS:
|
case EmailActionTypes.SET_EMAIL_OPTIONS:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
emailConfig: { ...action.payload }
|
emailConfig: { ...action.payload },
|
||||||
|
visible: true
|
||||||
};
|
};
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
|
|||||||
Reference in New Issue
Block a user