+
{bodyshop.shopname || ""}
{`${bodyshop.address1 || ""}`}
{`${bodyshop.address2 || ""}`}
@@ -93,13 +96,15 @@ export default function CsiContainerPage() {
{t("csi.labels.title")}
{`Hi ${job.ownr_fn || ""}!`}
- At {bodyshop.shopname || ""}, we value your feedback. We would love to
- hear what you have to say. Please fill out the form below.
+ {`At ${
+ bodyshop.shopname || ""
+ }, we value your feedback. We would love to
+ hear what you have to say. Please fill out the form below.`}
{submitting.error ? (
-
+
) : null}
{submitting.submitted ? (
@@ -109,9 +114,10 @@ export default function CsiContainerPage() {
margin: "2em 4em",
padding: "2em",
overflowY: "auto",
- }}>
+ }}
+ >
@@ -123,13 +129,15 @@ export default function CsiContainerPage() {
margin: "2em 4em",
padding: "2em",
overflowY: "auto",
- }}>
+ }}
+ >
@@ -137,7 +145,7 @@ export default function CsiContainerPage() {
)}
- Copyright ImEX.Online. Survey ID: {surveyId}
+ {`Copyright ImEX.Online. Survey ID: ${surveyId}`}
);
diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json
index 0226308ce..409e56fed 100644
--- a/client/src/translations/en_us/common.json
+++ b/client/src/translations/en_us/common.json
@@ -23,6 +23,7 @@
"intake": "Intake",
"new": "New Appointment",
"reschedule": "Reschedule",
+ "smartscheduling": "SMART Scheduling",
"viewjob": "View Job"
},
"errors": {
@@ -30,11 +31,13 @@
"saving": "Error scheduling appointment. {{message}}"
},
"fields": {
+ "time": "Appointment Time",
"title": "Title"
},
"labels": {
"arrivedon": "Arrived on: ",
"cancelledappointment": "Canceled appointment for: ",
+ "history": "History",
"nodateselected": "No date has been selected.",
"priorappointments": "Previous Appointments",
"scheduledfor": "Scheduled appointment for: "
@@ -76,6 +79,7 @@
"fields": {
"address1": "Address 1",
"address2": "Address 2",
+ "appt_length": "Default Appointment Length",
"city": "City",
"country": "Country",
"email": "General Shop Email",
diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json
index 8ad37cc7d..f7e648178 100644
--- a/client/src/translations/es/common.json
+++ b/client/src/translations/es/common.json
@@ -23,6 +23,7 @@
"intake": "Consumo",
"new": "Nueva cita",
"reschedule": "Reprogramar",
+ "smartscheduling": "",
"viewjob": "Ver trabajo"
},
"errors": {
@@ -30,11 +31,13 @@
"saving": "Error al programar la cita. {{message}}"
},
"fields": {
+ "time": "",
"title": "Título"
},
"labels": {
"arrivedon": "Llegado el:",
"cancelledappointment": "Cita cancelada para:",
+ "history": "",
"nodateselected": "No se ha seleccionado ninguna fecha.",
"priorappointments": "Nombramientos previos",
"scheduledfor": "Cita programada para:"
@@ -76,6 +79,7 @@
"fields": {
"address1": "",
"address2": "",
+ "appt_length": "",
"city": "",
"country": "",
"email": "",
diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json
index b5f824dab..e64dc2d5c 100644
--- a/client/src/translations/fr/common.json
+++ b/client/src/translations/fr/common.json
@@ -23,6 +23,7 @@
"intake": "Admission",
"new": "Nouveau rendez-vous",
"reschedule": "Replanifier",
+ "smartscheduling": "",
"viewjob": "Voir le travail"
},
"errors": {
@@ -30,11 +31,13 @@
"saving": "Erreur lors de la planification du rendez-vous. {{message}}"
},
"fields": {
+ "time": "",
"title": "Titre"
},
"labels": {
"arrivedon": "Arrivé le:",
"cancelledappointment": "Rendez-vous annulé pour:",
+ "history": "",
"nodateselected": "Aucune date n'a été sélectionnée.",
"priorappointments": "Rendez-vous précédents",
"scheduledfor": "Rendez-vous prévu pour:"
@@ -76,6 +79,7 @@
"fields": {
"address1": "",
"address2": "",
+ "appt_length": "",
"city": "",
"country": "",
"email": "",
diff --git a/client/src/utils/TemplateConstants.js b/client/src/utils/TemplateConstants.js
index 0bc5aa69c..449895334 100644
--- a/client/src/utils/TemplateConstants.js
+++ b/client/src/utils/TemplateConstants.js
@@ -10,6 +10,13 @@ export const TemplateList = {
drivingId: "Appointment Id",
key: "appointment_reminder",
},
+ appointment_confirmation: {
+ title: "Appointment Confirmation",
+ description:
+ "Sent to a customer as a Confirmation of an upcoming appointment.",
+ drivingId: "Appointment Id",
+ key: "appointment_confirmation",
+ },
parts_order_confirmation: {
title: "Parts Order Confirmation",
description: "Parts order template including part details",
diff --git a/client/templates/appointment_confirmation/appointment_confirmation.query.gql b/client/templates/appointment_confirmation/appointment_confirmation.query.gql
new file mode 100644
index 000000000..6e1c4f5a9
--- /dev/null
+++ b/client/templates/appointment_confirmation/appointment_confirmation.query.gql
@@ -0,0 +1,11 @@
+query EMAIL_APPOINTMENT_CONFIRMATION($id: uuid!) {
+ appointments_by_pk(id: $id) {
+ start
+ title
+ job {
+ ownr_fn
+ ownr_ln
+ ownr_ea
+ }
+ }
+}
diff --git a/client/templates/appointment_confirmation/appointment_confirmation.template.html b/client/templates/appointment_confirmation/appointment_confirmation.template.html
new file mode 100644
index 000000000..5aa9669c7
--- /dev/null
+++ b/client/templates/appointment_confirmation/appointment_confirmation.template.html
@@ -0,0 +1,9 @@
+
+
Hello {{appointments_by_pk.job.ownr_fn}},
+
+ This is a confirmation that you have an appointment at
+ {{appointments_by_pk.start}} to bring your car in for repair. Please email
+ us at {{bodyshop.email}} if you can't make it.
+
+
+
\ No newline at end of file
diff --git a/hasura/migrations/1591214568316_alter_table_public_bodyshops_add_column_appt_length/down.yaml b/hasura/migrations/1591214568316_alter_table_public_bodyshops_add_column_appt_length/down.yaml
new file mode 100644
index 000000000..4f0ee9f3c
--- /dev/null
+++ b/hasura/migrations/1591214568316_alter_table_public_bodyshops_add_column_appt_length/down.yaml
@@ -0,0 +1,5 @@
+- args:
+ cascade: false
+ read_only: false
+ sql: ALTER TABLE "public"."bodyshops" DROP COLUMN "appt_length";
+ type: run_sql
diff --git a/hasura/migrations/1591214568316_alter_table_public_bodyshops_add_column_appt_length/up.yaml b/hasura/migrations/1591214568316_alter_table_public_bodyshops_add_column_appt_length/up.yaml
new file mode 100644
index 000000000..4becf570d
--- /dev/null
+++ b/hasura/migrations/1591214568316_alter_table_public_bodyshops_add_column_appt_length/up.yaml
@@ -0,0 +1,6 @@
+- args:
+ cascade: false
+ read_only: false
+ sql: ALTER TABLE "public"."bodyshops" ADD COLUMN "appt_length" integer NOT NULL
+ DEFAULT 60;
+ type: run_sql
diff --git a/hasura/migrations/1591214578485_update_permission_user_public_table_bodyshops/down.yaml b/hasura/migrations/1591214578485_update_permission_user_public_table_bodyshops/down.yaml
new file mode 100644
index 000000000..c7c8f849d
--- /dev/null
+++ b/hasura/migrations/1591214578485_update_permission_user_public_table_bodyshops/down.yaml
@@ -0,0 +1,51 @@
+- args:
+ role: user
+ table:
+ name: bodyshops
+ schema: public
+ type: drop_select_permission
+- args:
+ permission:
+ allow_aggregations: false
+ columns:
+ - accountingconfig
+ - address1
+ - address2
+ - city
+ - country
+ - created_at
+ - email
+ - federal_tax_id
+ - id
+ - inhousevendorid
+ - insurance_vendor_id
+ - intakechecklist
+ - invoice_tax_rates
+ - logo_img_path
+ - md_order_statuses
+ - md_responsibility_centers
+ - md_ro_statuses
+ - messagingservicesid
+ - production_config
+ - region_config
+ - shopname
+ - shoprates
+ - state
+ - state_tax_id
+ - template_header
+ - textid
+ - updated_at
+ - zip_post
+ computed_fields: []
+ filter:
+ associations:
+ bodyshop:
+ associations:
+ user:
+ authid:
+ _eq: X-Hasura-User-Id
+ role: user
+ table:
+ name: bodyshops
+ schema: public
+ type: create_select_permission
diff --git a/hasura/migrations/1591214578485_update_permission_user_public_table_bodyshops/up.yaml b/hasura/migrations/1591214578485_update_permission_user_public_table_bodyshops/up.yaml
new file mode 100644
index 000000000..26ce89aa9
--- /dev/null
+++ b/hasura/migrations/1591214578485_update_permission_user_public_table_bodyshops/up.yaml
@@ -0,0 +1,52 @@
+- args:
+ role: user
+ table:
+ name: bodyshops
+ schema: public
+ type: drop_select_permission
+- args:
+ permission:
+ allow_aggregations: false
+ columns:
+ - accountingconfig
+ - address1
+ - address2
+ - appt_length
+ - city
+ - country
+ - created_at
+ - email
+ - federal_tax_id
+ - id
+ - inhousevendorid
+ - insurance_vendor_id
+ - intakechecklist
+ - invoice_tax_rates
+ - logo_img_path
+ - md_order_statuses
+ - md_responsibility_centers
+ - md_ro_statuses
+ - messagingservicesid
+ - production_config
+ - region_config
+ - shopname
+ - shoprates
+ - state
+ - state_tax_id
+ - template_header
+ - textid
+ - updated_at
+ - zip_post
+ computed_fields: []
+ filter:
+ associations:
+ bodyshop:
+ associations:
+ user:
+ authid:
+ _eq: X-Hasura-User-Id
+ role: user
+ table:
+ name: bodyshops
+ schema: public
+ type: create_select_permission
diff --git a/hasura/migrations/1591214587491_update_permission_user_public_table_bodyshops/down.yaml b/hasura/migrations/1591214587491_update_permission_user_public_table_bodyshops/down.yaml
new file mode 100644
index 000000000..86c1ba881
--- /dev/null
+++ b/hasura/migrations/1591214587491_update_permission_user_public_table_bodyshops/down.yaml
@@ -0,0 +1,49 @@
+- args:
+ role: user
+ table:
+ name: bodyshops
+ schema: public
+ type: drop_update_permission
+- args:
+ permission:
+ columns:
+ - accountingconfig
+ - address1
+ - address2
+ - city
+ - country
+ - created_at
+ - email
+ - federal_tax_id
+ - id
+ - inhousevendorid
+ - insurance_vendor_id
+ - intakechecklist
+ - invoice_tax_rates
+ - logo_img_path
+ - md_order_statuses
+ - md_responsibility_centers
+ - md_ro_statuses
+ - production_config
+ - shopname
+ - shoprates
+ - state
+ - state_tax_id
+ - updated_at
+ - zip_post
+ filter:
+ associations:
+ bodyshop:
+ associations:
+ user:
+ authid:
+ _eq: X-Hasura-User-Id
+ localPresets:
+ - key: ""
+ value: ""
+ set: {}
+ role: user
+ table:
+ name: bodyshops
+ schema: public
+ type: create_update_permission
diff --git a/hasura/migrations/1591214587491_update_permission_user_public_table_bodyshops/up.yaml b/hasura/migrations/1591214587491_update_permission_user_public_table_bodyshops/up.yaml
new file mode 100644
index 000000000..9c3945d54
--- /dev/null
+++ b/hasura/migrations/1591214587491_update_permission_user_public_table_bodyshops/up.yaml
@@ -0,0 +1,50 @@
+- args:
+ role: user
+ table:
+ name: bodyshops
+ schema: public
+ type: drop_update_permission
+- args:
+ permission:
+ columns:
+ - accountingconfig
+ - address1
+ - address2
+ - appt_length
+ - city
+ - country
+ - created_at
+ - email
+ - federal_tax_id
+ - id
+ - inhousevendorid
+ - insurance_vendor_id
+ - intakechecklist
+ - invoice_tax_rates
+ - logo_img_path
+ - md_order_statuses
+ - md_responsibility_centers
+ - md_ro_statuses
+ - production_config
+ - shopname
+ - shoprates
+ - state
+ - state_tax_id
+ - updated_at
+ - zip_post
+ filter:
+ associations:
+ bodyshop:
+ associations:
+ user:
+ authid:
+ _eq: X-Hasura-User-Id
+ localPresets:
+ - key: ""
+ value: ""
+ set: {}
+ role: user
+ table:
+ name: bodyshops
+ schema: public
+ type: create_update_permission
diff --git a/hasura/migrations/metadata.yaml b/hasura/migrations/metadata.yaml
index 8df2ef107..1b83cbd37 100644
--- a/hasura/migrations/metadata.yaml
+++ b/hasura/migrations/metadata.yaml
@@ -447,6 +447,7 @@ tables:
- accountingconfig
- address1
- address2
+ - appt_length
- city
- country
- created_at
@@ -486,6 +487,7 @@ tables:
- accountingconfig
- address1
- address2
+ - appt_length
- city
- country
- created_at
diff --git a/package.json b/package.json
index ea3c85777..2e5a2af80 100644
--- a/package.json
+++ b/package.json
@@ -27,6 +27,8 @@
"firebase-admin": "^8.11.0",
"graphql-request": "^1.8.2",
"handlebars": "^4.7.6",
+ "lodash": "^4.17.15",
+ "moment": "^2.26.0",
"nodemailer": "^6.4.4",
"phone": "^2.4.8",
"twilio": "^3.41.1",
diff --git a/server/render/renderHandlebars.js b/server/render/renderHandlebars.js
index fbe6c52e9..32bc16c77 100644
--- a/server/render/renderHandlebars.js
+++ b/server/render/renderHandlebars.js
@@ -1,13 +1,73 @@
const path = require("path");
+const moment = require("moment");
require("dotenv").config({
path: path.resolve(
process.cwd(),
`.env.${process.env.NODE_ENV || "development"}`
),
});
-
+var _ = require("lodash");
const Handlebars = require("handlebars");
+Handlebars.registerHelper("moment", function (context, block) {
+ if (context && context.hash) {
+ block = _.cloneDeep(context);
+ context = undefined;
+ }
+ var date = moment(context);
+
+ if (block.hash.timezone) {
+ date.tz(block.hash.timezone);
+ }
+
+ var hasFormat = false;
+
+ // Reset the language back to default before doing anything else
+ date.locale("en");
+
+ for (var i in block.hash) {
+ if (i === "format") {
+ hasFormat = true;
+ } else if (date[i]) {
+ date = date[i](block.hash[i]);
+ } else {
+ console.log('moment.js does not support "' + i + '"');
+ }
+ }
+
+ if (hasFormat) {
+ date = date.format(block.hash.format);
+ }
+ return date;
+});
+
+Handlebars.registerHelper("duration", function (context, block) {
+ if (context && context.hash) {
+ block = _.cloneDeep(context);
+ context = 0;
+ }
+ var duration = moment.duration(context);
+ var hasFormat = false;
+
+ // Reset the language back to default before doing anything else
+ duration = duration.lang("en");
+
+ for (var i in block.hash) {
+ if (i === "format") {
+ hasFormat = true;
+ } else if (duration[i]) {
+ duration = duration[i](block.hash[i]);
+ } else {
+ console.log('moment.js duration does not support "' + i + '"');
+ }
+ }
+
+ if (hasFormat) {
+ duration = duration.format(block.hash.format);
+ }
+ return duration;
+});
+
exports.render = (req, res) => {
//Perform request validation
let view;
diff --git a/yarn.lock b/yarn.lock
index d9fb779b4..50c539069 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1992,6 +1992,11 @@ mkdirp@^0.5.1:
dependencies:
minimist "0.0.8"
+moment@^2.26.0:
+ version "2.26.0"
+ resolved "https://registry.yarnpkg.com/moment/-/moment-2.26.0.tgz#5e1f82c6bafca6e83e808b30c8705eed0dcbd39a"
+ integrity sha512-oIixUO+OamkUkwjhAVE18rAMfRJNsNe/Stid/gwHSOfHrOtw9EhAY2AHvdKZ/k/MggcYELFCJz/Sn2pL8b8JMw==
+
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"