diff --git a/client/src/components/phone-number-consent/phone-number-consent.component.jsx b/client/src/components/phone-number-consent/phone-number-consent.component.jsx
index 0df53ca30..c0872997d 100644
--- a/client/src/components/phone-number-consent/phone-number-consent.component.jsx
+++ b/client/src/components/phone-number-consent/phone-number-consent.component.jsx
@@ -1,14 +1,17 @@
import { useQuery } from "@apollo/client";
-import { Input, Table } from "antd";
+import { Input, Space, Table, Typography } from "antd";
+import { Link } from "react-router-dom";
import { useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
import { GET_PHONE_NUMBER_OPT_OUTS, SEARCH_OWNERS_BY_PHONE_NUMBERS } from "../../graphql/phone-number-opt-out.queries";
-
import PhoneNumberFormatter from "../../utils/PhoneFormatter";
import { TimeAgoFormatter } from "../../utils/DateFormatter";
+import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
+
+const { Paragraph } = Typography; // Destructure Paragraph from Typography
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -44,18 +47,6 @@ function PhoneNumberConsentList({ bodyshop, currentUser }) {
fetchPolicy: "network-only"
});
- // Format owner names for display
- const formatOwnerName = (owner) => {
- 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/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 dca4f62ef..143bb14df 100644
--- a/client/src/translations/en_us/common.json
+++ b/client/src/translations/en_us/common.json
@@ -3875,7 +3875,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 cfc349043..1ff5d7fc9 100644
--- a/client/src/translations/es/common.json
+++ b/client/src/translations/es/common.json
@@ -3877,7 +3877,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 0e49be0e1..6c2b0b171 100644
--- a/client/src/translations/fr/common.json
+++ b/client/src/translations/fr/common.json
@@ -3877,7 +3877,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/server/sms/receive.js b/server/sms/receive.js
index 514d375b4..864531f36 100644
--- a/server/sms/receive.js
+++ b/server/sms/receive.js
@@ -12,6 +12,11 @@ const { phone } = require("phone");
const { admin } = require("../firebase/firebase-handler");
const InstanceManager = require("../utils/instanceMgr").default;
+/ TWILLIO KEYWORDS;
+// 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 +63,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, {