diff --git a/client/src/App/App.jsx b/client/src/App/App.jsx index 1cf4a8a06..1b26476ff 100644 --- a/client/src/App/App.jsx +++ b/client/src/App/App.jsx @@ -21,8 +21,8 @@ import "./App.styles.scss"; import Eula from "../components/eula/eula.component"; import InstanceRenderMgr from "../utils/instanceRenderMgr"; import ProductFruitsWrapper from "./ProductFruitsWrapper.jsx"; -import { SocketProvider } from "../contexts/SocketIO/useSocket.jsx"; import { NotificationProvider } from "../contexts/Notifications/notificationContext.jsx"; +import SocketProvider from "../contexts/SocketIO/socketProvider.jsx"; const ResetPassword = lazy(() => import("../pages/reset-password/reset-password.component")); const ManagePage = lazy(() => import("../pages/manage/manage.page.container")); diff --git a/client/src/components/chat-affix/chat-affix.container.jsx b/client/src/components/chat-affix/chat-affix.container.jsx index c757598c6..9885b8551 100644 --- a/client/src/components/chat-affix/chat-affix.container.jsx +++ b/client/src/components/chat-affix/chat-affix.container.jsx @@ -3,11 +3,11 @@ import { getToken } from "@firebase/messaging"; import axios from "axios"; import { useEffect } from "react"; import { useTranslation } from "react-i18next"; -import { useSocket } from "../../contexts/SocketIO/useSocket.jsx"; import { messaging, requestForToken } from "../../firebase/firebase.utils"; import ChatPopupComponent from "../chat-popup/chat-popup.component"; import "./chat-affix.styles.scss"; import { registerMessagingHandlers, unregisterMessagingHandlers } from "./registerMessagingSocketHandlers"; +import { useSocket } from "../../contexts/SocketIO/useSocket.js"; export function ChatAffixContainer({ bodyshop, chatVisible }) { const { t } = useTranslation(); diff --git a/client/src/components/chat-archive-button/chat-archive-button.component.jsx b/client/src/components/chat-archive-button/chat-archive-button.component.jsx index 24eb9cea4..5b055c3a6 100644 --- a/client/src/components/chat-archive-button/chat-archive-button.component.jsx +++ b/client/src/components/chat-archive-button/chat-archive-button.component.jsx @@ -3,10 +3,10 @@ import { Button } from "antd"; import { useState } from "react"; import { useTranslation } from "react-i18next"; import { TOGGLE_CONVERSATION_ARCHIVE } from "../../graphql/conversations.queries"; -import { useSocket } from "../../contexts/SocketIO/useSocket.jsx"; import { createStructuredSelector } from "reselect"; import { selectBodyshop } from "../../redux/user/user.selectors.js"; import { connect } from "react-redux"; +import { useSocket } from "../../contexts/SocketIO/useSocket.js"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop diff --git a/client/src/components/chat-conversation-title-tags/chat-conversation-title-tags.component.jsx b/client/src/components/chat-conversation-title-tags/chat-conversation-title-tags.component.jsx index e85ed6270..32ca5cad0 100644 --- a/client/src/components/chat-conversation-title-tags/chat-conversation-title-tags.component.jsx +++ b/client/src/components/chat-conversation-title-tags/chat-conversation-title-tags.component.jsx @@ -4,10 +4,10 @@ import { Link } from "react-router-dom"; import { logImEXEvent } from "../../firebase/firebase.utils"; import { REMOVE_CONVERSATION_TAG } from "../../graphql/job-conversations.queries"; import OwnerNameDisplay from "../owner-name-display/owner-name-display.component"; -import { useSocket } from "../../contexts/SocketIO/useSocket.jsx"; import { createStructuredSelector } from "reselect"; import { selectBodyshop } from "../../redux/user/user.selectors.js"; import { connect } from "react-redux"; +import { useSocket } from "../../contexts/SocketIO/useSocket.js"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop diff --git a/client/src/components/chat-conversation/chat-conversation.container.jsx b/client/src/components/chat-conversation/chat-conversation.container.jsx index 853c4851f..f951aabd1 100644 --- a/client/src/components/chat-conversation/chat-conversation.container.jsx +++ b/client/src/components/chat-conversation/chat-conversation.container.jsx @@ -3,11 +3,11 @@ import axios from "axios"; import { useCallback, useEffect, useState } from "react"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; -import { useSocket } from "../../contexts/SocketIO/useSocket.jsx"; import { CONVERSATION_SUBSCRIPTION_BY_PK, GET_CONVERSATION_DETAILS } from "../../graphql/conversations.queries"; import { selectSelectedConversation } from "../../redux/messaging/messaging.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors"; import ChatConversationComponent from "./chat-conversation.component"; +import { useSocket } from "../../contexts/SocketIO/useSocket.js"; const mapStateToProps = createStructuredSelector({ selectedConversation: selectSelectedConversation, diff --git a/client/src/components/chat-label/chat-label.component.jsx b/client/src/components/chat-label/chat-label.component.jsx index 6fccd1390..1152acf29 100644 --- a/client/src/components/chat-label/chat-label.component.jsx +++ b/client/src/components/chat-label/chat-label.component.jsx @@ -4,11 +4,11 @@ import { Input, Spin, Tag, Tooltip } from "antd"; import { useState } from "react"; import { useTranslation } from "react-i18next"; import { UPDATE_CONVERSATION_LABEL } from "../../graphql/conversations.queries"; -import { useSocket } from "../../contexts/SocketIO/useSocket.jsx"; import { createStructuredSelector } from "reselect"; import { selectBodyshop } from "../../redux/user/user.selectors.js"; import { connect } from "react-redux"; import { useNotification } from "../../contexts/Notifications/notificationContext.jsx"; +import { useSocket } from "../../contexts/SocketIO/useSocket.js"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop diff --git a/client/src/components/chat-new-conversation/chat-new-conversation.component.jsx b/client/src/components/chat-new-conversation/chat-new-conversation.component.jsx index 8806974bf..c3fd81a68 100644 --- a/client/src/components/chat-new-conversation/chat-new-conversation.component.jsx +++ b/client/src/components/chat-new-conversation/chat-new-conversation.component.jsx @@ -5,7 +5,7 @@ import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { openChatByPhone } from "../../redux/messaging/messaging.actions"; import PhoneFormItem, { PhoneItemFormatterValidation } from "../form-items-formatted/phone-form-item.component"; -import { useSocket } from "../../contexts/SocketIO/useSocket.jsx"; +import { useSocket } from "../../contexts/SocketIO/useSocket.js"; const mapStateToProps = createStructuredSelector({ //currentUser: selectCurrentUser diff --git a/client/src/components/chat-open-button/chat-open-button.component.jsx b/client/src/components/chat-open-button/chat-open-button.component.jsx index 68b9cd8b2..76db997cd 100644 --- a/client/src/components/chat-open-button/chat-open-button.component.jsx +++ b/client/src/components/chat-open-button/chat-open-button.component.jsx @@ -7,7 +7,7 @@ import PhoneNumberFormatter from "../../utils/PhoneFormatter"; import { createStructuredSelector } from "reselect"; import { selectBodyshop } from "../../redux/user/user.selectors"; import { searchingForConversation } from "../../redux/messaging/messaging.selectors"; -import { useSocket } from "../../contexts/SocketIO/useSocket.jsx"; +import { useSocket } from "../../contexts/SocketIO/useSocket.js"; import { useNotification } from "../../contexts/Notifications/notificationContext.jsx"; const mapStateToProps = createStructuredSelector({ diff --git a/client/src/components/chat-popup/chat-popup.component.jsx b/client/src/components/chat-popup/chat-popup.component.jsx index 2ae16b129..01c5b3e85 100644 --- a/client/src/components/chat-popup/chat-popup.component.jsx +++ b/client/src/components/chat-popup/chat-popup.component.jsx @@ -12,9 +12,9 @@ import ChatConversationListComponent from "../chat-conversation-list/chat-conver import ChatConversationContainer from "../chat-conversation/chat-conversation.container"; import ChatNewConversation from "../chat-new-conversation/chat-new-conversation.component"; import LoadingSpinner from "../loading-spinner/loading-spinner.component"; -import { useSocket } from "../../contexts/SocketIO/useSocket.jsx"; import "./chat-popup.styles.scss"; +import { useSocket } from "../../contexts/SocketIO/useSocket.js"; const mapStateToProps = createStructuredSelector({ selectedConversation: selectSelectedConversation, diff --git a/client/src/components/chat-tag-ro/chat-tag-ro.container.jsx b/client/src/components/chat-tag-ro/chat-tag-ro.container.jsx index 2a12d96db..d6c5bef4c 100644 --- a/client/src/components/chat-tag-ro/chat-tag-ro.container.jsx +++ b/client/src/components/chat-tag-ro/chat-tag-ro.container.jsx @@ -8,10 +8,10 @@ import { logImEXEvent } from "../../firebase/firebase.utils"; import { INSERT_CONVERSATION_TAG } from "../../graphql/job-conversations.queries"; import { SEARCH_FOR_JOBS } from "../../graphql/jobs.queries"; import ChatTagRo from "./chat-tag-ro.component"; -import { useSocket } from "../../contexts/SocketIO/useSocket.jsx"; import { createStructuredSelector } from "reselect"; import { selectBodyshop } from "../../redux/user/user.selectors.js"; import { connect } from "react-redux"; +import { useSocket } from "../../contexts/SocketIO/useSocket.js"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop diff --git a/client/src/components/header/header.component.jsx b/client/src/components/header/header.component.jsx index 407bfd8a5..effe2fbf9 100644 --- a/client/src/components/header/header.component.jsx +++ b/client/src/components/header/header.component.jsx @@ -40,7 +40,6 @@ import { RiSurveyLine } from "react-icons/ri"; import { connect } from "react-redux"; import { Link } from "react-router-dom"; import { createStructuredSelector } from "reselect"; -import { useSocket } from "../../contexts/SocketIO/useSocket.jsx"; import { GET_UNREAD_COUNT } from "../../graphql/notifications.queries.js"; import { selectRecentItems, selectSelectedHeader } from "../../redux/application/application.selectors"; import { setModalContext } from "../../redux/modals/modals.actions"; @@ -51,6 +50,7 @@ import InstanceRenderManager from "../../utils/instanceRenderMgr"; import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component"; import LockWrapper from "../lock-wrapper/lock-wrapper.component"; import NotificationCenterContainer from "../notification-center/notification-center.container.jsx"; +import { useSocket } from "../../contexts/SocketIO/useSocket.js"; // Redux mappings const mapStateToProps = createStructuredSelector({ diff --git a/client/src/components/job-at-change/schedule-event.component.jsx b/client/src/components/job-at-change/schedule-event.component.jsx index eb53dffd4..4facb2a19 100644 --- a/client/src/components/job-at-change/schedule-event.component.jsx +++ b/client/src/components/job-at-change/schedule-event.component.jsx @@ -8,7 +8,7 @@ import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { Link, useLocation, useNavigate } from "react-router-dom"; import { createStructuredSelector } from "reselect"; -import { useSocket } from "../../contexts/SocketIO/useSocket.jsx"; +import { useSocket } from "../../contexts/SocketIO/useSocket.js"; import { UPDATE_APPOINTMENT } from "../../graphql/appointments.queries"; import { openChatByPhone, setMessage } from "../../redux/messaging/messaging.actions"; import { setModalContext } from "../../redux/modals/modals.actions"; diff --git a/client/src/components/job-detail-cards/job-detail-cards.component.jsx b/client/src/components/job-detail-cards/job-detail-cards.component.jsx index 5e5df5b58..d114816ed 100644 --- a/client/src/components/job-detail-cards/job-detail-cards.component.jsx +++ b/client/src/components/job-detail-cards/job-detail-cards.component.jsx @@ -6,7 +6,8 @@ import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { Link, useLocation, useNavigate } from "react-router-dom"; import { createStructuredSelector } from "reselect"; -import { useSocket } from "../../contexts/SocketIO/useSocket.jsx"; +import { useSocket } from "../../contexts/SocketIO/useSocket.js"; + import { logImEXEvent } from "../../firebase/firebase.utils"; import { QUERY_JOB_CARD_DETAILS, UPDATE_JOB } from "../../graphql/jobs.queries"; import { insertAuditTrail } from "../../redux/application/application.actions.js"; diff --git a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx index 02a6b3494..9488c60e1 100644 --- a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx +++ b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx @@ -9,7 +9,7 @@ import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { Link, useNavigate } from "react-router-dom"; import { createStructuredSelector } from "reselect"; -import { useSocket } from "../../contexts/SocketIO/useSocket.jsx"; +import { useSocket } from "../../contexts/SocketIO/useSocket.js"; import { auth, logImEXEvent } from "../../firebase/firebase.utils"; import { CANCEL_APPOINTMENTS_BY_JOB_ID, INSERT_MANUAL_APPT } from "../../graphql/appointments.queries"; import { GET_CURRENT_QUESTIONSET_ID, INSERT_CSI } from "../../graphql/csi.queries"; diff --git a/client/src/components/notification-center/notification-center.container.jsx b/client/src/components/notification-center/notification-center.container.jsx index ae12552f3..a2924aa3a 100644 --- a/client/src/components/notification-center/notification-center.container.jsx +++ b/client/src/components/notification-center/notification-center.container.jsx @@ -3,10 +3,10 @@ import { useQuery } from "@apollo/client"; import { connect } from "react-redux"; import NotificationCenterComponent from "./notification-center.component"; import { GET_NOTIFICATIONS } from "../../graphql/notifications.queries"; -import { INITIAL_NOTIFICATIONS, useSocket } from "../../contexts/SocketIO/useSocket.jsx"; import { createStructuredSelector } from "reselect"; import { selectBodyshop } from "../../redux/user/user.selectors.js"; import day from "../../utils/day.js"; +import { INITIAL_NOTIFICATIONS, useSocket } from "../../contexts/SocketIO/useSocket.js"; // This will be used to poll for notifications when the socket is disconnected const NOTIFICATION_POLL_INTERVAL_SECONDS = 60; diff --git a/client/src/components/payments-generate-link/payments-generate-link.component.jsx b/client/src/components/payments-generate-link/payments-generate-link.component.jsx index 7e121621f..4c1fb5fef 100644 --- a/client/src/components/payments-generate-link/payments-generate-link.component.jsx +++ b/client/src/components/payments-generate-link/payments-generate-link.component.jsx @@ -10,7 +10,7 @@ import { createStructuredSelector } from "reselect"; import { openChatByPhone, setMessage } from "../../redux/messaging/messaging.actions"; import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors"; import CurrencyFormItemComponent from "../form-items-formatted/currency-form-item.component"; -import { useSocket } from "../../contexts/SocketIO/useSocket.jsx"; +import { useSocket } from "../../contexts/SocketIO/useSocket.js"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, diff --git a/client/src/components/production-board-kanban/production-board-kanban.container.jsx b/client/src/components/production-board-kanban/production-board-kanban.container.jsx index 3b0c4066f..536f1193e 100644 --- a/client/src/components/production-board-kanban/production-board-kanban.container.jsx +++ b/client/src/components/production-board-kanban/production-board-kanban.container.jsx @@ -12,7 +12,7 @@ import { QUERY_KANBAN_SETTINGS } from "../../graphql/user.queries"; import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors"; import ProductionBoardKanbanComponent from "./production-board-kanban.component"; import { useSplitTreatments } from "@splitsoftware/splitio-react"; -import { useSocket } from "../../contexts/SocketIO/useSocket.jsx"; +import { useSocket } from "../../contexts/SocketIO/useSocket.js"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, diff --git a/client/src/components/production-list-detail/production-list-detail.component.jsx b/client/src/components/production-list-detail/production-list-detail.component.jsx index 7db55bd07..d05110fc5 100644 --- a/client/src/components/production-list-detail/production-list-detail.component.jsx +++ b/client/src/components/production-list-detail/production-list-detail.component.jsx @@ -7,7 +7,7 @@ import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { useLocation, useNavigate } from "react-router-dom"; import { createStructuredSelector } from "reselect"; -import { useSocket } from "../../contexts/SocketIO/useSocket.jsx"; +import { useSocket } from "../../contexts/SocketIO/useSocket.js"; import { logImEXEvent } from "../../firebase/firebase.utils.js"; import { QUERY_JOB_CARD_DETAILS, UPDATE_JOB } from "../../graphql/jobs.queries"; import { insertAuditTrail } from "../../redux/application/application.actions.js"; diff --git a/client/src/components/production-list-table/production-list-table.container.jsx b/client/src/components/production-list-table/production-list-table.container.jsx index 373222a65..17aba9b16 100644 --- a/client/src/components/production-list-table/production-list-table.container.jsx +++ b/client/src/components/production-list-table/production-list-table.container.jsx @@ -10,7 +10,7 @@ import { import ProductionListTable from "./production-list-table.component"; import _ from "lodash"; import { useSplitTreatments } from "@splitsoftware/splitio-react"; -import { useSocket } from "../../contexts/SocketIO/useSocket.jsx"; +import { useSocket } from "../../contexts/SocketIO/useSocket.js"; export default function ProductionListTableContainer({ bodyshop, subscriptionType = "direct" }) { const client = useApolloClient(); diff --git a/client/src/components/profile-my/profile-my.component.jsx b/client/src/components/profile-my/profile-my.component.jsx index d17547cf0..0b3180d0a 100644 --- a/client/src/components/profile-my/profile-my.component.jsx +++ b/client/src/components/profile-my/profile-my.component.jsx @@ -8,7 +8,7 @@ import { selectCurrentUser } from "../../redux/user/user.selectors"; import { logImEXEvent, updateCurrentPassword } from "../../firebase/firebase.utils"; import LayoutFormRow from "../layout-form-row/layout-form-row.component"; import { useNotification } from "../../contexts/Notifications/notificationContext.jsx"; -import { useSocket } from "../../contexts/SocketIO/useSocket.jsx"; +import { useSocket } from "../../contexts/SocketIO/useSocket.js"; import NotificationSettingsForm from "../notification-settings/notification-settings-form.component.jsx"; const mapStateToProps = createStructuredSelector({ diff --git a/client/src/contexts/SocketIO/useSocket.jsx b/client/src/contexts/SocketIO/socketProvider.jsx similarity index 96% rename from client/src/contexts/SocketIO/useSocket.jsx rename to client/src/contexts/SocketIO/socketProvider.jsx index 70f52311f..efc77ea7c 100644 --- a/client/src/contexts/SocketIO/useSocket.jsx +++ b/client/src/contexts/SocketIO/socketProvider.jsx @@ -1,4 +1,5 @@ -import { createContext, useContext, useEffect, useRef, useState } from "react"; +// SocketProvider.js +import { useEffect, useRef, useState } from "react"; import SocketIO from "socket.io-client"; import { auth } from "../../firebase/firebase.utils"; import { store } from "../../redux/store"; @@ -15,10 +16,7 @@ import { import { useMutation } from "@apollo/client"; import { useTranslation } from "react-i18next"; import { useSplitTreatments } from "@splitsoftware/splitio-react"; - -const SocketContext = createContext(null); - -const INITIAL_NOTIFICATIONS = 10; +import { SocketContext, INITIAL_NOTIFICATIONS } from "./useSocket.js"; /** * Socket Provider - Scenario Notifications / Web Socket related items @@ -216,7 +214,6 @@ const SocketProvider = ({ children, bodyshop, navigate, currentUser }) => { }; const handleNotification = (data) => { - // Scenario Notifications have been disabled, bail. if (Realtime_Notifications_UI?.treatment !== "on") { return; } @@ -336,7 +333,6 @@ const SocketProvider = ({ children, bodyshop, navigate, currentUser }) => { }; const handleSyncNotificationRead = ({ notificationId, timestamp }) => { - // Scenario Notifications have been disabled, bail. if (Realtime_Notifications_UI?.treatment !== "on") { return; } @@ -378,7 +374,6 @@ const SocketProvider = ({ children, bodyshop, navigate, currentUser }) => { }; const handleSyncAllNotificationsRead = ({ timestamp }) => { - // Scenario Notifications have been disabled, bail. if (Realtime_Notifications_UI?.treatment !== "on") { return; } @@ -490,11 +485,4 @@ const SocketProvider = ({ children, bodyshop, navigate, currentUser }) => { ); }; -const useSocket = () => { - const context = useContext(SocketContext); - // NOTE: Not sure if we absolutely require this, does cause slipups on dev env - if (!context) throw new Error("useSocket must be used within a SocketProvider"); - return context; -}; - -export { SocketContext, SocketProvider, INITIAL_NOTIFICATIONS, useSocket }; +export default SocketProvider; diff --git a/client/src/contexts/SocketIO/useSocket.js b/client/src/contexts/SocketIO/useSocket.js new file mode 100644 index 000000000..d9a6f9b84 --- /dev/null +++ b/client/src/contexts/SocketIO/useSocket.js @@ -0,0 +1,13 @@ +import { createContext, useContext } from "react"; + +const SocketContext = createContext(null); + +const INITIAL_NOTIFICATIONS = 10; + +const useSocket = () => { + const context = useContext(SocketContext); + if (!context) throw new Error("useSocket must be used within a SocketProvider"); + return context; +}; + +export { SocketContext, INITIAL_NOTIFICATIONS, useSocket }; diff --git a/client/src/pages/jobs-detail/jobs-detail.page.component.jsx b/client/src/pages/jobs-detail/jobs-detail.page.component.jsx index d5b6776ee..6afe3ba15 100644 --- a/client/src/pages/jobs-detail/jobs-detail.page.component.jsx +++ b/client/src/pages/jobs-detail/jobs-detail.page.component.jsx @@ -56,7 +56,7 @@ import { DateTimeFormat } from "../../utils/DateFormatter"; import dayjs from "../../utils/day"; import UndefinedToNull from "../../utils/undefinedtonull"; import { useNotification } from "../../contexts/Notifications/notificationContext.jsx"; -import { useSocket } from "../../contexts/SocketIO/useSocket.jsx"; +import { useSocket } from "../../contexts/SocketIO/useSocket.js"; import JobWatcherToggleContainer from "../../components/job-watcher-toggle/job-watcher-toggle.container.jsx"; const mapStateToProps = createStructuredSelector({ diff --git a/client/src/pages/manage/manage.page.component.jsx b/client/src/pages/manage/manage.page.component.jsx index e813eaae0..b6148aa1d 100644 --- a/client/src/pages/manage/manage.page.component.jsx +++ b/client/src/pages/manage/manage.page.component.jsx @@ -20,7 +20,6 @@ import PartnerPingComponent from "../../components/partner-ping/partner-ping.com import PrintCenterModalContainer from "../../components/print-center-modal/print-center-modal.container"; import ShopSubStatusComponent from "../../components/shop-sub-status/shop-sub-status.component"; import { requestForToken } from "../../firebase/firebase.utils"; -import { useSocket } from "../../contexts/SocketIO/useSocket.jsx"; import { selectBodyshop, selectInstanceConflict } from "../../redux/user/user.selectors"; import UpdateAlert from "../../components/update-alert/update-alert.component"; import InstanceRenderManager from "../../utils/instanceRenderMgr.js"; @@ -29,6 +28,7 @@ import WssStatusDisplayComponent from "../../components/wss-status-display/wss-s import { selectAlerts } from "../../redux/application/application.selectors.js"; import { addAlerts } from "../../redux/application/application.actions.js"; import { useNotification } from "../../contexts/Notifications/notificationContext.jsx"; +import { useSocket } from "../../contexts/SocketIO/useSocket.js"; const JobsPage = lazy(() => import("../jobs/jobs.page"));