diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index 8969c93eb..399953905 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -12791,27 +12791,6 @@ - - allow_text_message - false - - - - - - en-US - false - - - es-MX - false - - - fr-CA - false - - - checklist false @@ -42614,27 +42593,6 @@ - - allow_text_message - false - - - - - - en-US - false - - - es-MX - false - - - fr-CA - false - - - name false diff --git a/client/src/components/job-checklist/components/job-checklist-form/job-checklist-form.component.jsx b/client/src/components/job-checklist/components/job-checklist-form/job-checklist-form.component.jsx index 18f5d025e..eca3147dc 100644 --- a/client/src/components/job-checklist/components/job-checklist-form/job-checklist-form.component.jsx +++ b/client/src/components/job-checklist/components/job-checklist-form/job-checklist-form.component.jsx @@ -129,24 +129,6 @@ export function JobChecklistForm({ insertAuditTrail, formItems, bodyshop, curren } } - if (type === "intake" && job.owner && job.owner.id) { - //Updae Owner Allow to Text - const updateOwnerResult = await updateOwner({ - variables: { - ownerId: job.owner.id, - owner: { allow_text_message: values.allow_text_message } - } - }); - - if (!!updateOwnerResult.errors) { - notification["error"]({ - message: t("checklist.errors.complete", { - error: JSON.stringify(result.errors) - }) - }); - } - } - setLoading(false); if (!!!result.errors) { @@ -189,7 +171,6 @@ export function JobChecklistForm({ insertAuditTrail, formItems, bodyshop, curren initialValues={{ ...(type === "intake" && { addToProduction: true, - allow_text_message: job.owner && job.owner.allow_text_message, scheduled_completion: (job && job.scheduled_completion && dayjs(job.scheduled_completion)) || (job && @@ -228,14 +209,6 @@ export function JobChecklistForm({ insertAuditTrail, formItems, bodyshop, curren > - - - - - - ); diff --git a/client/src/components/owner-detail-form/owner-detail-form.component.jsx b/client/src/components/owner-detail-form/owner-detail-form.component.jsx index 5de4231f7..a71cbc836 100644 --- a/client/src/components/owner-detail-form/owner-detail-form.component.jsx +++ b/client/src/components/owner-detail-form/owner-detail-form.component.jsx @@ -1,4 +1,4 @@ -import { Form, Input, Switch } from "antd"; +import { Form, Input } from "antd"; import React from "react"; import { useTranslation } from "react-i18next"; import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component"; @@ -26,7 +26,7 @@ export default function OwnerDetailFormComponent({ form, loading }) { - + @@ -50,9 +50,6 @@ export default function OwnerDetailFormComponent({ form, loading }) { - - - { - const parts = []; - if (owner.ownr_fn || owner.ownr_ln) { - parts.push([owner.ownr_fn, owner.ownr_ln].filter(Boolean).join(" ")); - } - if (owner.ownr_co_nm) { - parts.push(owner.ownr_co_nm); - } - return parts.join(", ") || "-"; - }; - // Map phone numbers to their associated owners and identify phone field const getAssociatedOwners = (phoneNumber) => { if (!ownersData?.owners) return []; @@ -102,15 +93,20 @@ function PhoneNumberConsentList({ bodyshop, currentUser }) { } return owners.map((owner) => (
- {formatOwnerName(owner)} ({owner.phoneField}) + + + + + ({owner.phoneField}) +
)); }, sorter: (a, b) => { const aOwners = getAssociatedOwners(a.phone_number); const bOwners = getAssociatedOwners(b.phone_number); - const aName = aOwners[0] ? formatOwnerName(aOwners[0]) : ""; - const bName = bOwners[0] ? formatOwnerName(bOwners[0]) : ""; + const aName = aOwners[0] ? `${aOwners[0].ownr_fn} ${aOwners[0].ownr_ln}` : ""; + const bName = bOwners[0] ? `${bOwners[0].ownr_fn} ${bOwners[0].ownr_ln}` : ""; return aName.localeCompare(bName); } }, @@ -124,6 +120,7 @@ function PhoneNumberConsentList({ bodyshop, currentUser }) { return (
+ {t("consent.text_body")} setSearch(value)} diff --git a/client/src/graphql/bodyshop.queries.js b/client/src/graphql/bodyshop.queries.js index 7faff13a2..73e222c01 100644 --- a/client/src/graphql/bodyshop.queries.js +++ b/client/src/graphql/bodyshop.queries.js @@ -312,7 +312,6 @@ export const QUERY_INTAKE_CHECKLIST = gql` intakechecklist status owner { - allow_text_message id } labhrs: joblines_aggregate(where: { _and: [{ mod_lbr_ty: { _neq: "LAR" } }, { removed: { _eq: false } }] }) { diff --git a/client/src/graphql/jobs.queries.js b/client/src/graphql/jobs.queries.js index 5150b7a9f..68c8adfbe 100644 --- a/client/src/graphql/jobs.queries.js +++ b/client/src/graphql/jobs.queries.js @@ -874,7 +874,6 @@ export const QUERY_JOB_CARD_DETAILS = gql` } owner { id - allow_text_message preferred_contact tax_number } @@ -2071,7 +2070,6 @@ export const QUERY_JOB_CHECKLISTS = gql` production_vars owner { id - allow_text_message } bodyshop { id @@ -2428,7 +2426,6 @@ export const QUERY_PARTS_QUEUE_CARD_DETAILS = gql` ownr_ph2 owner { id - allow_text_message preferred_contact tax_number } diff --git a/client/src/graphql/owners.queries.js b/client/src/graphql/owners.queries.js index d169263f4..de1b654b7 100644 --- a/client/src/graphql/owners.queries.js +++ b/client/src/graphql/owners.queries.js @@ -49,7 +49,6 @@ export const QUERY_OWNER_BY_ID = gql` owners_by_pk(id: $id) { id accountingid - allow_text_message ownr_addr1 ownr_addr2 ownr_co_nm @@ -104,7 +103,6 @@ export const QUERY_ALL_OWNERS = gql` query QUERY_ALL_OWNERS { owners { id - allow_text_message created_at ownr_addr1 ownr_addr2 @@ -129,7 +127,6 @@ export const QUERY_ALL_OWNERS_PAGINATED = gql` query QUERY_ALL_OWNERS_PAGINATED($search: String, $offset: Int, $limit: Int, $order: [owners_order_by!]!) { search_owners(args: { search: $search }, offset: $offset, limit: $limit, order_by: $order) { id - allow_text_message created_at ownr_addr1 ownr_addr2 diff --git a/client/src/pages/jobs-create/jobs-create.container.jsx b/client/src/pages/jobs-create/jobs-create.container.jsx index b12cd7823..0ed5c9d70 100644 --- a/client/src/pages/jobs-create/jobs-create.container.jsx +++ b/client/src/pages/jobs-create/jobs-create.container.jsx @@ -114,7 +114,6 @@ function JobsCreateContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) { if (!!!job.ownerid) { ownerData = job.owner.data; ownerData.shopid = bodyshop.id; - delete ownerData.allow_text_message; delete ownerData.preferred_contact; delete job.ownerid; } else { diff --git a/client/src/pages/shop/shop.page.component.jsx b/client/src/pages/shop/shop.page.component.jsx index b6ded16f6..f26f06d5a 100644 --- a/client/src/pages/shop/shop.page.component.jsx +++ b/client/src/pages/shop/shop.page.component.jsx @@ -92,13 +92,15 @@ export function ShopPage({ bodyshop, setSelectedHeader, setBreadcrumbs }) { }); } - // Add Consent Settings tab - items.push({ - key: "consent", - label: t("bodyshop.labels.consent_settings"), - children: - }); - + if (bodyshop.messagingservicesid) { + // Add Consent Settings tab + items.push({ + key: "consent", + label: t("bodyshop.labels.consent_settings"), + children: + }); + } + return ( history({ search: `?tab=${key}` })} items={items} /> diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index 52d6c1c00..fd3dd5134 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -775,7 +775,6 @@ }, "labels": { "addtoproduction": "Add Job to Production?", - "allow_text_message": "Permission to Text?", "checklist": "Checklist", "printpack": "Job Intake Print Pack", "removefromproduction": "Remove Job from Production?" @@ -2524,7 +2523,6 @@ "fields": { "accountingid": "Accounting ID", "address": "Address", - "allow_text_message": "Permission to Text?", "name": "Name", "note": "Owner Note", "ownr_addr1": "Address", @@ -3876,7 +3874,8 @@ "created_at": "Opt-Out Date", "no_owners": "No Associated Owners", "phone_1": "Phone 1", - "phone_2": "Phone 2" + "phone_2": "Phone 2", + "text_body": "Users can opt out of receiving SMS messages by replying with keywords such as STOP, UNSUBSCRIBE, CANCEL, END, QUIT, STOPALL, REVOKE and OPTOUT. To opt back in, users can reply with START, YES, or UNSTOP. Even after opting out, users can still send messages to us, which will be received and processed as needed. Ensure customers are informed to reply with these keywords to manage their messaging preferences. After opting out, users receive a confirmation message and will not receive further messages until they opt back in." }, "settings": { "title": "Phone Number Opt-Out List" diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index b01353c1b..bf3817291 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -775,7 +775,6 @@ }, "labels": { "addtoproduction": "", - "allow_text_message": "", "checklist": "", "printpack": "", "removefromproduction": "" @@ -2526,7 +2525,6 @@ "fields": { "accountingid": "", "address": "Dirección", - "allow_text_message": "Permiso de texto?", "name": "Nombre", "note": "", "ownr_addr1": "Dirección", @@ -3878,7 +3876,8 @@ "created_at": "", "no_owners": "", "phone_1": "", - "phone_2": "" + "phone_2": "", + "text_body": "" }, "settings": { "title": "" diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index e77bd39c8..8a4092e1a 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -775,7 +775,6 @@ }, "labels": { "addtoproduction": "", - "allow_text_message": "", "checklist": "", "printpack": "", "removefromproduction": "" @@ -2526,7 +2525,6 @@ "fields": { "accountingid": "", "address": "Adresse", - "allow_text_message": "Autorisation de texte?", "name": "Prénom", "note": "", "ownr_addr1": "Adresse", @@ -3878,7 +3876,8 @@ "created_at": "Opt-Out Date", "no_owners": "No Associated Owners", "phone_1": "Phone 1", - "phone_2": "Phone 2" + "phone_2": "Phone 2", + "text_body": "" }, "settings": { "title": "" diff --git a/new_bodyshop_translations.babel b/new_bodyshop_translations.babel index 5409f6ce5..e92daf2e6 100644 --- a/new_bodyshop_translations.babel +++ b/new_bodyshop_translations.babel @@ -10028,25 +10028,6 @@ - - allow_text_message - - - - - en-US - false - - - es-ES - false - - - fr-CA - false - - - checklist @@ -33000,25 +32981,6 @@ - - allow_text_message - - - - - en-US - false - - - es-ES - false - - - fr-CA - false - - - name diff --git a/server/sms/receive.js b/server/sms/receive.js index 514d375b4..a9670b76a 100644 --- a/server/sms/receive.js +++ b/server/sms/receive.js @@ -12,6 +12,10 @@ const { phone } = require("phone"); const { admin } = require("../firebase/firebase-handler"); const InstanceManager = require("../utils/instanceMgr").default; +// Note: When we handle different languages, we might need to adjust these keywords accordingly. +const optInKeywords = ["START", "YES", "UNSTOP"]; +const optOutKeywords = ["STOP", "STOPALL", "UNSUBSCRIBE", "CANCEL", "END", "QUIT", "REVOKE", "OPTOUT"]; + /** * Receive SMS messages from Twilio and process them * @param req @@ -58,9 +62,6 @@ const receive = async (req, res) => { const messageText = (req.body.Body || "").trim().toUpperCase(); // Step 2: Check for opt-in or opt-out keywords - const optInKeywords = ["START", "YES", "UNSTOP"]; - const optOutKeywords = ["STOP", "STOPALL", "UNSUBSCRIBE", "CANCEL", "END", "QUIT"]; - if (optInKeywords.includes(messageText) || optOutKeywords.includes(messageText)) { // Check if the phone number is in phone_number_opt_out const optOutCheck = await client.request(CHECK_PHONE_NUMBER_OPT_OUT, {