diff --git a/client/src/components/profile-my/notification-settings.component.jsx b/client/src/components/profile-my/notification-settings.component.jsx
index 054092025..659b951a7 100644
--- a/client/src/components/profile-my/notification-settings.component.jsx
+++ b/client/src/components/profile-my/notification-settings.component.jsx
@@ -11,22 +11,12 @@ import { QUERY_NOTIFICATION_SETTINGS, UPDATE_NOTIFICATION_SETTINGS } from "../..
import { notificationScenarios } from "../../utils/jobNotificationScenarios.js";
import LoadingSpinner from "../loading-spinner/loading-spinner.component.jsx";
-/**
- * ColumnHeaderCheckbox
- *
- * A header checkbox for a given channel that toggles the state for all scenarios.
- *
- * Props:
- * - channel: The notification channel (e.g. "app", "email", "fcm").
- * - form: The Ant Design form instance.
- * - disabled: (Optional) If true, the checkbox will be disabled.
- */
-const ColumnHeaderCheckbox = ({ channel, form, disabled = false }) => {
+const ColumnHeaderCheckbox = ({ channel, form, disabled = false, onHeaderChange }) => {
const { t } = useTranslation();
- // Watch the entire form values so that this component re-renders on changes.
+ // Subscribe to all form values so that this component re-renders on changes.
const formValues = Form.useWatch([], form) || {};
- // Use the known scenarios list to decide if every row has this channel enabled.
+ // Determine if all scenarios for this channel are checked.
const allChecked =
notificationScenarios.length > 0 && notificationScenarios.every((scenario) => formValues[scenario]?.[channel]);
@@ -39,7 +29,12 @@ const ColumnHeaderCheckbox = ({ channel, form, disabled = false }) => {
notificationScenarios.forEach((scenario) => {
newValues[scenario] = { ...newValues[scenario], [channel]: checked };
});
+ // Update form values.
form.setFieldsValue(newValues);
+ // Manually mark the form as dirty.
+ if (onHeaderChange) {
+ onHeaderChange();
+ }
};
return (
@@ -55,7 +50,7 @@ function NotificationSettingsForm({ currentUser }) {
const [initialValues, setInitialValues] = useState({});
const [isDirty, setIsDirty] = useState(false);
- // Fetch notification settings
+ // Fetch notification settings.
const { loading, error, data } = useQuery(QUERY_NOTIFICATION_SETTINGS, {
fetchPolicy: "network-only",
nextFetchPolicy: "network-only",
@@ -65,12 +60,11 @@ function NotificationSettingsForm({ currentUser }) {
const [updateNotificationSettings, { loading: saving }] = useMutation(UPDATE_NOTIFICATION_SETTINGS);
- // Populate form with fetched data
+ // Populate form with fetched data.
useEffect(() => {
if (data?.associations?.length > 0) {
const settings = data.associations[0].notification_settings || {};
- // For each scenario, expect an object with keys { app, email, fcm }.
- // If not present in the fetched data, default to all false.
+ // Ensure each scenario has an object with { app, email, fcm }.
const formattedValues = notificationScenarios.reduce((acc, scenario) => {
acc[scenario] = settings[scenario] ?? { app: false, email: false, fcm: false };
return acc;
@@ -78,20 +72,21 @@ function NotificationSettingsForm({ currentUser }) {
setInitialValues(formattedValues);
form.setFieldsValue(formattedValues);
- setIsDirty(false); // Reset dirty state when new data loads
+ setIsDirty(false); // Reset dirty state when new data loads.
}
}, [data, form]);
const handleSave = async (values) => {
if (data?.associations?.length > 0) {
const userId = data.associations[0].id;
- // `values` now contains, for each scenario, an object with keys { app, email, fcm }
+ // Save the updated notification settings.
await updateNotificationSettings({ variables: { id: userId, ns: values } });
setInitialValues(values);
setIsDirty(false);
}
};
+ // Mark the form as dirty on any manual change.
const handleFormChange = () => {
setIsDirty(true);
};
@@ -113,10 +108,10 @@ function NotificationSettingsForm({ currentUser }) {
width: "90%"
},
{
- title: ,
+ title: setIsDirty(true)} />,
dataIndex: "app",
key: "app",
- align: "center", // Center the cell content
+ align: "center",
render: (_, record) => (
@@ -124,10 +119,10 @@ function NotificationSettingsForm({ currentUser }) {
)
},
{
- title: ,
+ title: setIsDirty(true)} />,
dataIndex: "email",
key: "email",
- align: "center", // Center the cell content
+ align: "center",
render: (_, record) => (
@@ -135,10 +130,10 @@ function NotificationSettingsForm({ currentUser }) {
)
},
{
- title: ,
+ title: setIsDirty(true)} />,
dataIndex: "fcm",
key: "fcm",
- align: "center", // Center the cell content
+ align: "center",
render: (_, record) => (
@@ -147,7 +142,6 @@ function NotificationSettingsForm({ currentUser }) {
}
];
- // Create dataSource from the list of scenarios.
const dataSource = notificationScenarios.map((scenario) => ({ key: scenario }));
return (
@@ -178,7 +172,6 @@ function NotificationSettingsForm({ currentUser }) {
);
}
-// Redux connection
const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser
});
diff --git a/client/src/components/profile-my/profile-my.component.jsx b/client/src/components/profile-my/profile-my.component.jsx
index 24f26c6f7..0a8624360 100644
--- a/client/src/components/profile-my/profile-my.component.jsx
+++ b/client/src/components/profile-my/profile-my.component.jsx
@@ -1,6 +1,5 @@
import { Button, Card, Col, Form, Input } from "antd";
import { LockOutlined } from "@ant-design/icons";
-import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
@@ -47,8 +46,6 @@ export default connect(
}
};
- const handleScenarios = async ({ values }) => {};
-
return (
<>
diff --git a/server/graphql-client/queries.js b/server/graphql-client/queries.js
index 0dc6fd03a..ddb1ba429 100644
--- a/server/graphql-client/queries.js
+++ b/server/graphql-client/queries.js
@@ -2706,6 +2706,8 @@ query GET_JOB_WATCHERS($jobid: uuid!) {
}
job: jobs_by_pk(id: $jobid) {
id,
+ ro_number
+ clm_no
bodyshop {
id
shopname
diff --git a/server/notifications/scenarioBuilders/jobStatusChangeBuilder.js b/server/notifications/scenarioBuilders/jobStatusChangeBuilder.js
new file mode 100644
index 000000000..10a7404e5
--- /dev/null
+++ b/server/notifications/scenarioBuilders/jobStatusChangeBuilder.js
@@ -0,0 +1,6 @@
+const consoleDir = require("../../utils/consoleDir");
+const jobStatusChangeBuilder = (data) => {
+ consoleDir(data);
+};
+
+module.exports = jobStatusChangeBuilder;
diff --git a/server/notifications/utils/scenarioMapperr.js b/server/notifications/utils/scenarioMapperr.js
index 38eb24b44..caca96341 100644
--- a/server/notifications/utils/scenarioMapperr.js
+++ b/server/notifications/utils/scenarioMapperr.js
@@ -5,15 +5,25 @@
// Builder: function to handle the scenario
const tasksUpdatedCreatedBuilder = require("../scenarioBuilders/tasksUpdatedCreatedBuilder");
+const jobStatusChangeBuilder = require("../scenarioBuilders/jobStatusChangeBuilder");
+const jobAssignedToMeBuilder = require("../scenarioBuilders/jobAssignedToMeBuilder");
const notificationScenarios = [
{
key: "job-assigned-to-me",
table: "jobs",
fields: ["employee_pre", "employee_body", "employee_csr", "employee_refinish"],
- matchEmployee: true
+ matchEmployee: true,
+ builder: jobAssignedToMeBuilder
+ },
+ {
+ key: "bill-posted",
+ table: "bills"
+ },
+ {
+ key: "new-note-added",
+ table: "notes",
+ onNew: true
},
- { key: "bill-posted", table: "bills" },
- { key: "new-note-added", table: "notes", onNew: true },
{
key: "schedule-dates-changed",
table: "jobs",
@@ -26,16 +36,22 @@ const notificationScenarios = [
// onNew: true,
builder: tasksUpdatedCreatedBuilder
},
+ {
+ key: "job-status-change",
+ table: "jobs",
+ fields: ["status"],
+ builder: jobStatusChangeBuilder
+ },
{ key: "job-added-to-production", table: "jobs", fields: ["introduction"] },
- { key: "job-status-change", table: "jobs", fields: ["status"] },
{ key: "alternate-transport-changed", table: "jobs", fields: ["alt_transport"] },
- { key: "payment-collected-completed" },
- { key: "new-media-added-reassigned" },
- { key: "new-time-ticket-posted" },
- { key: "intake-delivery-checklist-completed" },
+ { key: "payment-collected-completed", table: "payments", onNew: true },
+ // MAKE SURE YOU ARE NOT ON A LMS ENVIRONMENT
+ { key: "new-media-added-reassigned", table: "documents" },
+ { key: "new-time-ticket-posted", table: "timetickets" },
+ { key: "intake-delivery-checklist-completed", table: "jobs", fields: ["intakechecklist"] },
{ key: "supplement-imported" },
- { key: "critical-parts-status-changed" },
- { key: "part-marked-back-ordered" }
+ { key: "critical-parts-status-changed", table: "joblines" },
+ { key: "part-marked-back-ordered", table: "joblines" }
];
/**