feature/IO-3096-GlobalNotifications - Code Review Part 1
This commit is contained in:
@@ -21,7 +21,7 @@ import "./App.styles.scss";
|
|||||||
import Eula from "../components/eula/eula.component";
|
import Eula from "../components/eula/eula.component";
|
||||||
import InstanceRenderMgr from "../utils/instanceRenderMgr";
|
import InstanceRenderMgr from "../utils/instanceRenderMgr";
|
||||||
import ProductFruitsWrapper from "./ProductFruitsWrapper.jsx";
|
import ProductFruitsWrapper from "./ProductFruitsWrapper.jsx";
|
||||||
import { SocketProvider } from "../contexts/SocketIO/socketContext.jsx";
|
import { SocketProvider } from "../contexts/SocketIO/useSocket.jsx";
|
||||||
import { NotificationProvider } from "../contexts/Notifications/notificationContext.jsx";
|
import { NotificationProvider } from "../contexts/Notifications/notificationContext.jsx";
|
||||||
|
|
||||||
const ResetPassword = lazy(() => import("../pages/reset-password/reset-password.component"));
|
const ResetPassword = lazy(() => import("../pages/reset-password/reset-password.component"));
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { getToken } from "@firebase/messaging";
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useSocket } from "../../contexts/SocketIO/socketContext";
|
import { useSocket } from "../../contexts/SocketIO/useSocket.jsx";
|
||||||
import { messaging, requestForToken } from "../../firebase/firebase.utils";
|
import { messaging, requestForToken } from "../../firebase/firebase.utils";
|
||||||
import ChatPopupComponent from "../chat-popup/chat-popup.component";
|
import ChatPopupComponent from "../chat-popup/chat-popup.component";
|
||||||
import "./chat-affix.styles.scss";
|
import "./chat-affix.styles.scss";
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Button } from "antd";
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { TOGGLE_CONVERSATION_ARCHIVE } from "../../graphql/conversations.queries";
|
import { TOGGLE_CONVERSATION_ARCHIVE } from "../../graphql/conversations.queries";
|
||||||
import { useSocket } from "../../contexts/SocketIO/socketContext.jsx";
|
import { useSocket } from "../../contexts/SocketIO/useSocket.jsx";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors.js";
|
import { selectBodyshop } from "../../redux/user/user.selectors.js";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { Link } from "react-router-dom";
|
|||||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
import { REMOVE_CONVERSATION_TAG } from "../../graphql/job-conversations.queries";
|
import { REMOVE_CONVERSATION_TAG } from "../../graphql/job-conversations.queries";
|
||||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
import { useSocket } from "../../contexts/SocketIO/socketContext.jsx";
|
import { useSocket } from "../../contexts/SocketIO/useSocket.jsx";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors.js";
|
import { selectBodyshop } from "../../redux/user/user.selectors.js";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import axios from "axios";
|
|||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { useSocket } from "../../contexts/SocketIO/socketContext";
|
import { useSocket } from "../../contexts/SocketIO/useSocket.jsx";
|
||||||
import { CONVERSATION_SUBSCRIPTION_BY_PK, GET_CONVERSATION_DETAILS } from "../../graphql/conversations.queries";
|
import { CONVERSATION_SUBSCRIPTION_BY_PK, GET_CONVERSATION_DETAILS } from "../../graphql/conversations.queries";
|
||||||
import { selectSelectedConversation } from "../../redux/messaging/messaging.selectors";
|
import { selectSelectedConversation } from "../../redux/messaging/messaging.selectors";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { Input, Spin, Tag, Tooltip } from "antd";
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { UPDATE_CONVERSATION_LABEL } from "../../graphql/conversations.queries";
|
import { UPDATE_CONVERSATION_LABEL } from "../../graphql/conversations.queries";
|
||||||
import { useSocket } from "../../contexts/SocketIO/socketContext.jsx";
|
import { useSocket } from "../../contexts/SocketIO/useSocket.jsx";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors.js";
|
import { selectBodyshop } from "../../redux/user/user.selectors.js";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { connect } from "react-redux";
|
|||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { openChatByPhone } from "../../redux/messaging/messaging.actions";
|
import { openChatByPhone } from "../../redux/messaging/messaging.actions";
|
||||||
import PhoneFormItem, { PhoneItemFormatterValidation } from "../form-items-formatted/phone-form-item.component";
|
import PhoneFormItem, { PhoneItemFormatterValidation } from "../form-items-formatted/phone-form-item.component";
|
||||||
import { useSocket } from "../../contexts/SocketIO/socketContext.jsx";
|
import { useSocket } from "../../contexts/SocketIO/useSocket.jsx";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
//currentUser: selectCurrentUser
|
//currentUser: selectCurrentUser
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import PhoneNumberFormatter from "../../utils/PhoneFormatter";
|
|||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import { searchingForConversation } from "../../redux/messaging/messaging.selectors";
|
import { searchingForConversation } from "../../redux/messaging/messaging.selectors";
|
||||||
import { useSocket } from "../../contexts/SocketIO/socketContext.jsx";
|
import { useSocket } from "../../contexts/SocketIO/useSocket.jsx";
|
||||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import ChatConversationListComponent from "../chat-conversation-list/chat-conver
|
|||||||
import ChatConversationContainer from "../chat-conversation/chat-conversation.container";
|
import ChatConversationContainer from "../chat-conversation/chat-conversation.container";
|
||||||
import ChatNewConversation from "../chat-new-conversation/chat-new-conversation.component";
|
import ChatNewConversation from "../chat-new-conversation/chat-new-conversation.component";
|
||||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||||
import { useSocket } from "../../contexts/SocketIO/socketContext.jsx";
|
import { useSocket } from "../../contexts/SocketIO/useSocket.jsx";
|
||||||
|
|
||||||
import "./chat-popup.styles.scss";
|
import "./chat-popup.styles.scss";
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { logImEXEvent } from "../../firebase/firebase.utils";
|
|||||||
import { INSERT_CONVERSATION_TAG } from "../../graphql/job-conversations.queries";
|
import { INSERT_CONVERSATION_TAG } from "../../graphql/job-conversations.queries";
|
||||||
import { SEARCH_FOR_JOBS } from "../../graphql/jobs.queries";
|
import { SEARCH_FOR_JOBS } from "../../graphql/jobs.queries";
|
||||||
import ChatTagRo from "./chat-tag-ro.component";
|
import ChatTagRo from "./chat-tag-ro.component";
|
||||||
import { useSocket } from "../../contexts/SocketIO/socketContext.jsx";
|
import { useSocket } from "../../contexts/SocketIO/useSocket.jsx";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors.js";
|
import { selectBodyshop } from "../../redux/user/user.selectors.js";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { connect } from "react-redux";
|
|||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { useQuery } from "@apollo/client";
|
import { useQuery } from "@apollo/client";
|
||||||
import { useSocket } from "../../contexts/SocketIO/socketContext.jsx";
|
import { useSocket } from "../../contexts/SocketIO/useSocket.jsx";
|
||||||
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
||||||
import NotificationCenterContainer from "../notification-center/notification-center.container.jsx";
|
import NotificationCenterContainer from "../notification-center/notification-center.container.jsx";
|
||||||
import LockWrapper from "../lock-wrapper/lock-wrapper.component";
|
import LockWrapper from "../lock-wrapper/lock-wrapper.component";
|
||||||
@@ -704,7 +704,11 @@ function Header({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{scenarioNotificationsOn && (
|
{scenarioNotificationsOn && (
|
||||||
<NotificationCenterContainer visible={notificationVisible} onClose={() => setNotificationVisible(false)} />
|
<NotificationCenterContainer
|
||||||
|
visible={notificationVisible}
|
||||||
|
onClose={() => setNotificationVisible(false)}
|
||||||
|
unreadCount={unreadCount}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</Layout.Header>
|
</Layout.Header>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { Link, useLocation, useNavigate } from "react-router-dom";
|
import { Link, useLocation, useNavigate } from "react-router-dom";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { useSocket } from "../../contexts/SocketIO/socketContext.jsx";
|
import { useSocket } from "../../contexts/SocketIO/useSocket.jsx";
|
||||||
import { UPDATE_APPOINTMENT } from "../../graphql/appointments.queries";
|
import { UPDATE_APPOINTMENT } from "../../graphql/appointments.queries";
|
||||||
import { openChatByPhone, setMessage } from "../../redux/messaging/messaging.actions";
|
import { openChatByPhone, setMessage } from "../../redux/messaging/messaging.actions";
|
||||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { Link, useNavigate } from "react-router-dom";
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { useSocket } from "../../contexts/SocketIO/socketContext.jsx";
|
import { useSocket } from "../../contexts/SocketIO/useSocket.jsx";
|
||||||
import { auth, logImEXEvent } from "../../firebase/firebase.utils";
|
import { auth, logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
import { CANCEL_APPOINTMENTS_BY_JOB_ID, INSERT_MANUAL_APPT } from "../../graphql/appointments.queries";
|
import { CANCEL_APPOINTMENTS_BY_JOB_ID, INSERT_MANUAL_APPT } from "../../graphql/appointments.queries";
|
||||||
import { GET_CURRENT_QUESTIONSET_ID, INSERT_CSI } from "../../graphql/csi.queries";
|
import { GET_CURRENT_QUESTIONSET_ID, INSERT_CSI } from "../../graphql/csi.queries";
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ const NotificationCenterComponent = ({
|
|||||||
toggleUnreadOnly,
|
toggleUnreadOnly,
|
||||||
markAllRead,
|
markAllRead,
|
||||||
loadMore,
|
loadMore,
|
||||||
onNotificationClick
|
onNotificationClick,
|
||||||
|
unreadCount
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@@ -61,8 +62,6 @@ const NotificationCenterComponent = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const hasUnread = notifications.some((n) => !n.read);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`notification-center ${visible ? "visible" : ""}`}>
|
<div className={`notification-center ${visible ? "visible" : ""}`}>
|
||||||
<div className="notification-header">
|
<div className="notification-header">
|
||||||
@@ -82,9 +81,9 @@ const NotificationCenterComponent = ({
|
|||||||
<Tooltip title={t("notifications.labels.mark-all-read")}>
|
<Tooltip title={t("notifications.labels.mark-all-read")}>
|
||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
icon={hasUnread ? <CheckCircleFilled /> : <CheckCircleOutlined />}
|
icon={!unreadCount ? <CheckCircleFilled /> : <CheckCircleOutlined />}
|
||||||
onClick={markAllRead}
|
onClick={markAllRead}
|
||||||
disabled={!hasUnread}
|
disabled={!unreadCount}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { useQuery } from "@apollo/client";
|
|||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import NotificationCenterComponent from "./notification-center.component";
|
import NotificationCenterComponent from "./notification-center.component";
|
||||||
import { GET_NOTIFICATIONS } from "../../graphql/notifications.queries";
|
import { GET_NOTIFICATIONS } from "../../graphql/notifications.queries";
|
||||||
import { INITIAL_NOTIFICATIONS, useSocket } from "../../contexts/SocketIO/socketContext.jsx";
|
import { INITIAL_NOTIFICATIONS, useSocket } from "../../contexts/SocketIO/useSocket.jsx";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors.js";
|
import { selectBodyshop } from "../../redux/user/user.selectors.js";
|
||||||
import day from "../../utils/day.js";
|
import day from "../../utils/day.js";
|
||||||
@@ -11,7 +11,7 @@ import day from "../../utils/day.js";
|
|||||||
// This will be used to poll for notifications when the socket is disconnected
|
// This will be used to poll for notifications when the socket is disconnected
|
||||||
const NOTIFICATION_POLL_INTERVAL_SECONDS = 60;
|
const NOTIFICATION_POLL_INTERVAL_SECONDS = 60;
|
||||||
|
|
||||||
export function NotificationCenterContainer({ visible, onClose, bodyshop }) {
|
export function NotificationCenterContainer({ visible, onClose, bodyshop, unreadCount }) {
|
||||||
const [showUnreadOnly, setShowUnreadOnly] = useState(false);
|
const [showUnreadOnly, setShowUnreadOnly] = useState(false);
|
||||||
const [notifications, setNotifications] = useState([]);
|
const [notifications, setNotifications] = useState([]);
|
||||||
const [error, setError] = useState(null);
|
const [error, setError] = useState(null);
|
||||||
@@ -169,6 +169,7 @@ export function NotificationCenterContainer({ visible, onClose, bodyshop }) {
|
|||||||
markAllRead={handleMarkAllRead}
|
markAllRead={handleMarkAllRead}
|
||||||
loadMore={loadMore}
|
loadMore={loadMore}
|
||||||
onNotificationClick={handleNotificationClick}
|
onNotificationClick={handleNotificationClick}
|
||||||
|
unreadCount={unreadCount}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { createStructuredSelector } from "reselect";
|
|||||||
import { openChatByPhone, setMessage } from "../../redux/messaging/messaging.actions";
|
import { openChatByPhone, setMessage } from "../../redux/messaging/messaging.actions";
|
||||||
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
|
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
|
||||||
import CurrencyFormItemComponent from "../form-items-formatted/currency-form-item.component";
|
import CurrencyFormItemComponent from "../form-items-formatted/currency-form-item.component";
|
||||||
import { useSocket } from "../../contexts/SocketIO/socketContext.jsx";
|
import { useSocket } from "../../contexts/SocketIO/useSocket.jsx";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { QUERY_KANBAN_SETTINGS } from "../../graphql/user.queries";
|
|||||||
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
|
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
|
||||||
import ProductionBoardKanbanComponent from "./production-board-kanban.component";
|
import ProductionBoardKanbanComponent from "./production-board-kanban.component";
|
||||||
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
||||||
import { useSocket } from "../../contexts/SocketIO/socketContext.jsx";
|
import { useSocket } from "../../contexts/SocketIO/useSocket.jsx";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
import ProductionListTable from "./production-list-table.component";
|
import ProductionListTable from "./production-list-table.component";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
||||||
import { useSocket } from "../../contexts/SocketIO/socketContext.jsx";
|
import { useSocket } from "../../contexts/SocketIO/useSocket.jsx";
|
||||||
|
|
||||||
export default function ProductionListTableContainer({ bodyshop, subscriptionType = "direct" }) {
|
export default function ProductionListTableContainer({ bodyshop, subscriptionType = "direct" }) {
|
||||||
const client = useApolloClient();
|
const client = useApolloClient();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useMutation, useQuery } from "@apollo/client";
|
import { useMutation, useQuery } from "@apollo/client";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { Button, Card, Checkbox, Form, Table } from "antd";
|
import { Button, Card, Checkbox, Form, Space, Table } from "antd";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
@@ -165,14 +165,15 @@ function NotificationSettingsForm({ currentUser }) {
|
|||||||
<Card
|
<Card
|
||||||
title={t("notifications.labels.notificationscenarios")}
|
title={t("notifications.labels.notificationscenarios")}
|
||||||
extra={
|
extra={
|
||||||
<>
|
<Space>
|
||||||
<Button type="default" onClick={handleReset} disabled={!isDirty} style={{ marginRight: 8 }}>
|
<Button type="default" onClick={handleReset} disabled={!isDirty}>
|
||||||
{t("general.actions.clear")}
|
{t("general.actions.clear")}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button type="primary" htmlType="submit" disabled={!isDirty} loading={saving}>
|
<Button type="primary" htmlType="submit" disabled={!isDirty} loading={saving}>
|
||||||
{t("notifications.labels.save")}
|
{t("notifications.labels.save")}
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</Space>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Table dataSource={dataSource} columns={columns} pagination={false} bordered rowKey="key" />
|
<Table dataSource={dataSource} columns={columns} pagination={false} bordered rowKey="key" />
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { logImEXEvent, updateCurrentPassword } from "../../firebase/firebase.uti
|
|||||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||||
import NotificationSettingsForm from "./notification-settings.component.jsx";
|
import NotificationSettingsForm from "./notification-settings.component.jsx";
|
||||||
import { useSocket } from "../../contexts/SocketIO/socketContext.jsx";
|
import { useSocket } from "../../contexts/SocketIO/useSocket.jsx";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
currentUser: selectCurrentUser
|
currentUser: selectCurrentUser
|
||||||
|
|||||||
@@ -452,7 +452,9 @@ const SocketProvider = ({ children, bodyshop, navigate, currentUser, scenarioNot
|
|||||||
markNotificationRead,
|
markNotificationRead,
|
||||||
markAllNotificationsRead,
|
markAllNotificationsRead,
|
||||||
navigate,
|
navigate,
|
||||||
currentUser
|
currentUser,
|
||||||
|
scenarioNotificationsOn,
|
||||||
|
t
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -525,6 +525,7 @@ export const GET_JOB_BY_PK = gql`
|
|||||||
iouparent
|
iouparent
|
||||||
job_totals
|
job_totals
|
||||||
job_watchers {
|
job_watchers {
|
||||||
|
id
|
||||||
user_email
|
user_email
|
||||||
}
|
}
|
||||||
joblines(where: { removed: { _eq: false } }, order_by: { line_no: asc }) {
|
joblines(where: { removed: { _eq: false } }, order_by: { line_no: asc }) {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ export const GET_NOTIFICATIONS = gql`
|
|||||||
created_at
|
created_at
|
||||||
read
|
read
|
||||||
job {
|
job {
|
||||||
|
id
|
||||||
ro_number
|
ro_number
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { createStructuredSelector } from "reselect";
|
|||||||
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors.js";
|
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors.js";
|
||||||
import EmployeeSearchSelectComponent from "../../components/employee-search-select/employee-search-select.component.jsx";
|
import EmployeeSearchSelectComponent from "../../components/employee-search-select/employee-search-select.component.jsx";
|
||||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component.jsx";
|
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component.jsx";
|
||||||
|
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
||||||
|
|
||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
|
|
||||||
@@ -19,6 +20,14 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
|
|
||||||
const JobWatcherToggle = ({ job, currentUser, bodyshop }) => {
|
const JobWatcherToggle = ({ job, currentUser, bodyshop }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const {
|
||||||
|
treatments: { Enhanced_Payroll }
|
||||||
|
} = useSplitTreatments({
|
||||||
|
attributes: {},
|
||||||
|
names: ["Enhanced_Payroll"],
|
||||||
|
splitKey: bodyshop && bodyshop.imexshopid
|
||||||
|
});
|
||||||
|
|
||||||
const userEmail = currentUser.email;
|
const userEmail = currentUser.email;
|
||||||
const jobid = job.id;
|
const jobid = job.id;
|
||||||
|
|
||||||
@@ -146,7 +155,7 @@ const JobWatcherToggle = ({ job, currentUser, bodyshop }) => {
|
|||||||
/>
|
/>
|
||||||
{/* Divider for UI separation */}
|
{/* Divider for UI separation */}
|
||||||
{/* Only show team selection if there are available teams */}
|
{/* Only show team selection if there are available teams */}
|
||||||
{bodyshop?.employee_teams?.length > 0 && (
|
{Enhanced_Payroll && bodyshop?.employee_teams?.length > 0 && (
|
||||||
<>
|
<>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Text type="secondary">{t("notifications.labels.add-watchers-team")}</Text>
|
<Text type="secondary">{t("notifications.labels.add-watchers-team")}</Text>
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ import dayjs from "../../utils/day";
|
|||||||
import UndefinedToNull from "../../utils/undefinedtonull";
|
import UndefinedToNull from "../../utils/undefinedtonull";
|
||||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||||
import JobWatcherToggle from "./job-watcher-toggle.component.jsx";
|
import JobWatcherToggle from "./job-watcher-toggle.component.jsx";
|
||||||
import { useSocket } from "../../contexts/SocketIO/socketContext.jsx";
|
import { useSocket } from "../../contexts/SocketIO/useSocket.jsx";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import PartnerPingComponent from "../../components/partner-ping/partner-ping.com
|
|||||||
import PrintCenterModalContainer from "../../components/print-center-modal/print-center-modal.container";
|
import PrintCenterModalContainer from "../../components/print-center-modal/print-center-modal.container";
|
||||||
import ShopSubStatusComponent from "../../components/shop-sub-status/shop-sub-status.component";
|
import ShopSubStatusComponent from "../../components/shop-sub-status/shop-sub-status.component";
|
||||||
import { requestForToken } from "../../firebase/firebase.utils";
|
import { requestForToken } from "../../firebase/firebase.utils";
|
||||||
import { useSocket } from "../../contexts/SocketIO/socketContext.jsx";
|
import { useSocket } from "../../contexts/SocketIO/useSocket.jsx";
|
||||||
import { selectBodyshop, selectInstanceConflict } from "../../redux/user/user.selectors";
|
import { selectBodyshop, selectInstanceConflict } from "../../redux/user/user.selectors";
|
||||||
import UpdateAlert from "../../components/update-alert/update-alert.component";
|
import UpdateAlert from "../../components/update-alert/update-alert.component";
|
||||||
import InstanceRenderManager from "../../utils/instanceRenderMgr.js";
|
import InstanceRenderManager from "../../utils/instanceRenderMgr.js";
|
||||||
|
|||||||
@@ -69,11 +69,14 @@ const sendServerEmail = async ({ subject, text }) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
(err, info) => {
|
(err, info) => {
|
||||||
logger.log("server-email-failure", err ? "error" : "debug", null, null, { message: err?.message });
|
logger.log("server-email-failure", err ? "error" : "debug", null, null, {
|
||||||
|
message: err?.message,
|
||||||
|
stack: err?.stack
|
||||||
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log("server-email-failure", "error", null, null, { message: error?.message });
|
logger.log("server-email-failure", "error", null, null, { message: error?.message, stack: error?.stack });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -92,11 +95,11 @@ const sendTaskEmail = async ({ to, subject, type = "text", html, text, attachmen
|
|||||||
},
|
},
|
||||||
(err, info) => {
|
(err, info) => {
|
||||||
// (message, type, user, record, meta
|
// (message, type, user, record, meta
|
||||||
logger.log("server-email", err ? "error" : "debug", null, null, { message: err?.message });
|
logger.log("server-email", err ? "error" : "debug", null, null, { message: err?.message, stack: err?.stack });
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log("server-email-failure", "error", null, null, { message: error?.message });
|
logger.log("server-email-failure", "error", null, null, { message: error?.message, stack: error?.stack });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -125,7 +128,8 @@ const sendEmail = async (req, res) => {
|
|||||||
cc: req.body.cc,
|
cc: req.body.cc,
|
||||||
subject: req.body.subject,
|
subject: req.body.subject,
|
||||||
templateStrings: req.body.templateStrings,
|
templateStrings: req.body.templateStrings,
|
||||||
errorMessage: error?.message
|
errorMessage: error?.message,
|
||||||
|
errorStack: error?.stack
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -194,7 +198,8 @@ const sendEmail = async (req, res) => {
|
|||||||
cc: req.body.cc,
|
cc: req.body.cc,
|
||||||
subject: req.body.subject,
|
subject: req.body.subject,
|
||||||
templateStrings: req.body.templateStrings,
|
templateStrings: req.body.templateStrings,
|
||||||
errorMessage: err?.message
|
errorMessage: err?.message,
|
||||||
|
errorStack: err?.stack
|
||||||
});
|
});
|
||||||
logEmail(req, {
|
logEmail(req, {
|
||||||
to: req.body.to,
|
to: req.body.to,
|
||||||
@@ -202,7 +207,7 @@ const sendEmail = async (req, res) => {
|
|||||||
subject: req.body.subject,
|
subject: req.body.subject,
|
||||||
bodyshopid: req.body.bodyshopid
|
bodyshopid: req.body.bodyshopid
|
||||||
});
|
});
|
||||||
res.status(500).json({ success: false, errorMessage: err?.message });
|
res.status(500).json({ success: false, errorMessage: err?.message, stack: err?.stack });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -270,14 +275,16 @@ ${body.bounce?.bouncedRecipients.map(
|
|||||||
},
|
},
|
||||||
(err, info) => {
|
(err, info) => {
|
||||||
logger.log("sns-error", err ? "error" : "debug", "api", null, {
|
logger.log("sns-error", err ? "error" : "debug", "api", null, {
|
||||||
errorMessage: err?.message
|
errorMessage: err?.message,
|
||||||
|
errorStack: err?.stack
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log("sns-error", "ERROR", "api", null, {
|
logger.log("sns-error", "ERROR", "api", null, {
|
||||||
errorMessage: error?.message
|
errorMessage: error?.message,
|
||||||
|
errorStack: error?.stack
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
res.sendStatus(200);
|
res.sendStatus(200);
|
||||||
|
|||||||
@@ -2708,16 +2708,14 @@ exports.INSERT_AUDIT_TRAIL = `
|
|||||||
|
|
||||||
exports.GET_JOB_WATCHERS = `
|
exports.GET_JOB_WATCHERS = `
|
||||||
query GET_JOB_WATCHERS($jobid: uuid!) {
|
query GET_JOB_WATCHERS($jobid: uuid!) {
|
||||||
job_watchers_aggregate(where: { jobid: { _eq: $jobid } }) {
|
job_watchers(where: { jobid: { _eq: $jobid } }) {
|
||||||
nodes {
|
user_email
|
||||||
user_email
|
user {
|
||||||
user {
|
authid
|
||||||
authid
|
employee {
|
||||||
employee {
|
id
|
||||||
id
|
first_name
|
||||||
first_name
|
last_name
|
||||||
last_name
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ async function processNotificationEvent(req, res, parserPath, successMessage) {
|
|||||||
|
|
||||||
// Call scenarioParser but don't await it; log any error that occurs.
|
// Call scenarioParser but don't await it; log any error that occurs.
|
||||||
scenarioParser(req, parserPath).catch((error) => {
|
scenarioParser(req, parserPath).catch((error) => {
|
||||||
logger.log("notifications-error", "error", "notifications", null, { error: error?.message });
|
logger.log("notifications-error", "error", "notifications", null, { message: error?.message, stack: error?.stack });
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.status(200).json({ message: successMessage });
|
return res.status(200).json({ message: successMessage });
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ const loadAppQueue = async ({ pubClient, logger, redisHelpers, ioRedis }) => {
|
|||||||
|
|
||||||
await pubClient.del(`app:consolidate:${jobId}`);
|
await pubClient.del(`app:consolidate:${jobId}`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.log(`Consolidation error for jobId ${jobId}`, "ERROR", "notifications", "api", {
|
logger.log(`app-queue-consolidation-error`, "ERROR", "notifications", "api", {
|
||||||
message: err?.message,
|
message: err?.message,
|
||||||
stack: err?.stack
|
stack: err?.stack
|
||||||
});
|
});
|
||||||
@@ -237,13 +237,13 @@ const loadAppQueue = async ({ pubClient, logger, redisHelpers, ioRedis }) => {
|
|||||||
addWorker.on("completed", (job) => logger.logger.debug(`Add job ${job.id} completed`));
|
addWorker.on("completed", (job) => logger.logger.debug(`Add job ${job.id} completed`));
|
||||||
consolidateWorker.on("completed", (job) => logger.logger.debug(`Consolidate job ${job.id} completed`));
|
consolidateWorker.on("completed", (job) => logger.logger.debug(`Consolidate job ${job.id} completed`));
|
||||||
addWorker.on("failed", (job, err) =>
|
addWorker.on("failed", (job, err) =>
|
||||||
logger.log(`Add job ${job.id} failed:`, "ERROR", "notifications", "api", {
|
logger.log(`app-queue-notification-error`, "ERROR", "notifications", "api", {
|
||||||
message: err?.message,
|
message: err?.message,
|
||||||
stack: err?.stack
|
stack: err?.stack
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
consolidateWorker.on("failed", (job, err) =>
|
consolidateWorker.on("failed", (job, err) =>
|
||||||
logger.log(`Consolidate job ${job.id} failed:`, "ERROR", "notifications", "api", {
|
logger.log(`app-queue-consolidation-failed:`, "ERROR", "notifications", "api", {
|
||||||
message: err?.message,
|
message: err?.message,
|
||||||
stack: err?.stack
|
stack: err?.stack
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ const loadEmailQueue = async ({ pubClient, logger }) => {
|
|||||||
await pubClient.del(recipientsSet);
|
await pubClient.del(recipientsSet);
|
||||||
await pubClient.del(`email:consolidate:${jobId}`);
|
await pubClient.del(`email:consolidate:${jobId}`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.log(`Email Consolidation error for jobId ${jobId}`, "ERROR", "notifications", "api", {
|
logger.log(`email-queue-consolidation-error`, "ERROR", "notifications", "api", {
|
||||||
message: err?.message,
|
message: err?.message,
|
||||||
stack: err?.stack
|
stack: err?.stack
|
||||||
});
|
});
|
||||||
@@ -170,13 +170,13 @@ const loadEmailQueue = async ({ pubClient, logger }) => {
|
|||||||
emailAddWorker.on("completed", (job) => logger.logger.debug(`Email add job ${job.id} completed`));
|
emailAddWorker.on("completed", (job) => logger.logger.debug(`Email add job ${job.id} completed`));
|
||||||
emailConsolidateWorker.on("completed", (job) => logger.logger.debug(`Email consolidate job ${job.id} completed`));
|
emailConsolidateWorker.on("completed", (job) => logger.logger.debug(`Email consolidate job ${job.id} completed`));
|
||||||
emailAddWorker.on("failed", (job, err) =>
|
emailAddWorker.on("failed", (job, err) =>
|
||||||
logger.log(`Email add job ${job.id} failed`, "ERROR", "notifications", "api", {
|
logger.log(`add-email-queue-failed`, "ERROR", "notifications", "api", {
|
||||||
message: err?.message,
|
message: err?.message,
|
||||||
stack: err?.stack
|
stack: err?.stack
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
emailConsolidateWorker.on("failed", (job, err) =>
|
emailConsolidateWorker.on("failed", (job, err) =>
|
||||||
logger.log(`Email consolidate job ${job.id} failed:`, "ERROR", "notifications", "api", {
|
logger.log(`email-consolidation-job-failed`, "ERROR", "notifications", "api", {
|
||||||
message: err?.message,
|
message: err?.message,
|
||||||
stack: err?.stack
|
stack: err?.stack
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -24,8 +24,9 @@ const populateWatchers = (data, result) => {
|
|||||||
/**
|
/**
|
||||||
* Builds notification data for changes to alternate transport.
|
* Builds notification data for changes to alternate transport.
|
||||||
*/
|
*/
|
||||||
|
// Verified
|
||||||
const alternateTransportChangedBuilder = (data) => {
|
const alternateTransportChangedBuilder = (data) => {
|
||||||
const body = `The alternate transport status has been updated from ${data?.changedFields?.altTransport?.old}.`;
|
const body = `The Alternate Transport status has been updated to ${data?.data?.alt_transport}.`;
|
||||||
const result = {
|
const result = {
|
||||||
app: {
|
app: {
|
||||||
jobId: data.jobId,
|
jobId: data.jobId,
|
||||||
@@ -56,8 +57,12 @@ const alternateTransportChangedBuilder = (data) => {
|
|||||||
/**
|
/**
|
||||||
* Builds notification data for bill posted events.
|
* Builds notification data for bill posted events.
|
||||||
*/
|
*/
|
||||||
|
//verified
|
||||||
const billPostedHandler = (data) => {
|
const billPostedHandler = (data) => {
|
||||||
const body = `A bill of $${data.data.clm_total} has been posted.`;
|
const facing = data?.data?.isinhouse ? "In-House" : "External";
|
||||||
|
|
||||||
|
const body = `An ${facing} Bill has been posted${data?.data?.is_credit_memo ? " (Credit Memo)" : ""}.`.trim();
|
||||||
|
|
||||||
const result = {
|
const result = {
|
||||||
app: {
|
app: {
|
||||||
jobId: data.jobId,
|
jobId: data.jobId,
|
||||||
@@ -66,7 +71,8 @@ const billPostedHandler = (data) => {
|
|||||||
key: "notifications.job.billPosted",
|
key: "notifications.job.billPosted",
|
||||||
body,
|
body,
|
||||||
variables: {
|
variables: {
|
||||||
clmTotal: data.data.clm_total
|
facing,
|
||||||
|
is_credit_memo: data?.data?.is_credit_memo
|
||||||
},
|
},
|
||||||
recipients: []
|
recipients: []
|
||||||
},
|
},
|
||||||
@@ -87,6 +93,7 @@ const billPostedHandler = (data) => {
|
|||||||
/**
|
/**
|
||||||
* Builds notification data for changes to critical parts status.
|
* Builds notification data for changes to critical parts status.
|
||||||
*/
|
*/
|
||||||
|
// TODO: Needs change
|
||||||
const criticalPartsStatusChangedBuilder = (data) => {
|
const criticalPartsStatusChangedBuilder = (data) => {
|
||||||
const body = `The critical parts status has changed to ${data.data.queued_for_parts ? "queued" : "not queued"}.`;
|
const body = `The critical parts status has changed to ${data.data.queued_for_parts ? "queued" : "not queued"}.`;
|
||||||
const result = {
|
const result = {
|
||||||
@@ -119,8 +126,9 @@ const criticalPartsStatusChangedBuilder = (data) => {
|
|||||||
/**
|
/**
|
||||||
* Builds notification data for completed intake or delivery checklists.
|
* Builds notification data for completed intake or delivery checklists.
|
||||||
*/
|
*/
|
||||||
|
// Verified
|
||||||
const intakeDeliveryChecklistCompletedBuilder = (data) => {
|
const intakeDeliveryChecklistCompletedBuilder = (data) => {
|
||||||
const checklistType = data.changedFields.intakechecklist ? "intake" : "delivery";
|
const checklistType = data?.changedFields?.intakechecklist ? "Intake" : "Delivery";
|
||||||
const body = `The ${checklistType.charAt(0).toUpperCase() + checklistType.slice(1)} checklist has been completed.`;
|
const body = `The ${checklistType.charAt(0).toUpperCase() + checklistType.slice(1)} checklist has been completed.`;
|
||||||
const result = {
|
const result = {
|
||||||
app: {
|
app: {
|
||||||
@@ -152,6 +160,7 @@ const intakeDeliveryChecklistCompletedBuilder = (data) => {
|
|||||||
/**
|
/**
|
||||||
* Builds notification data for job assignment events.
|
* Builds notification data for job assignment events.
|
||||||
*/
|
*/
|
||||||
|
// Verified
|
||||||
const jobAssignedToMeBuilder = (data) => {
|
const jobAssignedToMeBuilder = (data) => {
|
||||||
const body = `You have been assigned to ${getJobAssignmentType(data.scenarioFields?.[0])}`;
|
const body = `You have been assigned to ${getJobAssignmentType(data.scenarioFields?.[0])}`;
|
||||||
const result = {
|
const result = {
|
||||||
@@ -183,8 +192,9 @@ const jobAssignedToMeBuilder = (data) => {
|
|||||||
/**
|
/**
|
||||||
* Builds notification data for jobs added to production.
|
* Builds notification data for jobs added to production.
|
||||||
*/
|
*/
|
||||||
|
// Verified
|
||||||
const jobsAddedToProductionBuilder = (data) => {
|
const jobsAddedToProductionBuilder = (data) => {
|
||||||
const body = `Job has been added to production.`;
|
const body = `Has been added to Production.`;
|
||||||
const result = {
|
const result = {
|
||||||
app: {
|
app: {
|
||||||
jobId: data.jobId,
|
jobId: data.jobId,
|
||||||
@@ -212,6 +222,7 @@ const jobsAddedToProductionBuilder = (data) => {
|
|||||||
/**
|
/**
|
||||||
* Builds notification data for job status changes.
|
* Builds notification data for job status changes.
|
||||||
*/
|
*/
|
||||||
|
// Verified
|
||||||
const jobStatusChangeBuilder = (data) => {
|
const jobStatusChangeBuilder = (data) => {
|
||||||
const body = `The status has changed from ${data.changedFields.status.old} to ${data.changedFields.status.new}`;
|
const body = `The status has changed from ${data.changedFields.status.old} to ${data.changedFields.status.new}`;
|
||||||
const result = {
|
const result = {
|
||||||
@@ -244,8 +255,15 @@ const jobStatusChangeBuilder = (data) => {
|
|||||||
/**
|
/**
|
||||||
* Builds notification data for new media added or reassigned events.
|
* Builds notification data for new media added or reassigned events.
|
||||||
*/
|
*/
|
||||||
|
// Verified
|
||||||
const newMediaAddedReassignedBuilder = (data) => {
|
const newMediaAddedReassignedBuilder = (data) => {
|
||||||
const body = `New media has been added.`;
|
// Determine if it's an image or document
|
||||||
|
const mediaType = data?.data?.type?.startsWith("image") ? "Image" : "Document";
|
||||||
|
// Determine if it's added or updated
|
||||||
|
const action = data.isNew ? "added" : "updated";
|
||||||
|
// Construct the body string
|
||||||
|
const body = `An ${mediaType} has been ${action}.`;
|
||||||
|
|
||||||
const result = {
|
const result = {
|
||||||
app: {
|
app: {
|
||||||
jobId: data.jobId,
|
jobId: data.jobId,
|
||||||
@@ -253,7 +271,10 @@ const newMediaAddedReassignedBuilder = (data) => {
|
|||||||
bodyShopId: data.bodyShopId,
|
bodyShopId: data.bodyShopId,
|
||||||
key: "notifications.job.newMediaAdded",
|
key: "notifications.job.newMediaAdded",
|
||||||
body,
|
body,
|
||||||
variables: {},
|
variables: {
|
||||||
|
mediaType,
|
||||||
|
action
|
||||||
|
},
|
||||||
recipients: []
|
recipients: []
|
||||||
},
|
},
|
||||||
email: {
|
email: {
|
||||||
@@ -274,7 +295,7 @@ const newMediaAddedReassignedBuilder = (data) => {
|
|||||||
* Builds notification data for new notes added to a job.
|
* Builds notification data for new notes added to a job.
|
||||||
*/
|
*/
|
||||||
const newNoteAddedBuilder = (data) => {
|
const newNoteAddedBuilder = (data) => {
|
||||||
const body = `A new note has been added: "${data.data.text}"`;
|
const body = `An Note has been added: "${data.data.text}"`;
|
||||||
const result = {
|
const result = {
|
||||||
app: {
|
app: {
|
||||||
jobId: data.jobId,
|
jobId: data.jobId,
|
||||||
@@ -305,7 +326,10 @@ const newNoteAddedBuilder = (data) => {
|
|||||||
* Builds notification data for new time tickets posted.
|
* Builds notification data for new time tickets posted.
|
||||||
*/
|
*/
|
||||||
const newTimeTicketPostedBuilder = (data) => {
|
const newTimeTicketPostedBuilder = (data) => {
|
||||||
const body = `A new time ticket has been posted.`;
|
consoleDir(data);
|
||||||
|
const type = data?.data?.cost_center;
|
||||||
|
const body = `An ${type} time ticket has been posted${data?.data?.flat_rate ? " (Flat Rate)" : ""}.`.trim();
|
||||||
|
|
||||||
const result = {
|
const result = {
|
||||||
app: {
|
app: {
|
||||||
jobId: data.jobId,
|
jobId: data.jobId,
|
||||||
@@ -313,7 +337,9 @@ const newTimeTicketPostedBuilder = (data) => {
|
|||||||
bodyShopId: data.bodyShopId,
|
bodyShopId: data.bodyShopId,
|
||||||
key: "notifications.job.newTimeTicketPosted",
|
key: "notifications.job.newTimeTicketPosted",
|
||||||
body,
|
body,
|
||||||
variables: {},
|
variables: {
|
||||||
|
type
|
||||||
|
},
|
||||||
recipients: []
|
recipients: []
|
||||||
},
|
},
|
||||||
email: {
|
email: {
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ const notificationScenarios = [
|
|||||||
{
|
{
|
||||||
key: "job-assigned-to-me",
|
key: "job-assigned-to-me",
|
||||||
table: "jobs",
|
table: "jobs",
|
||||||
fields: ["employee_pre", "employee_body", "employee_csr", "employee_refinish"],
|
fields: ["employee_prep", "employee_body", "employee_csr", "employee_refinish"],
|
||||||
matchToUserFields: ["employee_pre", "employee_body", "employee_csr", "employee_refinish"],
|
matchToUserFields: ["employee_prep", "employee_body", "employee_csr", "employee_refinish"],
|
||||||
builder: jobAssignedToMeBuilder
|
builder: jobAssignedToMeBuilder
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -88,19 +88,17 @@ const notificationScenarios = [
|
|||||||
// Good test for batching as this will hit multiple scenarios
|
// Good test for batching as this will hit multiple scenarios
|
||||||
key: "intake-delivery-checklist-completed",
|
key: "intake-delivery-checklist-completed",
|
||||||
table: "jobs",
|
table: "jobs",
|
||||||
fields: ["intakechecklist"],
|
fields: ["intakechecklist", "deliverchecklist"],
|
||||||
builder: intakeDeliveryChecklistCompletedBuilder
|
builder: intakeDeliveryChecklistCompletedBuilder
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "payment-collected-completed",
|
key: "payment-added",
|
||||||
table: "payments",
|
table: "payments",
|
||||||
onNew: true,
|
onNew: true,
|
||||||
builder: paymentCollectedCompletedBuilder
|
builder: paymentCollectedCompletedBuilder
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// MAKE SURE YOU ARE NOT ON A LMS ENVIRONMENT
|
// MAKE SURE YOU ARE NOT ON A LMS ENVIRONMENT
|
||||||
// Potential Callbacks / Save for last
|
|
||||||
// Not question mark for Non LMS Scenario
|
|
||||||
key: "new-media-added-reassigned",
|
key: "new-media-added-reassigned",
|
||||||
table: "documents",
|
table: "documents",
|
||||||
fields: ["jobid"],
|
fields: ["jobid"],
|
||||||
@@ -11,7 +11,7 @@ const eventParser = require("./eventParser");
|
|||||||
const { client: gqlClient } = require("../graphql-client/graphql-client");
|
const { client: gqlClient } = require("../graphql-client/graphql-client");
|
||||||
const queries = require("../graphql-client/queries");
|
const queries = require("../graphql-client/queries");
|
||||||
const { isEmpty, isFunction } = require("lodash");
|
const { isEmpty, isFunction } = require("lodash");
|
||||||
const { getMatchingScenarios } = require("./scenarioMapperr");
|
const { getMatchingScenarios } = require("./scenarioMapper");
|
||||||
const { dispatchEmailsToQueue } = require("./queues/emailQueue");
|
const { dispatchEmailsToQueue } = require("./queues/emailQueue");
|
||||||
const { dispatchAppsToQueue } = require("./queues/appQueue");
|
const { dispatchAppsToQueue } = require("./queues/appQueue");
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ const scenarioParser = async (req, jobIdField) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Transform watcher data into a simplified format with email and employee details
|
// Transform watcher data into a simplified format with email and employee details
|
||||||
let jobWatchers = watcherData?.job_watchers_aggregate?.nodes?.map((watcher) => ({
|
let jobWatchers = watcherData?.job_watchers?.map((watcher) => ({
|
||||||
email: watcher.user_email,
|
email: watcher.user_email,
|
||||||
firstName: watcher?.user?.employee?.first_name,
|
firstName: watcher?.user?.employee?.first_name,
|
||||||
lastName: watcher?.user?.employee?.last_name,
|
lastName: watcher?.user?.employee?.last_name,
|
||||||
|
|||||||
Reference in New Issue
Block a user