From 6caa7c8bfa72d993abddc08544dd888df0aab643 Mon Sep 17 00:00:00 2001 From: Aman Chaturvedi Date: Fri, 8 Mar 2024 20:21:02 +0530 Subject: [PATCH] TP-50439 map enhancements v2 (#878) * TP-50439 | map enhancements * TP-50439 | Map enhancements v2 * TP-50439 | fix missing icon houston * TP-50439 | revert config files changes * TP-50439 | revert debug extension console log * TP-50439 | fix * TP-50439 | fixes * TP-50439 | fixes * TP-50439 | zindex var * TP-50439 | live location external routing changes * TP-50439 | external Live Location Fixes * TP-50439 | internal map view fixes * TP-50439 | fixes * TP-50439 | revert api helper * TP-50439 | submodule update * TP-50439 | feedback selection fix * TP-50439 | fix --------- Co-authored-by: yashmantri --- .eslintrc.json | 1 + configuration.js | 49 ++--- src/assets/styles/variables.scss | 2 + .../SingleAutocompleteDropdown.tsx | 3 +- .../AutocompleteDropdown/interfaces.tsx | 1 + src/components/sidebar/SideBarItems.tsx | 4 +- src/components/sidebar/SideNavBar.tsx | 17 +- src/layout/DefaultLayout.tsx | 2 + src/layout/Routes.tsx | 2 + .../components/Header/index.module.scss | 23 +-- .../components/Header/index.tsx | 174 ++++++++++-------- .../ExternalDashboardSensei/constants.ts | 1 + src/pages/ExternalDashboardSensei/index.tsx | 21 +-- src/pages/ExternalDashboardSensei/types.ts | 1 + src/pages/ExternalDashboardSensei/utils.tsx | 49 ++++- .../components/AgentMarker/index.tsx | 91 ++++++--- .../AgentsAccordion/AccordionBody.tsx | 55 ++++-- .../AgentsAccordion/AgentDetail.tsx | 3 +- .../AgentsAccordion/FeedbackDetail.tsx | 7 +- .../AgentsAccordion/index.module.scss | 8 +- .../GoogleMapsContainer.module.scss | 2 +- .../LocationAgencySearch/index.module.scss | 68 +++++++ .../components/LocationAgencySearch/index.tsx | 72 ++++++++ .../MapPlaceholder/mapPlaceholder.module.scss | 7 +- .../components/MapView/index.tsx | 74 +++----- .../components/PinFilters/index.module.scss | 3 - .../components/PinFilters/index.tsx | 50 ++++- .../components/Tooltip/index.tsx | 99 +++++++--- .../components/Tooltip/tooltip.module.scss | 39 +++- .../components/TopBar/Filters.tsx | 64 +------ .../components/TopBar/TopBar.module.scss | 3 +- .../components/TopBar/index.tsx | 5 - .../LiveLocationTrackerInterfaces.ts | 16 +- .../LiveLocationTracker/index.module.scss | 26 ++- src/pages/LiveLocationTracker/index.tsx | 117 ++++++++++-- .../reducers/LiveLocationTrackerSlice.ts | 1 + src/pages/LiveLocationTracker/utils.tsx | 93 ++++++---- src/pages/auth/constants/AuthConstants.ts | 2 +- src/pages/sensei/index.tsx | 131 ++++++++++--- src/utils/ApiHelper.ts | 2 + src/utils/DateHelper.ts | 4 + src/utils/commonUtils.ts | 1 + 42 files changed, 946 insertions(+), 447 deletions(-) create mode 100644 src/pages/LiveLocationTracker/components/LocationAgencySearch/index.module.scss create mode 100644 src/pages/LiveLocationTracker/components/LocationAgencySearch/index.tsx diff --git a/.eslintrc.json b/.eslintrc.json index 92da60b4..d93b1aed 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -37,6 +37,7 @@ }, "rules": { "react/react-in-jsx-scope": "off", + "react/display-name": "off", "react/jsx-uses-react": "error", "react/jsx-uses-vars": "error", "react-hooks/rules-of-hooks": "error", diff --git a/configuration.js b/configuration.js index ab4bd350..73b29f84 100644 --- a/configuration.js +++ b/configuration.js @@ -1,26 +1,27 @@ window.config = { - BFF_SERVICE_BASE_URL: '/api', - EXTENSION_PLUGIN_USERS_LIST: [], - APM_BASE_URL: 'https://apm-server.np.navi-sa.in/', - APM_APP_NAME: 'collections-portal', - AUTH_BASE_URL: 'https://dev-dark-knight.np.navi-sa.in', - AUTH_CLIENT_ID: 'KBDpUxvr5S', - SENTRY_DSN: 'https://6f03f79661684b70a2e501dde312402d@glitchtip.cmd.navi-tech.in/126', - BUILD_TIME: 0, - ENABLE_SSO: "true", - ENV: "dev", - FCM_apiKey: 'AIzaSyAmUlPwmxtjehTcPBOH3HGxGP-BdWvC9JY', - FCM_authDomain: 'longhornchat-qa.firebaseapp.com', - FCM_databaseURL: 'https://address-verification-app-default-rtdb.firebaseio.com', - FCM_projectId: 'longhornchat-qa', - FCM_storageBucket: 'longhornchat-qa.appspot.com', - FCM_messagingSenderId: '767234038375', - FCM_appId: '1:767234038375:web:a6804341cbaa889b5c12c2', - FCM_measurementId: 'G-CV730KBYP6', - FCM_VapidKey: 'BBWfszq15lfSiA2IdSIi9mwo8vK52D47wlQBSHyMbdyaufuy5b13DAvNETyB-dvxROz5C_JKuOobbEfZt4Dpvzk', - DISABLE_AMEYO_TOOLBAR: "false", - GOOGLE_CAPTCHA_SITE_KEY: "6LezfLIlAAAAABGHea7siv00VaZhRjfcPoCEI6_c", - GOOGLE_MAPS_KEY: '', - GOOGLE_MAP_ID: '', - HRC_CALL_AUTO_ACCEPT_TIMEOUT: "2", + BFF_SERVICE_BASE_URL: '/api', + EXTENSION_PLUGIN_USERS_LIST: [], + APM_BASE_URL: 'https://apm-server.np.navi-sa.in/', + APM_APP_NAME: 'collections-portal', + AUTH_BASE_URL: 'https://dev-dark-knight.np.navi-sa.in', + AUTH_CLIENT_ID: 'KBDpUxvr5S', + SENTRY_DSN: 'https://6f03f79661684b70a2e501dde312402d@glitchtip.cmd.navi-tech.in/126', + BUILD_TIME: 0, + ENABLE_SSO: 'true', + ENV: 'dev', + FCM_apiKey: 'AIzaSyAmUlPwmxtjehTcPBOH3HGxGP-BdWvC9JY', + FCM_authDomain: 'longhornchat-qa.firebaseapp.com', + FCM_databaseURL: 'https://address-verification-app-default-rtdb.firebaseio.com', + FCM_projectId: 'longhornchat-qa', + FCM_storageBucket: 'longhornchat-qa.appspot.com', + FCM_messagingSenderId: '767234038375', + FCM_appId: '1:767234038375:web:a6804341cbaa889b5c12c2', + FCM_measurementId: 'G-CV730KBYP6', + FCM_VapidKey: + 'BBWfszq15lfSiA2IdSIi9mwo8vK52D47wlQBSHyMbdyaufuy5b13DAvNETyB-dvxROz5C_JKuOobbEfZt4Dpvzk', + DISABLE_AMEYO_TOOLBAR: 'false', + GOOGLE_CAPTCHA_SITE_KEY: '6LezfLIlAAAAABGHea7siv00VaZhRjfcPoCEI6_c', + GOOGLE_MAPS_KEY: '', + GOOGLE_MAP_ID: '', + HRC_CALL_AUTO_ACCEPT_TIMEOUT: '2' }; diff --git a/src/assets/styles/variables.scss b/src/assets/styles/variables.scss index 85cfdfa9..bb95daf7 100644 --- a/src/assets/styles/variables.scss +++ b/src/assets/styles/variables.scss @@ -141,6 +141,7 @@ --z-index-external-sensei-toggle-tabs: 3; --z-index-external-sensei-header: 4; --z-index-dropdown-picker: 10; + --z-index-map-options: 10; --z-index-side-logout-btn: 42; --z-index-ameyo-disconnect-btn: 99; --z-index-leaderboard-overlay: 99; @@ -150,6 +151,7 @@ --z-index-autocomplete-dropdown: 100; --z-index-ameyo-collapsible-toolbar: 100; --z-index-autocomplete-picker: 100; + --z-index-maps-loader-overlay: 100; --z-index-sticky-note: 999; --z-index-audio-player: 1001; --z-index-leaderboard-overlay-active: 1002; diff --git a/src/components/AutocompleteDropdown/SingleAutocompleteDropdown.tsx b/src/components/AutocompleteDropdown/SingleAutocompleteDropdown.tsx index 6f429606..249b56a3 100644 --- a/src/components/AutocompleteDropdown/SingleAutocompleteDropdown.tsx +++ b/src/components/AutocompleteDropdown/SingleAutocompleteDropdown.tsx @@ -17,6 +17,7 @@ const SingleAutocompleteDropdown = forwardRef
- {selectedOption && !disabled ? ( + {selectedOption && !disabled && !hideCloseOption ? ( ) : null} diff --git a/src/components/AutocompleteDropdown/interfaces.tsx b/src/components/AutocompleteDropdown/interfaces.tsx index 8d70e256..20fe614f 100644 --- a/src/components/AutocompleteDropdown/interfaces.tsx +++ b/src/components/AutocompleteDropdown/interfaces.tsx @@ -32,6 +32,7 @@ export interface ISingleAutocompleteDropdown extends ComponentPropsWithRef<'inpu error?: string; disabled?: boolean; sortOptions?: boolean; + hideCloseOption?: boolean; onSearch?: (searchTerm: string) => void; onSelectionChange: (selectedOptions: IOption | null) => void; customOptionTemplate?: (option: IOption) => React.ReactNode; diff --git a/src/components/sidebar/SideBarItems.tsx b/src/components/sidebar/SideBarItems.tsx index 83a8969a..64aeb5d2 100644 --- a/src/components/sidebar/SideBarItems.tsx +++ b/src/components/sidebar/SideBarItems.tsx @@ -16,7 +16,9 @@ export const DASHBOARD_URL = location.origin + '/calling-agent/dashboard'; export const ADMIN_CASES_URL = location.origin + '/admin'; export const persistQueryParamsRoutes = [ - APP_ROUTES_PATHS_WITH_PATH_PARAM.SENSEI.external_allocation_view + APP_ROUTES_PATHS_WITH_PATH_PARAM.SENSEI.external_allocation_view, + APP_ROUTES_PATHS_WITH_PATH_PARAM.SENSEI.external_live_location, + APP_ROUTES_PATHS_WITH_PATH_PARAM.SENSEI.live_location ]; export default SideBarItems; diff --git a/src/components/sidebar/SideNavBar.tsx b/src/components/sidebar/SideNavBar.tsx index 8fea287c..ec29d910 100644 --- a/src/components/sidebar/SideNavBar.tsx +++ b/src/components/sidebar/SideNavBar.tsx @@ -25,7 +25,7 @@ import Switch from '@navi/web-ui/lib/primitives/Switch/Switch'; import { refreshCallData, setManualLoginCreds } from 'src/reducers/humanReminderSlice'; import { ExtensionHandler } from 'src/utils/extension.utils'; import { AMEYO_STATUS_CODES } from 'src/service/naviExtension.service'; -import APP_ROUTES from 'src/layout/Routes'; +import APP_ROUTES, { APP_ROUTES_PATHS_WITH_PATH_PARAM } from 'src/layout/Routes'; import { toast } from '@navi/web-ui/lib/primitives/Toast/core/toast'; import { AMEYO_SESSION_EVENTS, @@ -404,7 +404,7 @@ function SideNavBar({ isDc97User, isHRCChatUser }: ISideNavbarProps) { route={ externalAgencyPerformanceDashboard ? APP_ROUTES.SENSEI_EXTERNAL.relativePath - : APP_ROUTES.PERFORMANCE_DASHBOARD.path + : APP_ROUTES_PATHS_WITH_PATH_PARAM.SENSEI.daily_planning } linkClickHandler={linkClickHandler} currentPathname={pathname} @@ -510,19 +510,6 @@ function SideNavBar({ isDc97User, isHRCChatUser }: ISideNavbarProps) { /> ) : null} - {fieldTLAndClusterAndZonalManagers ? ( - } - inActiveIcon={} - name={'Tracker'} - route={APP_ROUTES.SENSEI.relativePath} - linkClickHandler={linkClickHandler} - currentPathname={pathname} - currentSearch={search} - clickStreamEvent={CLICKSTREAM_EVENT_NAMES.LH_FIELD_DASHBOARD_SIDE_PANEL_CLICK} - /> - ) : null} {isPincodeMappingVisible ? ( { + const queryParams = readQueryParams(); + const agentLiveLocationParams = queryParams?.[AGENT_LIVE_LOCATION] || {}; const navigate = useNavigate(); - const dispatch = useDispatch(); const { tabId = '' } = useParams(); - const { allLastUpdatedAt, userData, featureFlags, dailyPlanningLastUpdatedAt } = useSelector( - (state: RootState) => ({ - allLastUpdatedAt: state?.externalDashboardSensei?.allLastUpdatedAt, - userData: state?.common?.userData, - featureFlags: state?.common?.featureFlags, - dailyPlanningLastUpdatedAt: state?.sensai?.dailyPlanning?.commitmentsTable?.lastUpdatedAt - }) - ); + const { + allLastUpdatedAt, + featureFlags, + dailyPlanningLastUpdatedAt, + liveLocationTrackerLastUpdatedAt + } = useSelector((state: RootState) => ({ + allLastUpdatedAt: state?.externalDashboardSensei?.allLastUpdatedAt, + featureFlags: state?.common?.featureFlags, + dailyPlanningLastUpdatedAt: state?.sensai?.dailyPlanning?.commitmentsTable?.lastUpdatedAt, + liveLocationTrackerLastUpdatedAt: state.liveLocationTracker?.lastUpdatedAt + })); const { overallPerformanceOverallMetricsTable, @@ -51,79 +53,103 @@ const Header = () => { agentAllocationMapViewFlag } = featureFlags || {}; - const lastUpdatedAt = useMemo( - () => getLastUpdatedAt({ ...allLastUpdatedAt, dailyPlanningLastUpdatedAt }, tabId), - [tabId, allLastUpdatedAt, dailyPlanningLastUpdatedAt] - ); - const { roles } = userData || {}; - const handleRefresh = () => { - switch (tabId) { - case TabsKey.OVERALL_PERFORMANCE: - if (overallPerformanceOverallMetricsTable) dispatch(getDpdBucketData()); - if (overallPerformanceAgentPerformanceTable) dispatch(getAgentPerformanceTLData()); - break; - case TabsKey.FIELD_GOVERNANCE: - if (fieldGovernanceAgencyPerformanceTable) dispatch(getAgencyDetailsData()); - if (fieldGovernanceAgentPerformanceTable) dispatch(getAgentPerformanceData()); - break; - case TabsKey.DAILY_PLANNING: - dispatch(fetchCommitments()); - dispatch(fetchPTPDetails()); - break; + const { lastUpdatedAt, handleRefresh } = useMemo(() => { + let handleRefresh = null; + let lastUpdatedAt = null; - case TabsKey.ALLOCATION_VIEW: - if (agentAllocationMapViewFlag) dispatch(getCaseAllocationViewData()); + switch (tabId) { + case TabsKey.DAILY_PLANNING: { + handleRefresh = () => { + dispatch(fetchCommitments()); + dispatch(fetchPTPDetails()); + }; + lastUpdatedAt = dailyPlanningLastUpdatedAt; + break; + } + case TabsKey.OVERALL_PERFORMANCE: { + handleRefresh = () => { + if (overallPerformanceOverallMetricsTable) dispatch(getDpdBucketData()); + if (overallPerformanceAgentPerformanceTable) dispatch(getAgentPerformanceTLData()); + }; + lastUpdatedAt = getOverallPerformanceLastUpdatedAt(allLastUpdatedAt); + break; + } + case TabsKey.FIELD_GOVERNANCE: { + handleRefresh = () => { + if (fieldGovernanceAgencyPerformanceTable) dispatch(getAgencyDetailsData()); + if (fieldGovernanceAgentPerformanceTable) dispatch(getAgentPerformanceData()); + }; + lastUpdatedAt = getFieldGovernanceLastUpdatedAt(allLastUpdatedAt); + break; + } + case TabsKey.ALLOCATION_VIEW: { + const isAllocationFiltersSelected = Object.keys(queryParams?.allocationView || {})?.length; + if (!isAllocationFiltersSelected) return { lastUpdatedAt: null, handleRefresh: null }; + handleRefresh = () => { + if (agentAllocationMapViewFlag) dispatch(getCaseAllocationViewData()); + }; + lastUpdatedAt = allLastUpdatedAt?.allocationViewLastUpdatedAt; + break; + } + case TabsKey.LIVE_LOCATION: + if (!agentLiveLocationParams?.AGENCY) { + return { lastUpdatedAt: null, handleRefresh: null }; + } + handleRefresh = () => { + if (agentLiveLocationParams?.AGENTID) { + dispatch( + getAgentDetails( + { + date: agentLiveLocationParams?.DATE, + referenceId: agentLiveLocationParams?.AGENTID + }, + navigate + ) + ); + } else { + const selectedTeamLead = agentLiveLocationParams[FilterTypes.TEAM_LEAD]; + const selectedAgency = agentLiveLocationParams[FilterTypes.AGENCY]; + const payload = { + agencyCodes: [selectedAgency], + teamLeadReferenceIds: selectedTeamLead ? [selectedTeamLead] : [] + }; + dispatch(getAgentsLocations(payload, false)); + } + }; + lastUpdatedAt = liveLocationTrackerLastUpdatedAt; break; default: break; } - }; - const enableAgentLiveLocation = useMemo(() => showAgentsLiveLocation(roles), [roles]); - - const handleLiveLocationClick = () => { - addClickstreamEvent( - PERFORMANCE_DASHBOARD_CLICKSTREAM[PERFORMANCE_DASHBOARD_EVENTS.LH_AGENT_TRACKING_CLICKED], - { userId: userData?.referenceId } - ); - const updatedParams = getLiveLocationParams(LIVE_LOCATION_SOURCE.EXTERNAL_SENSEI); - navigate(`${APP_ROUTES.LIVE_LOCATION_TRACKER.path}${updatedParams}`); - }; - - const queryParams = readQueryParams(); - const isAllocationFiltersSelected = Object.keys(queryParams?.allocationView || {})?.length; - const showExtraInfo = tabId === TabsKey.ALLOCATION_VIEW ? isAllocationFiltersSelected : true; + return { lastUpdatedAt, handleRefresh }; + }, [ + tabId, + queryParams?.SELECTED_FEEDBACK_ID, + allLastUpdatedAt, + dailyPlanningLastUpdatedAt, + liveLocationTrackerLastUpdatedAt + ]); return (
Agent Dashboard - {showExtraInfo ? ( - <> +
+ {lastUpdatedAt ? ( Last updated at{' '} {lastUpdatedAt ? dateFormat(new Date(lastUpdatedAt), DateFormat.LONG_DATE_FORMAT_WITH_TIME) : '--'} + ) : null} + {handleRefresh ? (
- - ) : null} -
-
- {enableAgentLiveLocation ? ( -
- -
- ) : null} + ) : null} +
); diff --git a/src/pages/ExternalDashboardSensei/constants.ts b/src/pages/ExternalDashboardSensei/constants.ts index 79081ccd..ec5e9ec3 100644 --- a/src/pages/ExternalDashboardSensei/constants.ts +++ b/src/pages/ExternalDashboardSensei/constants.ts @@ -28,6 +28,7 @@ export enum TabsKey { OVERALL_PERFORMANCE = 'overall_performance', FIELD_GOVERNANCE = 'field_governance', DAILY_PLANNING = 'daily_planning', + LIVE_LOCATION = 'live_location', ALLOCATION_VIEW = 'allocation_view' } diff --git a/src/pages/ExternalDashboardSensei/index.tsx b/src/pages/ExternalDashboardSensei/index.tsx index 510cf052..10934372 100644 --- a/src/pages/ExternalDashboardSensei/index.tsx +++ b/src/pages/ExternalDashboardSensei/index.tsx @@ -10,7 +10,7 @@ import { RootState } from '@cp/src/store'; import { addClickstreamEvent } from '@cp/src/service/clickStreamEventService'; import { CLICKSTREAM_EVENT_NAMES } from '@cp/src/service/clickStream.constant'; import Header from './components/Header'; -import APP_ROUTES, { APP_ROUTES_PATHS_WITH_PATH_PARAM } from '@cp/src/layout/Routes'; +import APP_ROUTES from '@cp/src/layout/Routes'; import { interpolatePathParams } from '@cp/src/utils/interpolate'; import { LocalStorage } from '@cp/src/utils/StorageUtils'; @@ -26,12 +26,7 @@ const ExternalDashboardSensei = () => { const paramsMap: Record = LocalStorage.getItem('paramsMap') || {}; const handleTabChange = (updateTabId: TabItemKey) => { - let currentParams = ''; if (tabId !== updateTabId) { - if (updateTabId === TabsKey.ALLOCATION_VIEW) { - currentParams = - paramsMap[APP_ROUTES_PATHS_WITH_PATH_PARAM.SENSEI.external_allocation_view] || ''; - } addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.LH_FIELD_DASHBOARD_TAB_SWITCH, { currentTab: tabId, newTab: updateTabId @@ -39,6 +34,7 @@ const ExternalDashboardSensei = () => { const updatedUrl = interpolatePathParams(APP_ROUTES.SENSEI_EXTERNAL.path, { tabId: String(updateTabId) }); + const currentParams = paramsMap[updatedUrl] || ''; navigate(updatedUrl + currentParams); } }; @@ -57,17 +53,14 @@ const ExternalDashboardSensei = () => { TabsKey.FIELD_GOVERNANCE, TabsKey.OVERALL_PERFORMANCE, TabsKey.DAILY_PLANNING, - TabsKey.ALLOCATION_VIEW + TabsKey.ALLOCATION_VIEW, + TabsKey.LIVE_LOCATION ].includes(tabId as TabsKey); if (isTabAccessNotAvailable || noTabSelected) { - const tabId = dashboardTabs?.[0]?.relativePath; - let currentParams = ''; - if (tabId.includes(TabsKey.ALLOCATION_VIEW)) { - currentParams = - paramsMap[APP_ROUTES_PATHS_WITH_PATH_PARAM.SENSEI.external_allocation_view] || ''; - } - navigate(tabId + currentParams); + const relativePath = dashboardTabs?.[0]?.relativePath; + const currentParams = paramsMap[relativePath] || ''; + navigate(relativePath + currentParams); } }, [tabId, dashboardTabs]); diff --git a/src/pages/ExternalDashboardSensei/types.ts b/src/pages/ExternalDashboardSensei/types.ts index 360eea32..42138a46 100644 --- a/src/pages/ExternalDashboardSensei/types.ts +++ b/src/pages/ExternalDashboardSensei/types.ts @@ -155,6 +155,7 @@ export interface IAllLastUpdateAt { agentPerformanceTlLastUpdatedAt: number; dailyPlanningLastUpdatedAt: number; allocationViewLastUpdatedAt: number; + liveLocationTrackerLastUpdatedAt: string | Date; } export interface IExternalSenseiDashboard { diff --git a/src/pages/ExternalDashboardSensei/utils.tsx b/src/pages/ExternalDashboardSensei/utils.tsx index fa80288b..81e8bda0 100644 --- a/src/pages/ExternalDashboardSensei/utils.tsx +++ b/src/pages/ExternalDashboardSensei/utils.tsx @@ -7,10 +7,16 @@ import AllocationView from '../MapAllocationView'; import OverallPerformance from './OverallPerformance'; import { FIELD_GOVERNANCE_TABS_VALUE, IAllLastUpdateAt } from './types'; import ExternalDailyPlanning from './components/DailyPlanning'; +import LiveLocationTracker from '../LiveLocationTracker'; export const getTabs = (featureFlags: IFeatureFlags, tabId: string) => { - const { overallPerformanceTab, fieldGovernanceTab, fcmDashboard, agentAllocationMapViewFlag } = - featureFlags || {}; + const { + overallPerformanceTab, + fieldGovernanceTab, + fcmDashboard, + agentAllocationMapViewFlag, + liveLocationTrackerFeatureFlag + } = featureFlags || {}; const tabs = []; @@ -41,6 +47,15 @@ export const getTabs = (featureFlags: IFeatureFlags, tabId: string) => { }); } + if (liveLocationTrackerFeatureFlag) { + tabs.push({ + key: TabsKey.LIVE_LOCATION, + value: 'Live location tracker', + component: , + relativePath: '/sensei-external/live_location' + }); + } + if (agentAllocationMapViewFlag) { tabs.push({ key: TabsKey.ALLOCATION_VIEW, @@ -121,6 +136,30 @@ export const setInitialOverallPerformanceTabParams = ( navigate(updatedParams); }; +export const getOverallPerformanceLastUpdatedAt = (allLastUpdatedAt: IAllLastUpdateAt) => { + const { dpdBucketLastUpdatedAt, agentPerformanceTlLastUpdatedAt } = allLastUpdatedAt; + + if (!dpdBucketLastUpdatedAt) return agentPerformanceTlLastUpdatedAt; + if (!agentPerformanceTlLastUpdatedAt) return dpdBucketLastUpdatedAt; + + if (dpdBucketLastUpdatedAt < agentPerformanceTlLastUpdatedAt) { + return dpdBucketLastUpdatedAt; + } + return agentPerformanceTlLastUpdatedAt; +}; + +export const getFieldGovernanceLastUpdatedAt = (allLastUpdatedAt: IAllLastUpdateAt) => { + const { agencyDetailsLastUpdatedAt, agentPerformanceLastUpdatedAt } = allLastUpdatedAt; + + if (!agencyDetailsLastUpdatedAt) return agentPerformanceLastUpdatedAt; + if (!agentPerformanceLastUpdatedAt) return agencyDetailsLastUpdatedAt; + + if (agencyDetailsLastUpdatedAt < agentPerformanceLastUpdatedAt) { + return agencyDetailsLastUpdatedAt; + } + return agentPerformanceLastUpdatedAt; +}; + export const getLastUpdatedAt = (allLastUpdatedAt: IAllLastUpdateAt, tabId: string) => { const { dpdBucketLastUpdatedAt, @@ -128,7 +167,8 @@ export const getLastUpdatedAt = (allLastUpdatedAt: IAllLastUpdateAt, tabId: stri agentPerformanceLastUpdatedAt, agentPerformanceTlLastUpdatedAt, dailyPlanningLastUpdatedAt, - allocationViewLastUpdatedAt + allocationViewLastUpdatedAt, + liveLocationTrackerLastUpdatedAt } = allLastUpdatedAt; if (tabId === TabsKey.OVERALL_PERFORMANCE) { @@ -158,4 +198,7 @@ export const getLastUpdatedAt = (allLastUpdatedAt: IAllLastUpdateAt, tabId: stri if (tabId === TabsKey.ALLOCATION_VIEW) { return allocationViewLastUpdatedAt; } + if (tabId === TabsKey.LIVE_LOCATION) { + return liveLocationTrackerLastUpdatedAt; + } }; diff --git a/src/pages/LiveLocationTracker/components/AgentMarker/index.tsx b/src/pages/LiveLocationTracker/components/AgentMarker/index.tsx index 8e3d6890..994e69ae 100644 --- a/src/pages/LiveLocationTracker/components/AgentMarker/index.tsx +++ b/src/pages/LiveLocationTracker/components/AgentMarker/index.tsx @@ -3,14 +3,22 @@ import useMap from '../../hooks/useMap'; import styles from './agentMarker.module.scss'; import Tooltip from '../Tooltip'; import { getNameInitials } from 'src/utils/commonUtils'; -import { AgentMarkerProps, ColorMap } from '../../constants/LiveLocationTrackerInterfaces'; -import { useSelector } from 'react-redux'; +import { + AgentMarkerProps, + ColorMap, + LOCATION_TYPE_FILTERS +} from '../../constants/LiveLocationTrackerInterfaces'; +import { useDispatch, useSelector } from 'react-redux'; import { RootState } from '../../../../store'; import { addClickstreamEvent } from 'src/service/clickStreamEventService'; import { AgentTrackingEvents } from 'src/service/clickStream.constant'; import AgentMarkerIcon from './AgentMarkerIcon'; import { shouldZoomIn, loadCustomPopup } from '../../utils'; import { ICustomPopup } from '../../types'; +import { AGENT_LIVE_LOCATION, PinColorMapping } from '../../constants/LiveLocatonTrackerConstants'; +import { setSelectedFeedback } from '../../reducers/LiveLocationTrackerSlice'; +import { createQueryParams, readQueryParams } from '@cp/src/utils/QueryParamsHelper'; +import { useNavigate } from 'react-router-dom'; export const colorMap: ColorMap = { yellow: { @@ -38,19 +46,11 @@ export interface InfoWindowRef { close: () => void; } -const AgentMarker = ({ - color, - position, - name, - lastUpdatedAt, - referenceId, - type, - lanNo, - interactionId, - interactionStatus, - activeCustomPopup, - refId -}: AgentMarkerProps) => { +export const AgentMarker = ({ agentLocation, activeCustomPopup, position }: AgentMarkerProps) => { + const { name, referenceId, type, lanNo, interactionId, activityLevel, location, zIndex } = + agentLocation; + const refId = referenceId || lanNo || interactionId || ''; + const color = PinColorMapping[activityLevel] ?? 'red'; const map = useMap(); const markerRef = useRef(null); const markerInstance: any = useRef(null); @@ -59,15 +59,24 @@ const AgentMarker = ({ const initials = getNameInitials(name); const isInfoWindowVisible = useRef(false); const customPopupRef = useRef(null); + const dispatch = useDispatch(); + const navigate = useNavigate(); + const { [AGENT_LIVE_LOCATION]: queryParams = {} } = readQueryParams(); - const { selectedAgent, isShowAllInfoWindow, userId, selectedFeedback } = useSelector( - (store: RootState) => ({ + const { selectedAgent, isShowAllInfoWindow, userId, selectedFeedback, agentAllocations } = + useSelector((store: RootState) => ({ selectedAgent: store?.liveLocationTracker?.selectedAgent, isShowAllInfoWindow: store?.liveLocationTracker?.showAllInfoWindows, userId: store?.common?.userData?.referenceId, - selectedFeedback: store?.liveLocationTracker?.selectedFeedback - }) - ); + selectedFeedback: store?.liveLocationTracker?.selectedFeedback, + agentAllocations: store?.liveLocationTracker?.agentAllocations?.data + })); + + const selectedFeedbackRef = useRef(selectedFeedback); + + useEffect(() => { + selectedFeedbackRef.current = selectedFeedback; + }, [selectedFeedback]); useEffect(() => { if ( @@ -103,6 +112,33 @@ const AgentMarker = ({ } }, [selectedFeedback]); + const feedbackClickHandler = () => { + if (!lanNo) { + return; + } + const selectedFeedback = selectedFeedbackRef.current; + const data = agentAllocations?.[lanNo]; + const isSelectedFeedbackClicked = selectedFeedback?.interactionId === interactionId; + dispatch( + isSelectedFeedbackClicked + ? setSelectedFeedback(null) + : setSelectedFeedback({ + lanNo, + interactionId, + feedbackLocation: location, + caseLocation: data?.location, + isSuspicious: type === LOCATION_TYPE_FILTERS.SUSPICIOUS_FEEDBACK + }) + ); + const newQueryParams = { + ...queryParams + }; + const url = createQueryParams({ + [AGENT_LIVE_LOCATION]: newQueryParams + }); + navigate(url); + }; + useEffect(() => { if (map?.state?.mapLoaderInstance) { map?.state?.mapLoaderInstance @@ -111,7 +147,8 @@ const AgentMarker = ({ markerInstance.current = new AdvancedMarkerElement({ position: position, map: map.state.mapInstance, - content: markerRef.current + content: markerRef.current, + zIndex }); const CustomPopup = loadCustomPopup(type); if (tooltipRef.current) { @@ -133,6 +170,12 @@ const AgentMarker = ({ name } }); + if ( + type === LOCATION_TYPE_FILTERS.GENUINE_FEEDBACK || + type === LOCATION_TYPE_FILTERS.SUSPICIOUS_FEEDBACK + ) { + feedbackClickHandler(); + } } else { addClickstreamEvent(AgentTrackingEvents.LH_AGENT_TRACKING_PIN_CLICKED, { userId, @@ -181,12 +224,8 @@ const AgentMarker = ({
diff --git a/src/pages/LiveLocationTracker/components/AgentsAccordion/AccordionBody.tsx b/src/pages/LiveLocationTracker/components/AgentsAccordion/AccordionBody.tsx index 250a0115..48fa8ce0 100644 --- a/src/pages/LiveLocationTracker/components/AgentsAccordion/AccordionBody.tsx +++ b/src/pages/LiveLocationTracker/components/AgentsAccordion/AccordionBody.tsx @@ -1,4 +1,3 @@ -import { BorderedInput } from '@navi/web-ui/lib/primitives'; import React, { useEffect, useMemo, useRef } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useNavigate } from 'react-router-dom'; @@ -15,7 +14,6 @@ import styles from './index.module.scss'; import { _map } from 'src/utils/commonUtils'; import { IFeedback, LOCATION_TYPE_FILTERS } from '../../constants/LiveLocationTrackerInterfaces'; import { setSelectedFeedback } from '../../reducers/LiveLocationTrackerSlice'; -import useMap from '../../hooks/useMap'; import DateTimePickerComponent from '@cp/src/components/DateTimePicker/DateTimePickerComponent'; import { DATE_TIME_TYPE } from '@cp/src/components/DateTimePicker/constants'; @@ -35,6 +33,7 @@ const AccordionBody = () => { const dispatch = useDispatch(); const navigate = useNavigate(); const polylineRef = useRef(null); + const feedbackRefs = useRef>({}); const { [AGENT_LIVE_LOCATION]: queryParams = {} } = readQueryParams(); @@ -86,6 +85,19 @@ const AccordionBody = () => { return lanKeys; }, [agentAllocations]); + useEffect(() => { + if (selectedFeedback && !queryParams?.SELECTED_FEEDBACK_ID) { + // scroll to the selected feedback view + const feedbackRef = feedbackRefs.current[selectedFeedback.lanNo]; + if (feedbackRef) { + feedbackRef.scrollIntoView({ + behavior: 'smooth', + block: 'start' + }); + } + } + }, [selectedFeedback, queryParams?.SELECTED_FEEDBACK_ID]); + const feedbackClickHandler = (lanNo: string, feedback: IFeedback) => { const data = agentAllocations?.[lanNo]; const isSelectedFeedbackClicked = selectedFeedback?.interactionId === feedback?.interactionId; @@ -103,7 +115,7 @@ const AccordionBody = () => { ); addClickstreamEvent( isSelectedFeedbackClicked - ? AgentTrackingEvents.LH_MAP_FEEDBACK_CLICKED + ? AgentTrackingEvents.LH_MAP_FEEDBACK_DOUBLE_CLICKED : AgentTrackingEvents.LH_MAP_FEEDBACK_CLICKED, { userId, @@ -129,7 +141,7 @@ const AccordionBody = () => { if (selectedAgent) { return ( - <> +
ACTIVITY LOG
@@ -143,18 +155,21 @@ const AccordionBody = () => { containerClasses={styles.activityDatePicker} />
- {agentAllocationsLoading ? null : lanKeys?.length ? ( - lanKeys.map(lanNo => ( - feedbackClickHandler(lanNo, feedback)} - /> - )) - ) : ( -
No Feedbacks Found
- )} - +
+ {agentAllocationsLoading ? null : lanKeys?.length ? ( + lanKeys.map(lanNo => ( + (feedbackRefs.current[lanNo] = el)} + lanNo={lanNo} + feedbackClickHandler={feedback => feedbackClickHandler(lanNo, feedback)} + /> + )) + ) : ( +
No Feedbacks Found
+ )} +
+
); } @@ -169,9 +184,11 @@ const AccordionBody = () => { ))}
{agentLocations?.length ? ( - agentLocations?.map(item => ( - - )) +
+ {agentLocations?.map(item => ( + + ))} +
) : (
No Agents Found
)} diff --git a/src/pages/LiveLocationTracker/components/AgentsAccordion/AgentDetail.tsx b/src/pages/LiveLocationTracker/components/AgentsAccordion/AgentDetail.tsx index 1b2fb0b4..c0eaf529 100644 --- a/src/pages/LiveLocationTracker/components/AgentsAccordion/AgentDetail.tsx +++ b/src/pages/LiveLocationTracker/components/AgentsAccordion/AgentDetail.tsx @@ -36,7 +36,7 @@ const AgentDetail = (props: AgentDetailProps) => { userId: state?.common?.userData?.referenceId })); const { selectedAgent } = liveLocationTracker || {}; - const { name = '', activityLevel, referenceId, lastUpdatedAt } = item || {}; + const { name = '', activityLevel, referenceId, lastUpdatedAt, totalAllocatedCases } = item || {}; const color = PinColorMapping[activityLevel]; @@ -133,6 +133,7 @@ const AgentDetail = (props: AgentDetailProps) => { last seen {date} {time} )} +
Allocated: {totalAllocatedCases || 0}
{showNextIcon && } diff --git a/src/pages/LiveLocationTracker/components/AgentsAccordion/FeedbackDetail.tsx b/src/pages/LiveLocationTracker/components/AgentsAccordion/FeedbackDetail.tsx index b601a87b..3f6c8738 100644 --- a/src/pages/LiveLocationTracker/components/AgentsAccordion/FeedbackDetail.tsx +++ b/src/pages/LiveLocationTracker/components/AgentsAccordion/FeedbackDetail.tsx @@ -1,5 +1,5 @@ +import React from 'react'; import { useSelector } from 'react-redux'; -import FeedbackTriangleIcon from 'src/assets/icons/FeedbackTriangleIcon'; import RedirectionIcon from 'src/assets/icons/RedirectionIcon'; import APP_ROUTES from 'src/layout/Routes'; import { TAB_KEYS } from 'src/pages/CaseDetails/constants'; @@ -20,7 +20,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from 'src/components/TooltipV import ChatBubbleExclamation from 'src/assets/images/icons/ChatBubbleExclamation'; import ChatBubble from 'src/assets/images/icons/ChatBubble'; -const FeedbackDetail = (props: FeedbackDetailProps) => { +const FeedbackDetail = React.forwardRef((props, ref) => { const { lanNo, feedbackClickHandler } = props; const { agentAllocations: { data: agentAllocations }, @@ -63,6 +63,7 @@ const FeedbackDetail = (props: FeedbackDetailProps) => { const isFeedbackSelected = selectedFeedback?.interactionId === feedback?.interactionId; return (
{ })} ); -}; +}); export default FeedbackDetail; diff --git a/src/pages/LiveLocationTracker/components/AgentsAccordion/index.module.scss b/src/pages/LiveLocationTracker/components/AgentsAccordion/index.module.scss index 78ded760..2a0647b5 100644 --- a/src/pages/LiveLocationTracker/components/AgentsAccordion/index.module.scss +++ b/src/pages/LiveLocationTracker/components/AgentsAccordion/index.module.scss @@ -1,5 +1,6 @@ .agentsAccordionContainer { width: 260px; + font-family: 'Inter'; .accordion { border-radius: 8px; @@ -19,10 +20,7 @@ .accordionBody { margin: 0; - } - - .content { - max-height: calc(100vh - 230px); + overflow-y: hidden; } } @@ -153,8 +151,6 @@ .dateFilterContainer { padding: 12px 12px 6px 12px; border-bottom: 1px solid var(--navi-color-gray-border); - position: sticky; - top: 0; background: var(--navi-color-gray-bg-primary); .activityLog { diff --git a/src/pages/LiveLocationTracker/components/GoogleMapsContainer/GoogleMapsContainer.module.scss b/src/pages/LiveLocationTracker/components/GoogleMapsContainer/GoogleMapsContainer.module.scss index 1278f2c5..3a186464 100644 --- a/src/pages/LiveLocationTracker/components/GoogleMapsContainer/GoogleMapsContainer.module.scss +++ b/src/pages/LiveLocationTracker/components/GoogleMapsContainer/GoogleMapsContainer.module.scss @@ -1,4 +1,4 @@ .googleMapContainer { width: 100%; - height: calc(100vh - 60px); + height: calc(100vh - 100px); // 100px is the height of the header } diff --git a/src/pages/LiveLocationTracker/components/LocationAgencySearch/index.module.scss b/src/pages/LiveLocationTracker/components/LocationAgencySearch/index.module.scss new file mode 100644 index 00000000..bf080a1b --- /dev/null +++ b/src/pages/LiveLocationTracker/components/LocationAgencySearch/index.module.scss @@ -0,0 +1,68 @@ +@import '../../../../assets/styles/animations'; + +.blurMapContainer { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 2; + + .blurMapImg { + object-fit: cover; + width: 100%; + height: 100%; + filter: blur(12.5px); + } +} + +.mapPlaceholderContainer { + padding: 20px 16px; + border-radius: 8px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + position: absolute; + left: 50%; + top: 25%; + transform: translate(-50%); + + span { + color: var(--black-base); + } +} + +.loader { + border: 8px solid var(--grayscale-background-secondary); + border-top: 8px solid var(--navi-color-blue-light); + border-radius: 50%; + width: 60px; + height: 60px; + animation: spin 2s linear infinite; +} + +.autoCompleteMainContainer { + width: 100%; +} + +.autoCompleteContainer { + background: white; + margin-top: 4px; +} + +.optionLabel { + font-size: 14px; + font-weight: 400; + line-height: 20px; + letter-spacing: -0.0125em; + color: var(--navi-color-gray-c1); + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; +} + +.selectPickerWrapper { + padding: 0; + max-height: calc((100vh - 100px - 25%) / 2); +} diff --git a/src/pages/LiveLocationTracker/components/LocationAgencySearch/index.tsx b/src/pages/LiveLocationTracker/components/LocationAgencySearch/index.tsx new file mode 100644 index 00000000..5bf96373 --- /dev/null +++ b/src/pages/LiveLocationTracker/components/LocationAgencySearch/index.tsx @@ -0,0 +1,72 @@ +import styles from './index.module.scss'; +import { Typography } from '@primitives'; +import { SelectPickerValue } from '@cp/src/components/interfaces'; +import { useNavigate } from 'react-router-dom'; +import { QueryParamTypeMapping } from '../../../ExternalDashboardSensei/constants'; +import { createQueryParams, readQueryParams } from '@cp/src/utils/QueryParamsHelper'; +import { SingleSelectAutoComplete } from '@navi/web-ui/lib/components'; +import { useDispatch, useSelector } from 'react-redux'; +import { RootState } from '@cp/src/store'; +import { addClickstreamEvent } from '@cp/src/service/clickStreamEventService'; +import { AgentTrackingEvents } from '@cp/src/service/clickStream.constant'; +import AllocationMapPlaceholder from '@cp/src/pages/MapAllocationView/components/AllocationMapPlaceholder'; +import { AGENT_LIVE_LOCATION } from '../../constants/LiveLocatonTrackerConstants'; +import { FilterTypes } from '../../constants/LiveLocationTrackerInterfaces'; +import { useEffect } from 'react'; +import { getFilterData } from '../../actions/LiveLocationTrackerActions'; + +const LocationAgencySearch = () => { + const navigate = useNavigate(); + const dispatch = useDispatch(); + const params = readQueryParams(); + const { filterTypes, filterData } = useSelector((state: RootState) => state.liveLocationTracker); + const { data = [] } = filterData['AGENCY']; + useEffect(() => { + // Get agency filter data + dispatch(getFilterData()); + }, []); + + const { caseAllocation } = useSelector((state: RootState) => ({ + caseAllocation: state.caseAllocation + })); + const { reportingAgencies } = caseAllocation || {}; + + const agencyDropdownHandler = (action: SelectPickerValue) => { + if (!action) return; + const queryParams = { ...params }; + + if (!queryParams?.[AGENT_LIVE_LOCATION]) queryParams[AGENT_LIVE_LOCATION] = {}; + + if (!queryParams[AGENT_LIVE_LOCATION]?.[FilterTypes.AGENCY]) { + queryParams[AGENT_LIVE_LOCATION][FilterTypes.AGENCY] = action; + } + + // addClickstreamEvent(AgentTrackingEvents.LH_MAP_AUTOCOMPLETE_FILTER_APPLIED, { + // value: action, + // page: ALLOCATION_PAGE + // }); + const updatedParams = createQueryParams(queryParams); + navigate(updatedParams); + }; + + return ( + + + Select an agency to view locations + +
{option.label}
} + /> +
+ ); +}; + +export default LocationAgencySearch; diff --git a/src/pages/LiveLocationTracker/components/MapPlaceholder/mapPlaceholder.module.scss b/src/pages/LiveLocationTracker/components/MapPlaceholder/mapPlaceholder.module.scss index 45ee24ed..2c1f5b49 100644 --- a/src/pages/LiveLocationTracker/components/MapPlaceholder/mapPlaceholder.module.scss +++ b/src/pages/LiveLocationTracker/components/MapPlaceholder/mapPlaceholder.module.scss @@ -1,10 +1,10 @@ .blurMapContainer { - position: absolute; + position: fixed; top: 0; left: 0; width: 100%; height: 100%; - z-index: 10; + z-index: var(--z-index-maps-loader-overlay); .blurMapImg { object-fit: cover; @@ -29,6 +29,9 @@ } .blurImageWrapper { + position: absolute; + top: 0px; + left: 0px; z-index: 2; } diff --git a/src/pages/LiveLocationTracker/components/MapView/index.tsx b/src/pages/LiveLocationTracker/components/MapView/index.tsx index 32db79a6..d95ab18d 100644 --- a/src/pages/LiveLocationTracker/components/MapView/index.tsx +++ b/src/pages/LiveLocationTracker/components/MapView/index.tsx @@ -4,11 +4,7 @@ import AgentMarker from '../AgentMarker'; import useMap from '../../hooks/useMap'; import { useSelector } from 'react-redux'; import { RootState } from 'src/store'; -import { - AGENT_LIVE_LOCATION, - FilterMap, - PinColorMapping -} from '../../constants/LiveLocatonTrackerConstants'; +import { AGENT_LIVE_LOCATION, FilterMap } from '../../constants/LiveLocatonTrackerConstants'; import styles from './index.module.scss'; import { readQueryParams } from 'src/utils/QueryParamsHelper'; import { @@ -18,8 +14,6 @@ import { } from '../../constants/LiveLocationTrackerInterfaces'; import { INHOUSE_AGENCY_CODE } from 'src/components/constant'; import MapPlaceholder from '../MapPlaceholder'; -import AgentsAccordion from '../AgentsAccordion'; -import PinFilters from '../PinFilters'; import { ICustomPopup } from '../../types'; const defaultMapOptions = { @@ -48,7 +42,6 @@ function MapView() { const { filterTypes, loadingFilters, - selectedAgent, agentLocations, mapLocations, agentLocationsLoading, @@ -84,7 +77,7 @@ function MapView() { map.state.mapInstance.setCenter(bounds.getCenter()); //or use custom center map.state.mapInstance.fitBounds(bounds); const currentZoomLevel = map.state.mapInstance.getZoom(); - const newLevel = currentZoomLevel - 1; + const newLevel = currentZoomLevel - 2; map.state.mapInstance.setZoom(newLevel); }); } @@ -165,17 +158,19 @@ function MapView() { }, [queryParams?.DATE]); useEffect(() => { - if (!queryParams.SELECTED_FEEDBACK_ID && polylineRef.current) { + if (!queryParams?.SELECTED_FEEDBACK_ID && polylineRef.current) { polylineRef.current.setMap(null); return; } - zoomOverFeedback(selectedFeedback?.feedbackLocation, selectedFeedback?.caseLocation); - drawLineBetweenFeedbackAndCase( - selectedFeedback?.feedbackLocation, - selectedFeedback?.caseLocation, - selectedFeedback?.isSuspicious - ); - }, [queryParams?.SELECTED_FEEDBACK_ID]); + if (queryParams?.SELECTED_FEEDBACK_ID) { + zoomOverFeedback(selectedFeedback?.feedbackLocation, selectedFeedback?.caseLocation); + drawLineBetweenFeedbackAndCase( + selectedFeedback?.feedbackLocation, + selectedFeedback?.caseLocation, + selectedFeedback?.isSuspicious + ); + } + }, [queryParams?.SELECTED_FEEDBACK_ID, selectedFeedback]); useEffect(() => { if (!mapLocations?.length) { @@ -212,66 +207,39 @@ function MapView() { const showBlurMap = !mapLocations?.length && !loadingFilters && !isFiltersSelected(); - const googleMapsContainer = useMemo( - () => ( + const googleMapsContainer = useMemo(() => { + return (
{mapLocations?.map(agentLocation => { - const { - location, - name = '', - activityLevel, - referenceId, - lastUpdatedAt, - type, - lanNo, - interactionId, - interactionStatus - } = agentLocation || {}; + const { location } = agentLocation || {}; const { latitude: lat, longitude: lng } = location || {}; if (!lat || !lng) { return null; } - const refId = referenceId || lanNo || interactionId || ''; - const color = PinColorMapping[activityLevel] ?? 'red'; return ( ); })}
- ), - [mapLocations] - ); + ); + }, [mapLocations]); return ( -
+
{googleMapsContainer} - {filteredAgentLocations?.length === 0 && !agentLocationsLoading ? ( + {!filteredAgentLocations?.length && !agentLocationsLoading ? ( ) : null} {showBlurMap && !agentLocationsLoading ? ( ) : null} - {agentLocations?.length && ( -
- -
- )} - {selectedAgent && }
); } diff --git a/src/pages/LiveLocationTracker/components/PinFilters/index.module.scss b/src/pages/LiveLocationTracker/components/PinFilters/index.module.scss index 82daa4b4..3d206dde 100644 --- a/src/pages/LiveLocationTracker/components/PinFilters/index.module.scss +++ b/src/pages/LiveLocationTracker/components/PinFilters/index.module.scss @@ -1,7 +1,4 @@ .pinFiltersContainer { - position: absolute; - top: 16px; - left: 292px; // width of Agents Panel background-color: var(--bg-primary); padding: 8px 8px 8px 12px; border-radius: 8px; diff --git a/src/pages/LiveLocationTracker/components/PinFilters/index.tsx b/src/pages/LiveLocationTracker/components/PinFilters/index.tsx index 20164e96..87bd3e63 100644 --- a/src/pages/LiveLocationTracker/components/PinFilters/index.tsx +++ b/src/pages/LiveLocationTracker/components/PinFilters/index.tsx @@ -1,4 +1,4 @@ -import { useEffect } from 'react'; +import React, { useEffect, useMemo } from 'react'; import styles from './index.module.scss'; import cx from 'classnames'; import { createQueryParams, readQueryParams } from 'src/utils/QueryParamsHelper'; @@ -25,11 +25,20 @@ const PinFilters = () => { const { [AGENT_LIVE_LOCATION]: queryParams = {} } = readQueryParams(); const navigate = useNavigate(); const dispatch = useDispatch(); + // map of selected filters + const locationTypeParams = useMemo(() => { + const locationTypeArray = queryParams?.LOCATION_TYPE?.split(',') || []; + const locationTypeParams: Record = {}; + locationTypeArray.forEach((locationType: LOCATION_TYPE_FILTERS) => { + locationTypeParams[locationType] = true; + }); + return locationTypeParams; + }, [queryParams?.LOCATION_TYPE]); useEffect(() => { if (!agentLocationHistory?.loading && !agentAllocations?.loading) { const { data, disabledFilters } = getMapLocations( - queryParams?.LOCATION_TYPE, + locationTypeParams, agentAllocations?.data, agentLocationHistory?.data ); @@ -48,13 +57,42 @@ const PinFilters = () => { const filterClickHandler = (value: string) => { if (disabledFilters[value]) return; + + let updatedFilters = queryParams?.LOCATION_TYPE; + + if (value === LOCATION_TYPE_FILTERS.ALL && updatedFilters === LOCATION_TYPE_FILTERS.ALL) { + return; + } + addClickstreamEvent(AgentTrackingEvents.LH_MAP_FILTER_CLICKED, { userId, agentId: queryParams?.AGENTID, filterValue: value }); + + if (locationTypeParams?.[value]) { + // remove filter if already applied + updatedFilters = updatedFilters?.replace(value, ''); + } else { + if (value === LOCATION_TYPE_FILTERS.ALL) { + // remove other filter if all filter is applied + updatedFilters = LOCATION_TYPE_FILTERS.ALL; + } else { + // remove all filter if any other filter is applied + updatedFilters = updatedFilters?.replace(LOCATION_TYPE_FILTERS.ALL, ''); + updatedFilters += `,${value}`; + } + } + + // remove leading and trailing commas + updatedFilters = updatedFilters?.replace(/^,+|,+$/g, ''); + const url = createQueryParams({ - [AGENT_LIVE_LOCATION]: { ...queryParams, LOCATION_TYPE: value, SELECTED_FEEDBACK_ID: '' } + [AGENT_LIVE_LOCATION]: { + ...queryParams, + LOCATION_TYPE: updatedFilters || LOCATION_TYPE_FILTERS.ALL, + SELECTED_FEEDBACK_ID: '' + } }); navigate(url); }; @@ -63,10 +101,10 @@ const PinFilters = () => {
Filter by:
{locationsPinFilters.map(filter => ( - <> +
filterClickHandler(filter?.value)} @@ -75,7 +113,7 @@ const PinFilters = () => {
{filter.label}
{filter.value === LOCATION_TYPE_FILTERS.ALL &&
} - + ))}
); diff --git a/src/pages/LiveLocationTracker/components/Tooltip/index.tsx b/src/pages/LiveLocationTracker/components/Tooltip/index.tsx index 961e145e..56eb5433 100644 --- a/src/pages/LiveLocationTracker/components/Tooltip/index.tsx +++ b/src/pages/LiveLocationTracker/components/Tooltip/index.tsx @@ -1,46 +1,83 @@ +import React from 'react'; import { Typography } from '@navi/web-ui/lib/primitives'; import styles from './tooltip.module.scss'; import { forwardRef } from 'react'; import { DateFormat, dateFormat, formatDate, isToday } from 'src/utils/DateHelper'; -import { LOCATION_TYPE_FILTERS } from '../../constants/LiveLocationTrackerInterfaces'; +import { + IAgentLocation, + LOCATION_TYPE_FILTERS +} from '../../constants/LiveLocationTrackerInterfaces'; import RedirectionIcon from 'src/assets/icons/RedirectionIcon'; -import { useSelector } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import APP_ROUTES from 'src/layout/Routes'; import { TAB_KEYS } from 'src/pages/CaseDetails/constants'; import { RootState } from 'src/store'; import { interpolatePathParams } from 'src/utils/interpolate'; import { CloseIcon } from '@navi/web-ui/lib/icons'; +import { getMaxInputDate } from '../../utils'; +import { createQueryParams, readQueryParams } from '@cp/src/utils/QueryParamsHelper'; +import { AGENT_LIVE_LOCATION } from '../../constants/LiveLocatonTrackerConstants'; +import { useNavigate } from 'react-router-dom'; +import { setSelectedAgent } from '../../reducers/LiveLocationTrackerSlice'; +import { + getAgentAllocations, + getAgentLocationHistory +} from '../../actions/LiveLocationTrackerActions'; type ToolTipProps = { - name: string; - lastUpdateActivity: string; - style?: any; - type?: LOCATION_TYPE_FILTERS; - lanNo?: string; - interactionStatus?: string; + agentLocation: IAgentLocation; + style?: React.CSSProperties; closeTooltip: () => void; }; -function Tooltip(props: ToolTipProps, ref: any) { +const Tooltip = forwardRef((props: ToolTipProps, ref: any) => { + const { agentLocation, style, closeTooltip }: ToolTipProps = props; const { name, - lastUpdateActivity, - style, + lastUpdatedAt, type, lanNo, interactionStatus, - closeTooltip - }: ToolTipProps = props; - - const date = isToday(lastUpdateActivity) - ? 'Today' - : formatDate(lastUpdateActivity, DateFormat.DD_MMM); - const time = dateFormat(new Date(lastUpdateActivity), DateFormat.HH_mm_ampm) || '---'; + addressText, + phoneNumber, + referenceId + } = agentLocation; + const date = isToday(lastUpdatedAt) ? 'Today' : formatDate(lastUpdatedAt, DateFormat.DD_MMM); + const time = dateFormat(new Date(lastUpdatedAt), DateFormat.HH_mm_ampm) || '---'; + const { liveLocationTracker, userId } = useSelector((state: RootState) => ({ + liveLocationTracker: state.liveLocationTracker, + userId: state?.common?.userData?.referenceId + })); + const { selectedAgent } = liveLocationTracker || {}; const { agentAllocations: { data: agentAllocations } } = useSelector((state: RootState) => state.liveLocationTracker); + const { [AGENT_LIVE_LOCATION]: queryParams = {} } = readQueryParams(); + const navigate = useNavigate(); + const dispatch = useDispatch(); + + const selectAgentHandler = () => { + if (!selectedAgent) { + const maxInputDate = getMaxInputDate('YYYY-MM-DD'); + const payload = { date: maxInputDate, referenceId }; + + const url = createQueryParams({ + [AGENT_LIVE_LOCATION]: { + ...queryParams, + AGENTID: referenceId, + LOCATION_TYPE: LOCATION_TYPE_FILTERS.ALL, + DATE: maxInputDate + } + }); + navigate(url); + dispatch(setSelectedAgent(agentLocation)); + dispatch(getAgentLocationHistory(payload)); + dispatch(getAgentAllocations(payload)); + } + }; + const viewCaseHandler = () => { if (lanNo) { const data = agentAllocations?.[lanNo]; @@ -68,9 +105,12 @@ function Tooltip(props: ToolTipProps, ref: any) { {lanNo} + + {addressText} +
View Case
- +
); @@ -82,8 +122,21 @@ function Tooltip(props: ToolTipProps, ref: any) {
{name && ( - - {name} +
+ + {name} + + +
+ )} + {phoneNumber && ( + + {phoneNumber} )} {interactionStatus && ( @@ -98,6 +151,6 @@ function Tooltip(props: ToolTipProps, ref: any) { )}
); -} +}); -export default forwardRef(Tooltip); +export default Tooltip; diff --git a/src/pages/LiveLocationTracker/components/Tooltip/tooltip.module.scss b/src/pages/LiveLocationTracker/components/Tooltip/tooltip.module.scss index 44257539..7722f68e 100644 --- a/src/pages/LiveLocationTracker/components/Tooltip/tooltip.module.scss +++ b/src/pages/LiveLocationTracker/components/Tooltip/tooltip.module.scss @@ -4,17 +4,15 @@ border-radius: 8px; display: flex; flex-direction: column; - align-items: center; justify-content: center; - text-align: center; .nameText { font-size: 17px; font-weight: 500; line-height: 24px; letter-spacing: -0.2px; - margin-bottom: 5px; - margin-right: 16px; + text-align: center; + text-wrap: nowrap; } .lastUpdatedAt { @@ -24,7 +22,8 @@ line-height: 20px; letter-spacing: -0.13px; color: var(--navi-color-gray-c2); - margin-right: 16px; + padding-right: 16px; + text-align: center; } .casesNameText { @@ -33,11 +32,11 @@ font-weight: 500; line-height: 18px; letter-spacing: -0.12px; - margin-right: 16px; + padding-right: 18px; } .lanNo { - color: var(--navi-color-gray-c3); + color: var(--navi-color-gray-c2); font-size: 12px; font-weight: 400; line-height: 18px; @@ -50,13 +49,33 @@ font-weight: 400; line-height: 18px; letter-spacing: -0.12px; - margin-right: 16px; + text-align: center; + margin-right: 8px; + } + + .phoneNumber { + color: var(--navi-color-gray-c2); + font-size: 12px; + font-weight: 400; + line-height: 18px; + letter-spacing: -0.12px; + text-align: center; + } + + .addressText { + color: var(--navi-color-gray-c3); + font-size: 12px; + font-weight: 400; + line-height: 18px; + margin-top: 4px; + letter-spacing: -0.12px; } .viewCaseCtaWrapper { display: flex; align-items: center; - justify-content: center; + margin-top: 2px; + width: fit-content; cursor: pointer; } @@ -71,7 +90,7 @@ .closeIcon { position: absolute; - padding: 8px; + padding: 8px 8px 4px 4px; top: 2px; right: 0px; cursor: pointer; diff --git a/src/pages/LiveLocationTracker/components/TopBar/Filters.tsx b/src/pages/LiveLocationTracker/components/TopBar/Filters.tsx index 3390c5a6..b49a44f3 100644 --- a/src/pages/LiveLocationTracker/components/TopBar/Filters.tsx +++ b/src/pages/LiveLocationTracker/components/TopBar/Filters.tsx @@ -1,17 +1,13 @@ -import { useEffect, useMemo } from 'react'; +import { useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import { - getAgentsLocations, - getFilterData, - getFilterTypes -} from '../../actions/LiveLocationTrackerActions'; +import { getFilterData } from '../../actions/LiveLocationTrackerActions'; import { RootState } from 'src/store'; import { FilterTypes } from '../../constants/LiveLocationTrackerInterfaces'; import { _map } from 'src/utils/commonUtils'; import styles from './TopBar.module.scss'; import { FilterMap, AGENT_LIVE_LOCATION } from '../../constants/LiveLocatonTrackerConstants'; import { createQueryParams, readQueryParams } from 'src/utils/QueryParamsHelper'; -import { useNavigate, useSearchParams } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import { setAgentLocations, setFilterData, @@ -19,73 +15,22 @@ import { setSelectedAgent } from '../../reducers/LiveLocationTrackerSlice'; import SingleAutocompleteDropdown from 'src/components/AutocompleteDropdown/SingleAutocompleteDropdown'; -import { INHOUSE_AGENCY_CODE } from 'src/components/constant'; import { addClickstreamEvent } from 'src/service/clickStreamEventService'; import { AgentTrackingEvents } from 'src/service/clickStream.constant'; const Filters = () => { const dispatch = useDispatch(); - const { filterTypes, filterData, agentLocations } = useSelector( - (state: RootState) => state.liveLocationTracker - ); + const { filterTypes, filterData } = useSelector((state: RootState) => state.liveLocationTracker); const userId = useSelector((state: RootState) => state.common.userData?.referenceId); - const [searchParams] = useSearchParams(); const { filters } = filterTypes; const { [AGENT_LIVE_LOCATION]: queryParams = {} } = readQueryParams(); const navigate = useNavigate(); - const pinsPayload = useMemo(() => { - const selectedAgency = - queryParams[FilterTypes.AGENCY] || filterData[FilterTypes.AGENCY]?.data[0]?.value; - const selectedTeamLead = queryParams[FilterTypes.TEAM_LEAD]; - return { - agencyCodes: [selectedAgency], - teamLeadReferenceIds: selectedTeamLead ? [selectedTeamLead] : [] - }; - }, [searchParams]); - useEffect(() => { // Get agency filter data dispatch(getFilterData()); }, [filterTypes]); - useEffect(() => { - if (!filters?.length) { - dispatch(getFilterTypes()); - return; - } - - const applyFilterRecursively = (filterType: FilterTypes) => { - const selectedFilter = queryParams[filterType]; - const { nextFilter } = FilterMap[filterType]; - - if (!selectedFilter) { - return; - } - - // If next filter is not selected or not in the list of filters, we need to fetch the pins data - if (!nextFilter || !filters.includes(nextFilter)) { - dispatch(getAgentsLocations(pinsPayload)); - return; - } - - if (filterType === FilterTypes.AGENCY) { - dispatch(getAgentsLocations(pinsPayload)); - } - - const payload = { - type: nextFilter, - agencyCodes: [selectedFilter] - }; - dispatch(getFilterData(payload)); - - // recursively call the function to apply the next filter - applyFilterRecursively(nextFilter); - }; - - applyFilterRecursively(FilterTypes.AGENCY); - }, [queryParams?.AGENCY, queryParams?.TEAM_LEAD, filters]); - const handleFilterChange = (value: string, filterType: FilterTypes) => { dispatch(setMapLocations({ data: [] })); const nextFilter = FilterMap[filterType]?.nextFilter; @@ -173,6 +118,7 @@ const Filters = () => { containerClasses={styles.dropdown} disabled={disabled} sortOptions + hideCloseOption={filterType === FilterTypes.AGENCY} /> ); })} diff --git a/src/pages/LiveLocationTracker/components/TopBar/TopBar.module.scss b/src/pages/LiveLocationTracker/components/TopBar/TopBar.module.scss index cbc2cddd..062ddc5b 100644 --- a/src/pages/LiveLocationTracker/components/TopBar/TopBar.module.scss +++ b/src/pages/LiveLocationTracker/components/TopBar/TopBar.module.scss @@ -67,12 +67,11 @@ .filters { display: flex; - align-items: center; - justify-content: center; gap: 12px; .dropdown { background-color: var(--bg-primary); + box-shadow: var(--box-shadow-3) !important; width: 250px; height: 36px; } diff --git a/src/pages/LiveLocationTracker/components/TopBar/index.tsx b/src/pages/LiveLocationTracker/components/TopBar/index.tsx index 837f699d..b5133441 100644 --- a/src/pages/LiveLocationTracker/components/TopBar/index.tsx +++ b/src/pages/LiveLocationTracker/components/TopBar/index.tsx @@ -15,17 +15,12 @@ import { createQueryParams, readQueryParams } from '../../../../utils/QueryParam import { getAgentsLocations } from '../../actions/LiveLocationTrackerActions'; import { RootState } from '../../../../store'; import dayjs from 'dayjs'; -import relativeTime from 'dayjs/plugin/relativeTime'; -import isToday from 'dayjs/plugin/isToday'; import usePolling from '../../../../hooks/usePolling'; import { getAgentDetails } from '../../utils'; import { resetMapData, setSelectedAgent } from '../../reducers/LiveLocationTrackerSlice'; import { INHOUSE_AGENCY_CODE } from 'src/components/constant'; import { useMemo } from 'react'; -dayjs.extend(relativeTime); -dayjs.extend(isToday); - function TopBar() { const navigate = useNavigate(); const dispatch = useDispatch(); diff --git a/src/pages/LiveLocationTracker/constants/LiveLocationTrackerInterfaces.ts b/src/pages/LiveLocationTracker/constants/LiveLocationTrackerInterfaces.ts index fbd56571..c61cbe11 100644 --- a/src/pages/LiveLocationTracker/constants/LiveLocationTrackerInterfaces.ts +++ b/src/pages/LiveLocationTracker/constants/LiveLocationTrackerInterfaces.ts @@ -43,6 +43,7 @@ export interface IAgentAllocation { customerName: string; location: ILocation; feedbacks: IFeedback[]; + addressText: string; } export interface ILocation { @@ -54,6 +55,7 @@ export interface IAgentLocationHistory { referenceId: string; location: ILocation; epochTimestamp: number; + zIndex?: number; } export interface IAgentLocation { @@ -68,6 +70,8 @@ export interface IAgentLocation { lanNo?: string; interactionId?: string; interactionStatus?: string; + addressText?: string; + totalAllocatedCases: number; } interface IFilterTypes { @@ -91,6 +95,8 @@ export interface MapPinLocation { interactionId?: string; interactionStatus?: string; referenceId?: string; + addressText?: string; + zIndex?: number; } export enum FilterTypes { @@ -142,20 +148,12 @@ export type ColorMap = Record< >; export interface AgentMarkerProps { - color: string; - name: string; - lastUpdatedAt: string; position: { lat: number; lng: number; }; - referenceId: string; - type?: LOCATION_TYPE_FILTERS; - lanNo?: string; - interactionId?: string; - interactionStatus?: string; activeCustomPopup: React.MutableRefObject; - refId: string; + agentLocation: IAgentLocation; } export enum LOCATION_TYPE_FILTERS { diff --git a/src/pages/LiveLocationTracker/index.module.scss b/src/pages/LiveLocationTracker/index.module.scss index 7bac8f1d..6b3bf5b5 100644 --- a/src/pages/LiveLocationTracker/index.module.scss +++ b/src/pages/LiveLocationTracker/index.module.scss @@ -2,7 +2,31 @@ position: relative; .overlay { - z-index: 10; + z-index: var(--z-index-maps-loader-overlay); + width: 100%; + height: 100%; + position: fixed; + } + + .agentFilters { + position: absolute; + top: 24px; + left: 298px; + z-index: var(--z-index-map-options); + } + + .agentAccordion { + position: absolute; + top: 24px; + left: 24px; + z-index: var(--z-index-map-options); + } + + .pinFilters { + position: absolute; + top: 24px; + left: 298px; + z-index: var(--z-index-map-options); } } diff --git a/src/pages/LiveLocationTracker/index.tsx b/src/pages/LiveLocationTracker/index.tsx index ef0cb356..b48bad62 100644 --- a/src/pages/LiveLocationTracker/index.tsx +++ b/src/pages/LiveLocationTracker/index.tsx @@ -1,17 +1,28 @@ -import TopBar from './components/TopBar'; import MapView from './components/MapView'; import Footer from './components/Footer/Footer'; import styles from './index.module.scss'; import Loader from 'src/components/Loader/Loader'; import { RootState } from 'src/store'; -import { useSelector } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import cx from 'classnames'; -import { useEffect } from 'react'; +import { useEffect, useMemo } from 'react'; import { addClickstreamEvent } from 'src/service/clickStreamEventService'; import { AgentTrackingEvents } from 'src/service/clickStream.constant'; import MapPlaceholder from './components/MapPlaceholder'; import { readQueryParams } from 'src/utils/QueryParamsHelper'; -import { AGENT_LIVE_LOCATION } from './constants/LiveLocatonTrackerConstants'; +import { AGENT_LIVE_LOCATION, FilterMap } from './constants/LiveLocatonTrackerConstants'; +import Filters from './components/TopBar/Filters'; +import AgentsAccordion from './components/AgentsAccordion'; +import PinFilters from './components/PinFilters'; +import { + getAgentsLocations, + getFilterData, + getFilterTypes +} from './actions/LiveLocationTrackerActions'; +import { FilterTypes } from './constants/LiveLocationTrackerInterfaces'; +import { useSearchParams } from 'react-router-dom'; +import { resetMapData } from './reducers/LiveLocationTrackerSlice'; +import LocationAgencySearch from './components/LocationAgencySearch'; function LiveLocationTracker() { const { @@ -20,20 +31,42 @@ function LiveLocationTracker() { selectedAgent, agentLocationHistory: { loading: isAgentLocationHistoryloading }, agentAllocations: { loading: isAgentAllocationsloading }, - agentLocationsLoading + agentLocations, + agentLocationsLoading, + filterTypes, + filterData } = useSelector((state: RootState) => ({ loadingFilters: state.liveLocationTracker.loadingFilters, userId: state?.common?.userData?.referenceId, selectedAgent: state.liveLocationTracker.selectedAgent, agentLocationHistory: state.liveLocationTracker.agentLocationHistory, agentAllocations: state.liveLocationTracker.agentAllocations, - agentLocationsLoading: state.liveLocationTracker.agentLocationsLoading + agentLocationsLoading: state.liveLocationTracker.agentLocationsLoading, + agentLocations: state.liveLocationTracker.agentLocations, + filterTypes: state.liveLocationTracker.filterTypes, + filterData: state.liveLocationTracker.filterData })); - + const { filters } = filterTypes || {}; + const dispatch = useDispatch(); + const [searchParams] = useSearchParams(); const { [AGENT_LIVE_LOCATION]: queryParams = {} } = readQueryParams(); + const pinsPayload = useMemo(() => { + const selectedAgency = + queryParams[FilterTypes.AGENCY] || filterData[FilterTypes.AGENCY]?.data[0]?.value; + const selectedTeamLead = queryParams[FilterTypes.TEAM_LEAD]; + return { + agencyCodes: [selectedAgency], + teamLeadReferenceIds: selectedTeamLead ? [selectedTeamLead] : [] + }; + }, [searchParams]); + useEffect(() => { addClickstreamEvent(AgentTrackingEvents.LH_AGENT_TRACKING_PAGE_LOAD, { userId }); + return () => { + // reset map data on unmount + dispatch(resetMapData()); + }; }, []); useEffect(() => { @@ -41,18 +74,78 @@ function LiveLocationTracker() { localStorage.setItem('live-location-tracker-params', window.location.search); }, [queryParams]); + useEffect(() => { + if (!filters?.length) { + dispatch(getFilterTypes()); + return; + } + + const applyFilterRecursively = (filterType: FilterTypes) => { + const selectedFilter = queryParams[filterType]; + const { nextFilter } = FilterMap[filterType]; + + if (!selectedFilter) { + return; + } + + // If next filter is not selected or not in the list of filters, we need to fetch the pins data + if (!nextFilter || !filters.includes(nextFilter)) { + dispatch(getAgentsLocations(pinsPayload)); + return; + } + + if (filterType === FilterTypes.AGENCY) { + dispatch(getAgentsLocations(pinsPayload)); + } + + const payload = { + type: nextFilter, + agencyCodes: [selectedFilter] + }; + dispatch(getFilterData(payload)); + + // recursively call the function to apply the next filter + applyFilterRecursively(nextFilter); + }; + + applyFilterRecursively(FilterTypes.AGENCY); + }, [queryParams?.AGENCY, queryParams?.TEAM_LEAD, filters]); + + const mapLoading = + isAgentAllocationsloading || isAgentLocationHistoryloading || agentLocationsLoading; + + if (!queryParams?.AGENCY) + return ( +
+ +
+ ); return (
- + {!selectedAgent && !mapLoading ? ( +
+ +
+ ) : null} + {!mapLoading ? ( +
+ +
+ ) : null} + {selectedAgent && !mapLoading ? ( +
+ +
+ ) : null}