TP-34788 | Cosmos for AM/TLs
This commit is contained in:
7
App.tsx
7
App.tsx
@@ -120,11 +120,14 @@ const App = () => {
|
||||
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<PersistGate loading={<FullScreenLoader loading />} persistor={persistor}>
|
||||
<PersistGate
|
||||
loading={<FullScreenLoader loading isTranslucent={false} />}
|
||||
persistor={persistor}
|
||||
>
|
||||
<NavigationContainer ref={navigationRef}>
|
||||
<StatusBar backgroundColor={COLORS.BACKGROUND.INDIGO_DARK} />
|
||||
<SuspenseLoader
|
||||
fallBack={<FullScreenLoader loading />}
|
||||
fallBack={<FullScreenLoader loading isTranslucent={false} />}
|
||||
loading={!isGlobalDocumentMapLoaded}
|
||||
children={
|
||||
<ErrorBoundary>{permissions ? <AuthRouter /> : <Permissions />}</ErrorBoundary>
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
"@react-navigation/native": "6.1.4",
|
||||
"@react-navigation/native-stack": "6.9.4",
|
||||
"@reduxjs/toolkit": "1.9.1",
|
||||
"@sanar/react-native-highlight-text": "^1.0.2",
|
||||
"@sentry/react-native": "5.5.0",
|
||||
"@shopify/flash-list": "1.4.3",
|
||||
"@supersami/rn-foreground-service": "^2.1.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ToastMessages } from './../screens/allCases/constants';
|
||||
import 'react-native-get-random-values';
|
||||
import { IUser, setAuthData } from '../reducer/userSlice';
|
||||
import { IUser, IUserRole, setAgentRole, setAuthData } from '../reducer/userSlice';
|
||||
import axiosInstance, { ApiKeys, API_STATUS_CODE, getApiUrl } from '../components/utlis/apiHelper';
|
||||
import {
|
||||
resetLoginForm,
|
||||
@@ -115,6 +115,7 @@ export const verifyGoogleSignIn = (idToken: string) => async (dispatch: AppDispa
|
||||
});
|
||||
dispatch(setVerifyOTPSuccess('Login Successfully!'));
|
||||
dispatch(resetLoginForm());
|
||||
dispatch(getAgentDetail());
|
||||
}
|
||||
} catch (error: GenericType) {
|
||||
await handleGoogleLogout();
|
||||
@@ -157,6 +158,7 @@ export const verifyOTP =
|
||||
);
|
||||
dispatch(setVerifyOTPSuccess('OTP verified'));
|
||||
dispatch(resetLoginForm());
|
||||
dispatch(getAgentDetail());
|
||||
})
|
||||
.catch((err) => {
|
||||
dispatch(setVerifyOTPError('Invalid OTP entered. Kindly try again'));
|
||||
@@ -229,6 +231,7 @@ export const handleImpersonatedUserLogin =
|
||||
isImpersonated: true,
|
||||
})
|
||||
);
|
||||
dispatch(getAgentDetail());
|
||||
successCallback?.();
|
||||
})
|
||||
.catch((err) => {
|
||||
@@ -241,3 +244,14 @@ export const handleImpersonatedUserLogin =
|
||||
})
|
||||
.finally(() => finallyCallback?.());
|
||||
};
|
||||
|
||||
export const getAgentDetail = () => (dispatch: AppDispatch) => {
|
||||
const url = getApiUrl(ApiKeys.GET_AGENT_DETAIL);
|
||||
return axiosInstance.get(url).then((response) => {
|
||||
if (response.status === API_STATUS_CODE.OK) {
|
||||
const roles = response?.data?.roles || [];
|
||||
const isTeamLead = roles?.includes(IUserRole.ROLE_TEAM_LEAD);
|
||||
dispatch(setAgentRole(isTeamLead));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
19
src/action/reporteesActions.ts
Normal file
19
src/action/reporteesActions.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import axiosInstance, { ApiKeys, getApiUrl } from '../components/utlis/apiHelper';
|
||||
import { setReporteesList, setReporteesLoading } from '../reducer/reporteesSlice';
|
||||
import { AppDispatch } from '../store/store';
|
||||
|
||||
export const getAgentsList = () => (dispatch: AppDispatch) => {
|
||||
const url = getApiUrl(ApiKeys.REPORTEES); //, null, {pageNo: 1, pageSize: 10, fetchAll: 'true'});
|
||||
dispatch(setReporteesLoading(true));
|
||||
axiosInstance
|
||||
.get(url)
|
||||
.then((res) => {
|
||||
const reporteesList = res.data?.reportees;
|
||||
if (reporteesList) {
|
||||
dispatch(setReporteesList(reporteesList));
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
dispatch(setReporteesLoading(false));
|
||||
});
|
||||
};
|
||||
@@ -55,6 +55,7 @@ const TrackingComponent: React.FC<ITrackingComponent> = ({ children }) => {
|
||||
const isOnline = useIsOnline();
|
||||
const dispatch = useAppDispatch();
|
||||
const appState = useRef(AppState.currentState);
|
||||
const isTeamLead = useAppSelector((state) => state.user.isTeamLead);
|
||||
|
||||
const {
|
||||
referenceId,
|
||||
@@ -193,12 +194,6 @@ const TrackingComponent: React.FC<ITrackingComponent> = ({ children }) => {
|
||||
delay: 3 * MILLISECONDS_IN_A_MINUTE, // 3 minutes
|
||||
onLoop: true,
|
||||
},
|
||||
{
|
||||
taskId: FOREGROUND_TASKS.FIRESTORE_FALLBACK,
|
||||
task: handleGetCaseSyncStatus,
|
||||
delay: 5 * MILLISECONDS_IN_A_MINUTE, // 5 minutes
|
||||
onLoop: true,
|
||||
},
|
||||
{
|
||||
taskId: FOREGROUND_TASKS.UPDATE_AGENT_ACTIVENESS,
|
||||
task: handleUpdateActiveness,
|
||||
@@ -207,6 +202,15 @@ const TrackingComponent: React.FC<ITrackingComponent> = ({ children }) => {
|
||||
},
|
||||
];
|
||||
|
||||
if (!isTeamLead) {
|
||||
tasks.push({
|
||||
taskId: FOREGROUND_TASKS.FIRESTORE_FALLBACK,
|
||||
task: handleGetCaseSyncStatus,
|
||||
delay: 5 * MILLISECONDS_IN_A_MINUTE, // 5 minutes
|
||||
onLoop: true,
|
||||
});
|
||||
}
|
||||
|
||||
const handleDataSync = () => {
|
||||
if (!isOnline) {
|
||||
return;
|
||||
|
||||
@@ -54,6 +54,8 @@ export enum ApiKeys {
|
||||
GLOBAL_CONFIG = 'GLOBAL_CONFIG',
|
||||
UPLOAD_IMAGE_ID = 'UPLOAD_IMAGE_ID',
|
||||
GET_DOCUMENTS = 'GET_DOCUMENTS',
|
||||
REPORTEES = 'REPORTEES',
|
||||
GET_AGENT_DETAIL = 'GET_AGENT_DETAIL',
|
||||
}
|
||||
|
||||
export const API_URLS: Record<ApiKeys, string> = {} as Record<ApiKeys, string>;
|
||||
@@ -93,6 +95,8 @@ API_URLS[ApiKeys.UPLOAD_FEEDBACK_IMAGES] = '/feedback/persist-original-images';
|
||||
API_URLS[ApiKeys.GLOBAL_CONFIG] = '/global-config';
|
||||
API_URLS[ApiKeys.UPLOAD_IMAGE_ID] = '/user/documents/selfie';
|
||||
API_URLS[ApiKeys.GET_DOCUMENTS] = '/user/documents';
|
||||
API_URLS[ApiKeys.REPORTEES] = '/user/reportees';
|
||||
API_URLS[ApiKeys.GET_AGENT_DETAIL] = '/user/role-info';
|
||||
|
||||
export const API_STATUS_CODE = {
|
||||
OK: 200,
|
||||
|
||||
@@ -8,7 +8,7 @@ import { FirestoreUpdateTypes } from '../common/Constants';
|
||||
import { toast } from '../../RN-UI-LIB/src/components/toast';
|
||||
import auth from '@react-native-firebase/auth';
|
||||
import { updateAvTemplateData, updateCollectionTemplateData } from '../reducer/caseReducer';
|
||||
import { ILockData, setLockData, VisitPlanStatus } from '../reducer/userSlice';
|
||||
import { ILockData, MY_CASE_ITEM, setLockData, VisitPlanStatus } from '../reducer/userSlice';
|
||||
import { setFilters } from '../reducer/filtersSlice';
|
||||
import { FormTemplateV1 } from '../types/template.types';
|
||||
import { ToastMessages } from '../screens/allCases/constants';
|
||||
@@ -33,12 +33,13 @@ const isUserSignedIn = () => {
|
||||
|
||||
const useFirestoreUpdates = () => {
|
||||
const {
|
||||
user: { user, isLoggedIn, sessionDetails, lock },
|
||||
allCases: { caseDetails, casesList, loading },
|
||||
user: { user, isLoggedIn, sessionDetails, lock, selectedAgent = MY_CASE_ITEM },
|
||||
allCases: { caseDetails, casesList },
|
||||
} = useAppSelector((state: RootState) => ({
|
||||
user: state.user || {},
|
||||
allCases: state.allCases,
|
||||
}));
|
||||
const isTeamLead = useAppSelector((state) => state.user.isTeamLead);
|
||||
const lockRef = useRef<ILockData | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -155,6 +156,7 @@ const useFirestoreUpdates = () => {
|
||||
const handleError = (err: any, collectionPath?: string) => {
|
||||
const errMsg = `Error while fetching fireStore snapshot: referenceId: ${user?.referenceId} collectionPath: ${collectionPath}`;
|
||||
logError(err as Error, errMsg);
|
||||
dispatch(setLoading(false));
|
||||
};
|
||||
|
||||
const signInUserToFirebase = () => {
|
||||
@@ -176,12 +178,6 @@ const useFirestoreUpdates = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const subscribeToCollection = (successCb: GenericFunctionArgs, collectionPath: string) => {
|
||||
return firestore()
|
||||
.collection(collectionPath)
|
||||
.onSnapshot(successCb, (err) => handleError(err, collectionPath));
|
||||
};
|
||||
|
||||
const subscribeToDoc = (successCb: GenericFunctionArgs, collectionPath: string) => {
|
||||
return firestore()
|
||||
.doc(collectionPath)
|
||||
@@ -189,7 +185,11 @@ const useFirestoreUpdates = () => {
|
||||
};
|
||||
|
||||
const subscribeToCases = () => {
|
||||
const collectionPath = `allocations/${user?.referenceId}/cases`;
|
||||
let refId = user?.referenceId;
|
||||
if (isTeamLead && selectedAgent?.agentReferenceId !== MY_CASE_ITEM.agentReferenceId) {
|
||||
refId = selectedAgent?.agentReferenceId;
|
||||
}
|
||||
const collectionPath = `allocations/${refId}/cases`;
|
||||
return firestore()
|
||||
.collection(collectionPath)
|
||||
.orderBy('totalOverdueAmount', 'asc') // It is descending order only, but acting weirdly. Need to check.
|
||||
@@ -212,7 +212,11 @@ const useFirestoreUpdates = () => {
|
||||
};
|
||||
|
||||
const subscribeToFilters = () => {
|
||||
const collectionPath = `filters/${user?.referenceId}`;
|
||||
let refId = user?.referenceId;
|
||||
if (isTeamLead && selectedAgent?.agentReferenceId !== MY_CASE_ITEM.agentReferenceId) {
|
||||
refId = selectedAgent?.agentReferenceId;
|
||||
}
|
||||
const collectionPath = `filters/${refId}`;
|
||||
return subscribeToDoc(handleFilterUpdate, collectionPath);
|
||||
};
|
||||
|
||||
@@ -263,6 +267,33 @@ const useFirestoreUpdates = () => {
|
||||
};
|
||||
}, [isLoggedIn, user?.referenceId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isTeamLead) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
!selectedAgent?.agentReferenceId ||
|
||||
selectedAgent?.agentReferenceId === MY_CASE_ITEM.agentReferenceId
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (!isLoggedIn || !sessionDetails?.firebaseToken) {
|
||||
loggedOutCurrentUser();
|
||||
return;
|
||||
}
|
||||
// unsubscribe from previous agent's cases
|
||||
casesUnsubscribe && casesUnsubscribe();
|
||||
filterUnsubscribe && filterUnsubscribe();
|
||||
dispatch(setLoading(true));
|
||||
// subscribe to new agent's cases
|
||||
subscribeToCases();
|
||||
subscribeToFilters();
|
||||
return () => {
|
||||
casesUnsubscribe && casesUnsubscribe();
|
||||
filterUnsubscribe && filterUnsubscribe();
|
||||
};
|
||||
}, [selectedAgent, isTeamLead]);
|
||||
|
||||
useEffect(() => {
|
||||
forceUninstallUnsubscribe = subscribeToForceUninstall();
|
||||
}, []);
|
||||
|
||||
@@ -242,9 +242,6 @@ const allCasesSlice = createSlice({
|
||||
isInitialLoad: boolean;
|
||||
isVisitPlanLocked: boolean;
|
||||
};
|
||||
if (state.loading) {
|
||||
state.loading = false;
|
||||
}
|
||||
let newVisitCaseLoanIds: string[] = [];
|
||||
let newVisitCollectionCases: string[] = [];
|
||||
let removedVisitedCasesLoanIds: string[] = [];
|
||||
@@ -356,6 +353,9 @@ const allCasesSlice = createSlice({
|
||||
state.completedList = completedList;
|
||||
state.pinnedList = pinnedList;
|
||||
state.newVisitedCases = newVisitCollectionCases;
|
||||
if (state.loading) {
|
||||
state.loading = false;
|
||||
}
|
||||
|
||||
if (newVisitCaseLoanIds?.length > 0) {
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_VISIT_PLAN_UPDATED, {
|
||||
@@ -503,26 +503,8 @@ const allCasesSlice = createSlice({
|
||||
state.caseDetails[action.payload].isNewlyAdded = false;
|
||||
}
|
||||
},
|
||||
resetCasesData: (state) => {
|
||||
state.casesList = [];
|
||||
state.casesListMap = {};
|
||||
state.intermediateTodoList = [];
|
||||
state.intermediateTodoListMap = {};
|
||||
state.selectedTodoListCount = 0;
|
||||
state.selectedTodoListMap = {};
|
||||
state.initialPinnedRankCount = 0;
|
||||
state.pinnedRankCount = 0;
|
||||
state.loading = false;
|
||||
state.filterList = [];
|
||||
state.newlyPinnedCases = 0;
|
||||
state.completedCases = 0;
|
||||
state.caseDetails = {};
|
||||
state.searchQuery = '';
|
||||
state.isOnboarded = state.isOnboarded;
|
||||
state.newVisitedCases = [];
|
||||
state.pendingList = [];
|
||||
state.pinnedList = [];
|
||||
state.completedList = [];
|
||||
resetCasesData: () => {
|
||||
return initialState;
|
||||
},
|
||||
setVisitPlansUpdating: (state, action) => {
|
||||
state.visitPlansUpdating = action.payload;
|
||||
|
||||
36
src/reducer/reporteesSlice.ts
Normal file
36
src/reducer/reporteesSlice.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
import { IReportee } from '../screens/allCases/interface';
|
||||
import { MY_CASE_ITEM } from './userSlice';
|
||||
|
||||
interface IReporteesSlice {
|
||||
agentsList: IReportee[];
|
||||
isLoading: boolean;
|
||||
showAgentSelectionBottomSheet: boolean;
|
||||
}
|
||||
|
||||
const initialState: IReporteesSlice = {
|
||||
agentsList: [],
|
||||
isLoading: false,
|
||||
showAgentSelectionBottomSheet: false,
|
||||
};
|
||||
|
||||
export const userSlice = createSlice({
|
||||
name: 'reportees',
|
||||
initialState,
|
||||
reducers: {
|
||||
setReporteesList: (state, action) => {
|
||||
state.agentsList = [MY_CASE_ITEM, ...(action.payload || [])];
|
||||
},
|
||||
setReporteesLoading: (state, action) => {
|
||||
state.isLoading = action.payload;
|
||||
},
|
||||
setShowAgentSelectionBottomSheet: (state, action) => {
|
||||
state.showAgentSelectionBottomSheet = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { setReporteesList, setReporteesLoading, setShowAgentSelectionBottomSheet } =
|
||||
userSlice.actions;
|
||||
|
||||
export default userSlice.reducer;
|
||||
@@ -1,5 +1,6 @@
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
import { setGlobalUserData } from '../constants/Global';
|
||||
import { IReportee } from '../screens/allCases/interface';
|
||||
|
||||
interface ISessionDetails {
|
||||
sessionToken: string;
|
||||
@@ -9,8 +10,16 @@ interface ISessionDetails {
|
||||
|
||||
export enum IUserRole {
|
||||
SUPER_USER = 'ADDRESS_VERIFICATION:API:SUPER_USER',
|
||||
ROLE_TEAM_LEAD = 'ROLE_TEAM_LEAD',
|
||||
}
|
||||
|
||||
export const MY_CASE_ITEM = {
|
||||
name: 'My Cases',
|
||||
agentReferenceId: 'MY_CASES',
|
||||
agencyCode: '',
|
||||
agencyName: '',
|
||||
};
|
||||
|
||||
interface IUserDetails {
|
||||
emailId: string;
|
||||
referenceId: string;
|
||||
@@ -47,6 +56,8 @@ export interface IUserSlice extends IUser {
|
||||
clickstreamEvents: IClickstreamEvents[];
|
||||
isImpersonated: boolean;
|
||||
lock: ILockData;
|
||||
selectedAgent: IReportee;
|
||||
isTeamLead: boolean;
|
||||
}
|
||||
|
||||
const initialState: IUserSlice = {
|
||||
@@ -59,6 +70,8 @@ const initialState: IUserSlice = {
|
||||
lock: {
|
||||
visitPlanStatus: VisitPlanStatus.UNLOCKED,
|
||||
},
|
||||
selectedAgent: MY_CASE_ITEM,
|
||||
isTeamLead: false,
|
||||
};
|
||||
|
||||
export const userSlice = createSlice({
|
||||
@@ -86,9 +99,16 @@ export const userSlice = createSlice({
|
||||
state.lock = action.payload;
|
||||
}
|
||||
},
|
||||
setSelectedAgent: (state, action) => {
|
||||
state.selectedAgent = action.payload;
|
||||
},
|
||||
setAgentRole: (state, action) => {
|
||||
state.isTeamLead = action.payload ?? false;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { setAuthData, setDeviceId, setLockData } = userSlice.actions;
|
||||
export const { setAuthData, setDeviceId, setLockData, setSelectedAgent, setAgentRole } =
|
||||
userSlice.actions;
|
||||
|
||||
export default userSlice.reducer;
|
||||
|
||||
@@ -30,7 +30,7 @@ import VersionNumber from 'react-native-version-number';
|
||||
import { useFocusEffect } from '@react-navigation/native';
|
||||
import { CaseDetail } from '../caseDetails/interface';
|
||||
import CaseItem from '../allCases/CaseItem';
|
||||
import { IUserRole } from '../../reducer/userSlice';
|
||||
import { IUserRole, MY_CASE_ITEM } from '../../reducer/userSlice';
|
||||
import QuestionMarkIcon from '../../assets/icons/QuestionMarkIcon';
|
||||
import IDCardImageCapture from './IDCardImageCapture';
|
||||
import AgentIdCard from './AgentIdCard';
|
||||
@@ -53,6 +53,8 @@ const Profile: React.FC = () => {
|
||||
caseDetails,
|
||||
supportLink,
|
||||
pendingCases,
|
||||
selectedAgent,
|
||||
isTeamLead,
|
||||
} = useAppSelector((state: RootState) => ({
|
||||
originalImageUri: state.profile.originalImageUri,
|
||||
imageUri: state.profile.imageUri,
|
||||
@@ -65,6 +67,8 @@ const Profile: React.FC = () => {
|
||||
supportLink: state.config.data?.supportLink,
|
||||
isUploadingImage: state.profile.isUploadingImage,
|
||||
pendingCases: state.allCases.pendingList,
|
||||
selectedAgent: state.user.selectedAgent,
|
||||
isTeamLead: state.user.isTeamLead,
|
||||
}));
|
||||
|
||||
useEffect(() => {
|
||||
@@ -132,6 +136,9 @@ const Profile: React.FC = () => {
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ID_CARD_CLICKED);
|
||||
};
|
||||
|
||||
const showCompletedCases =
|
||||
!isTeamLead || selectedAgent?.agentReferenceId === MY_CASE_ITEM.agentReferenceId;
|
||||
|
||||
return (
|
||||
<View style={[GenericStyles.fill]}>
|
||||
<NavigationHeader
|
||||
@@ -174,53 +181,55 @@ const Profile: React.FC = () => {
|
||||
}
|
||||
/>
|
||||
<ScrollView>
|
||||
<View
|
||||
style={[
|
||||
GenericStyles.ph16,
|
||||
GenericStyles.pt16,
|
||||
numberOfCompletedCases === 2 ? { paddingBottom: 6 } : {},
|
||||
]}
|
||||
>
|
||||
{hideUploadImageBtn ? null : <IDCardImageCapture />}
|
||||
{showCompletedCases ? (
|
||||
<View
|
||||
style={[
|
||||
GenericStyles.row,
|
||||
GenericStyles.alignCenter,
|
||||
numberOfCompletedCases ? { paddingBottom: 12 } : GenericStyles.pb16,
|
||||
GenericStyles.ph16,
|
||||
GenericStyles.pt16,
|
||||
numberOfCompletedCases === 2 ? { paddingBottom: 6 } : {},
|
||||
]}
|
||||
>
|
||||
<View style={[GenericStyles.ml4, GenericStyles.mr8]}>
|
||||
<GroupIcon />
|
||||
</View>
|
||||
<Text>Completed cases ({numberOfCompletedCases})</Text>
|
||||
</View>
|
||||
{numberOfCompletedCases
|
||||
? completeCasesList.slice(0, 2).map((caseItem) => {
|
||||
const caseDetailItem = caseDetails[caseItem.caseReferenceId] as CaseDetail;
|
||||
return (
|
||||
<CaseItem
|
||||
key={caseItem.caseReferenceId}
|
||||
caseDetailObj={caseDetailItem}
|
||||
isCompleted={true}
|
||||
/>
|
||||
);
|
||||
})
|
||||
: null}
|
||||
{numberOfCompletedCases > 2 ? (
|
||||
<Button
|
||||
title="View all completed cases"
|
||||
variant="primaryText"
|
||||
{hideUploadImageBtn ? null : <IDCardImageCapture />}
|
||||
<View
|
||||
style={[
|
||||
GenericStyles.w100,
|
||||
GenericStyles.br8,
|
||||
GenericStyles.mt6,
|
||||
GenericStyles.mb12,
|
||||
GenericStyles.whiteBackground,
|
||||
GenericStyles.row,
|
||||
GenericStyles.alignCenter,
|
||||
numberOfCompletedCases ? { paddingBottom: 12 } : GenericStyles.pb16,
|
||||
]}
|
||||
onPress={handleViewAllCases}
|
||||
/>
|
||||
) : null}
|
||||
</View>
|
||||
>
|
||||
<View style={[GenericStyles.ml4, GenericStyles.mr8]}>
|
||||
<GroupIcon />
|
||||
</View>
|
||||
<Text>Completed cases ({numberOfCompletedCases})</Text>
|
||||
</View>
|
||||
{numberOfCompletedCases
|
||||
? completeCasesList.slice(0, 2).map((caseItem) => {
|
||||
const caseDetailItem = caseDetails[caseItem.caseReferenceId] as CaseDetail;
|
||||
return (
|
||||
<CaseItem
|
||||
key={caseItem.caseReferenceId}
|
||||
caseDetailObj={caseDetailItem}
|
||||
isCompleted={true}
|
||||
/>
|
||||
);
|
||||
})
|
||||
: null}
|
||||
{numberOfCompletedCases > 2 ? (
|
||||
<Button
|
||||
title="View all completed cases"
|
||||
variant="primaryText"
|
||||
style={[
|
||||
GenericStyles.w100,
|
||||
GenericStyles.br8,
|
||||
GenericStyles.mt6,
|
||||
GenericStyles.mb12,
|
||||
GenericStyles.whiteBackground,
|
||||
]}
|
||||
onPress={handleViewAllCases}
|
||||
/>
|
||||
) : null}
|
||||
</View>
|
||||
) : null}
|
||||
<View style={[styles.logoutContainer, GenericStyles.whiteBackground]}>
|
||||
<TouchableOpacity
|
||||
onPress={handleLogout}
|
||||
|
||||
79
src/screens/allCases/AgentListItem.tsx
Normal file
79
src/screens/allCases/AgentListItem.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
import { Pressable, StyleSheet, View } from 'react-native';
|
||||
import React from 'react';
|
||||
import Text from '../../../RN-UI-LIB/src/components/Text';
|
||||
import { GenericStyles } from '../../../RN-UI-LIB/src/styles';
|
||||
import ArrowSolidIcon from '../../../RN-UI-LIB/src/Icons/ArrowSolidIcon';
|
||||
import { COLORS } from '../../../RN-UI-LIB/src/styles/colors';
|
||||
import { useAppDispatch, useAppSelector } from '../../hooks';
|
||||
import { setShowAgentSelectionBottomSheet } from '../../reducer/reporteesSlice';
|
||||
import { IReportee } from './interface';
|
||||
import { resetCasesData } from '../../reducer/allCasesSlice';
|
||||
import fuzzySort from '../../../RN-UI-LIB/src/utlis/fuzzySort';
|
||||
import fuzzysort from 'fuzzysort';
|
||||
import { MY_CASE_ITEM, setSelectedAgent } from '../../reducer/userSlice';
|
||||
|
||||
interface IAgentListItem {
|
||||
agent: IReportee;
|
||||
leftAdornment?: React.ReactNode;
|
||||
searchQuery: string;
|
||||
}
|
||||
|
||||
const AgentListItem: React.FC<IAgentListItem> = ({ agent, leftAdornment, searchQuery }) => {
|
||||
const selectedAgent = useAppSelector((state) => state.user.selectedAgent) || MY_CASE_ITEM;
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const handleAgentSelection = () => {
|
||||
dispatch(setSelectedAgent(agent));
|
||||
dispatch(resetCasesData());
|
||||
dispatch(setShowAgentSelectionBottomSheet(false));
|
||||
};
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
style={[
|
||||
GenericStyles.row,
|
||||
GenericStyles.justifyContentSpaceBetween,
|
||||
GenericStyles.whiteBackground,
|
||||
GenericStyles.p12,
|
||||
GenericStyles.br8,
|
||||
GenericStyles.border,
|
||||
GenericStyles.alignCenter,
|
||||
GenericStyles.mb16,
|
||||
styles.shadow,
|
||||
{
|
||||
backgroundColor:
|
||||
agent.agentReferenceId === selectedAgent.agentReferenceId
|
||||
? COLORS.BACKGROUND.BLUE_LIGHT_3
|
||||
: COLORS.BACKGROUND.PRIMARY,
|
||||
},
|
||||
]}
|
||||
onPress={handleAgentSelection}
|
||||
>
|
||||
<View style={[GenericStyles.row, GenericStyles.alignCenter]}>
|
||||
{leftAdornment && <View style={[GenericStyles.mr4]}>{leftAdornment}</View>}
|
||||
<Text>
|
||||
{searchQuery.length > 0
|
||||
? fuzzySort.highlight(fuzzysort.single(searchQuery, agent.name), (result: string) => (
|
||||
<Text style={styles.highlight}>{result}</Text>
|
||||
))
|
||||
: agent.name}
|
||||
</Text>
|
||||
</View>
|
||||
<ArrowSolidIcon size={10} fillColor={COLORS.BACKGROUND.LIGHT} rotateY={180} />
|
||||
</Pressable>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
shadow: {
|
||||
elevation: 1,
|
||||
},
|
||||
highlight: {
|
||||
backgroundColor: COLORS.BACKGROUND.ORANGE,
|
||||
borderRadius: 4,
|
||||
borderWidth: 1,
|
||||
borderColor: COLORS.BORDER.ORANGE,
|
||||
},
|
||||
});
|
||||
|
||||
export default AgentListItem;
|
||||
21
src/screens/allCases/AgentListSearchbar.tsx
Normal file
21
src/screens/allCases/AgentListSearchbar.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import React from 'react';
|
||||
import TextInput from '../../../RN-UI-LIB/src/components/TextInput';
|
||||
import SearchIcon from '../../../RN-UI-LIB/src/Icons/SearchIcon';
|
||||
|
||||
interface IAgentListSearchbar {
|
||||
searchQuery: string;
|
||||
handleSearchChange: (val: string) => void;
|
||||
}
|
||||
|
||||
const AgentListSearchbar: React.FC<IAgentListSearchbar> = ({ searchQuery, handleSearchChange }) => {
|
||||
return (
|
||||
<TextInput
|
||||
LeftComponent={<SearchIcon />}
|
||||
onChangeText={handleSearchChange}
|
||||
placeholder="Search by agent"
|
||||
defaultValue={searchQuery}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default AgentListSearchbar;
|
||||
103
src/screens/allCases/AgentListView.tsx
Normal file
103
src/screens/allCases/AgentListView.tsx
Normal file
@@ -0,0 +1,103 @@
|
||||
import {
|
||||
Animated,
|
||||
NativeScrollEvent,
|
||||
NativeSyntheticEvent,
|
||||
SectionList,
|
||||
StyleSheet,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import React, { useMemo } from 'react';
|
||||
import Text from '../../../RN-UI-LIB/src/components/Text';
|
||||
import { IReportee, ISectionListData } from './interface';
|
||||
import { useAppSelector } from '../../hooks';
|
||||
import { GenericStyles } from '../../../RN-UI-LIB/src/styles';
|
||||
import { COLORS } from '../../../RN-UI-LIB/src/styles/colors';
|
||||
import AgentListItem from './AgentListItem';
|
||||
import { sectionListTranformData } from './utils';
|
||||
import ProfileSolidIcon from '../../../RN-UI-LIB/src/Icons/ProfileSolidIcon';
|
||||
import { Search } from '../../../RN-UI-LIB/src/utlis/search';
|
||||
import NoCasesFoundIcon from '../../assets/icons/NoCasesFoundIcon';
|
||||
import { MY_CASE_ITEM } from '../../reducer/userSlice';
|
||||
import Heading from '../../../RN-UI-LIB/src/components/Heading';
|
||||
|
||||
interface IAgentListView {
|
||||
searchQuery: string;
|
||||
scrollAnimation: Animated.Value;
|
||||
}
|
||||
|
||||
const AgentListView: React.FC<IAgentListView> = ({ scrollAnimation, searchQuery }) => {
|
||||
const { agentsList = [] } = useAppSelector((state) => state.reportees);
|
||||
const filteredAgentsList: ISectionListData[] = useMemo(() => {
|
||||
const filteredList =
|
||||
searchQuery.length > 0
|
||||
? Search(searchQuery, agentsList, { keys: ['name'] }).map(
|
||||
(item: { obj: IReportee }) => item.obj
|
||||
)
|
||||
: agentsList;
|
||||
return sectionListTranformData(filteredList);
|
||||
}, [searchQuery, agentsList]);
|
||||
|
||||
const handleListScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
|
||||
const offsetY = event.nativeEvent.contentOffset.y;
|
||||
scrollAnimation.setValue(offsetY);
|
||||
};
|
||||
|
||||
if (filteredAgentsList.length === 0) {
|
||||
return (
|
||||
<View style={[GenericStyles.fill, GenericStyles.alignCenter, styles.mt64]}>
|
||||
<View style={GenericStyles.alignCenter}>
|
||||
<NoCasesFoundIcon />
|
||||
<Heading style={GenericStyles.mt16} type="h4">
|
||||
No {agentsList.length === 0 ? 'reportees' : 'results'} found
|
||||
</Heading>
|
||||
{agentsList.length ? <Text light>Try searching something else</Text> : null}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<SectionList
|
||||
sections={filteredAgentsList}
|
||||
keyExtractor={(item) => item.agentReferenceId}
|
||||
onScroll={handleListScroll}
|
||||
contentContainerStyle={GenericStyles.ph16}
|
||||
renderItem={({ item }) => (
|
||||
<AgentListItem
|
||||
agent={item}
|
||||
searchQuery={searchQuery}
|
||||
leftAdornment={
|
||||
item.agentReferenceId === MY_CASE_ITEM.agentReferenceId ? <ProfileSolidIcon /> : null
|
||||
}
|
||||
/>
|
||||
)}
|
||||
renderSectionHeader={({ section: { title } }) => {
|
||||
if (!title) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<View style={[GenericStyles.centerAlignedRow, GenericStyles.pb16]}>
|
||||
<Text bold dark>
|
||||
{title}
|
||||
</Text>
|
||||
<View style={styles.separatorLine} />
|
||||
</View>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
separatorLine: {
|
||||
height: 1,
|
||||
flex: 1,
|
||||
backgroundColor: COLORS.BORDER.PRIMARY,
|
||||
marginLeft: 8,
|
||||
},
|
||||
mt64: {
|
||||
marginTop: 64,
|
||||
},
|
||||
});
|
||||
|
||||
export default AgentListView;
|
||||
21
src/screens/allCases/AgentListViewLoading.tsx
Normal file
21
src/screens/allCases/AgentListViewLoading.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import { View } from 'react-native';
|
||||
import React from 'react';
|
||||
import LineLoader from '../../../RN-UI-LIB/src/components/suspense_loader/LineLoader';
|
||||
import { GenericStyles } from '../../../RN-UI-LIB/src/styles';
|
||||
|
||||
const AgentListViewLoading = () => {
|
||||
return (
|
||||
<View style={[GenericStyles.fill, GenericStyles.whiteBackground, GenericStyles.ph16]}>
|
||||
{[...Array(8).keys()].map((_, index) => (
|
||||
<LineLoader
|
||||
key={index}
|
||||
width={'100%'}
|
||||
height={50}
|
||||
style={[GenericStyles.br6, { marginBottom: 20 }]}
|
||||
/>
|
||||
))}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default AgentListViewLoading;
|
||||
72
src/screens/allCases/AgentsListContainer.tsx
Normal file
72
src/screens/allCases/AgentsListContainer.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import { Animated, StyleSheet, View } from 'react-native';
|
||||
import React, { useCallback, useEffect, useRef } from 'react';
|
||||
import AgentListSearchbar from './AgentListSearchbar';
|
||||
import { debounce } from '../../components/utlis/commonFunctions';
|
||||
import AgentListView from './AgentListView';
|
||||
import { useAppDispatch, useAppSelector } from '../../hooks';
|
||||
import { getAgentsList } from '../../action/reporteesActions';
|
||||
import { GenericStyles } from '../../../RN-UI-LIB/src/styles';
|
||||
import { COLORS } from '../../../RN-UI-LIB/src/styles/colors';
|
||||
import AgentListViewLoading from './AgentListViewLoading';
|
||||
|
||||
const AgentsListContainer = () => {
|
||||
const [searchQuery, setSearchQuery] = React.useState<string>('');
|
||||
const { isLoading, agentsList } = useAppSelector((state) => state.reportees);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const scrollAnimation = useRef(new Animated.Value(0)).current;
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(getAgentsList());
|
||||
}, []);
|
||||
|
||||
const handleSearchChange = useCallback(
|
||||
debounce((query: string) => {
|
||||
setSearchQuery(query);
|
||||
}, 200),
|
||||
[]
|
||||
);
|
||||
|
||||
const elevateAnimatedValue = scrollAnimation.interpolate({
|
||||
inputRange: [0, 100],
|
||||
outputRange: [0, 6],
|
||||
extrapolate: 'clamp',
|
||||
});
|
||||
|
||||
const paddingBottomAnimatedValue = scrollAnimation.interpolate({
|
||||
inputRange: [0, 100],
|
||||
outputRange: [0, 10],
|
||||
extrapolate: 'clamp',
|
||||
});
|
||||
|
||||
if (isLoading && !agentsList.length) {
|
||||
return <AgentListViewLoading />;
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={[GenericStyles.fill, GenericStyles.whiteBackground]}>
|
||||
<Animated.View
|
||||
style={[{ paddingBottom: paddingBottomAnimatedValue }, GenericStyles.overflowHidden]}
|
||||
>
|
||||
<Animated.View
|
||||
style={[
|
||||
GenericStyles.ph16,
|
||||
GenericStyles.pb16,
|
||||
GenericStyles.whiteBackground,
|
||||
{
|
||||
borderColor: COLORS.BORDER.PRIMARY,
|
||||
elevation: elevateAnimatedValue,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<AgentListSearchbar searchQuery={searchQuery} handleSearchChange={handleSearchChange} />
|
||||
</Animated.View>
|
||||
</Animated.View>
|
||||
<Animated.View style={[GenericStyles.fill]}>
|
||||
<AgentListView searchQuery={searchQuery} scrollAnimation={scrollAnimation} />
|
||||
</Animated.View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default AgentsListContainer;
|
||||
@@ -335,7 +335,7 @@ const CasesList: React.FC<ICasesList> = ({ casesList = [], isVisitPlan, allCases
|
||||
HeaderNode={() => (
|
||||
<View style={[...row, GenericStyles.ph16]}>
|
||||
<Heading dark type="h4">
|
||||
View team’s assigned cases
|
||||
View team's assigned cases
|
||||
</Heading>
|
||||
<TouchableOpacity activeOpacity={0.7} onPress={toggleAgentSelectionBottomSheet}>
|
||||
<CloseIcon color={COLORS.TEXT.LIGHT} />
|
||||
@@ -343,6 +343,7 @@ const CasesList: React.FC<ICasesList> = ({ casesList = [], isVisitPlan, allCases
|
||||
</View>
|
||||
)}
|
||||
heightPercentage={100}
|
||||
allowBackdropClose={false}
|
||||
visible={showAgentSelectionBottomSheet}
|
||||
setVisible={toggleAgentSelectionBottomSheet}
|
||||
>
|
||||
|
||||
@@ -23,12 +23,16 @@ interface IEmptyList {
|
||||
|
||||
const EmptyList: React.FC<IEmptyList> = (props) => {
|
||||
const { isCompleted, isVisitPlan, isFilterApplied, setShowAgentSelectionBottomSheet } = props;
|
||||
|
||||
const { isLockedVisitPlanStatus } = useAppSelector((state: RootState) => ({
|
||||
const { isLockedVisitPlanStatus, isCasesLoading } = useAppSelector((state: RootState) => ({
|
||||
isLockedVisitPlanStatus: state.user?.lock?.visitPlanStatus === VisitPlanStatus.LOCKED,
|
||||
isCasesLoading: state.allCases.loading,
|
||||
}));
|
||||
|
||||
const isAgentTLOrAM = true;
|
||||
const isTeamLead = useAppSelector((state) => state.user.isTeamLead);
|
||||
|
||||
if (isCasesLoading) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const renderIcon = () => {
|
||||
if (isLockedVisitPlanStatus && isVisitPlan) {
|
||||
@@ -60,7 +64,7 @@ const EmptyList: React.FC<IEmptyList> = (props) => {
|
||||
return EmptyListMessages.NO_VISIT_PLANS;
|
||||
}
|
||||
|
||||
if (isAgentTLOrAM) {
|
||||
if (isTeamLead) {
|
||||
return EmptyListMessages.NO_ACTIVE_ALLOCATIONS;
|
||||
}
|
||||
|
||||
@@ -74,7 +78,7 @@ const EmptyList: React.FC<IEmptyList> = (props) => {
|
||||
if (isFilterApplied) {
|
||||
return EmptyListMessages.NO_CASES_FOUND_SUB;
|
||||
}
|
||||
if (isAgentTLOrAM) {
|
||||
if (isTeamLead) {
|
||||
return EmptyListMessages.SELECT_AGENT;
|
||||
}
|
||||
};
|
||||
@@ -87,7 +91,7 @@ const EmptyList: React.FC<IEmptyList> = (props) => {
|
||||
};
|
||||
}
|
||||
|
||||
if (isAgentTLOrAM && setShowAgentSelectionBottomSheet) {
|
||||
if (isTeamLead && setShowAgentSelectionBottomSheet) {
|
||||
return {
|
||||
btnHandler: () => setShowAgentSelectionBottomSheet(true),
|
||||
btnText: 'Select Agent',
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { StyleSheet, TouchableOpacity, View } from 'react-native';
|
||||
import React from 'react';
|
||||
import { Animated, Easing, StyleSheet, TouchableOpacity, View } from 'react-native';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import Heading from '../../../RN-UI-LIB/src/components/Heading';
|
||||
import { COLORS } from '../../../RN-UI-LIB/src/styles/colors';
|
||||
import { GenericStyles } from '../../../RN-UI-LIB/src/styles';
|
||||
import ArrowDownOutlineIcon from '../../assets/icons/ArrowDownOutlineIcon';
|
||||
import { useAppSelector } from '../../hooks';
|
||||
import { RootState } from '../../store/store';
|
||||
import { VisitPlanStatus } from '../../reducer/userSlice';
|
||||
import { MY_CASE_ITEM, VisitPlanStatus } from '../../reducer/userSlice';
|
||||
import { dateFormat, DAY_MONTH_DATE_FORMAT } from '../../../RN-UI-LIB/src/utlis/dates';
|
||||
|
||||
interface HeaderLabelProps {
|
||||
@@ -18,11 +18,22 @@ interface HeaderLabelProps {
|
||||
const HeaderLabel: React.FC<HeaderLabelProps> = (props) => {
|
||||
const { setShowAgentSelectionBottomSheet, filteredListCount, isVisitPlan } = props;
|
||||
|
||||
const { isLockedVisitPlanStatus } = useAppSelector((state: RootState) => ({
|
||||
const {
|
||||
isLockedVisitPlanStatus,
|
||||
selectedAgent = MY_CASE_ITEM,
|
||||
loading,
|
||||
} = useAppSelector((state: RootState) => ({
|
||||
isLockedVisitPlanStatus: state.user?.lock?.visitPlanStatus === VisitPlanStatus.LOCKED,
|
||||
selectedAgent: state.user.selectedAgent,
|
||||
loading: state.allCases.loading,
|
||||
}));
|
||||
const opacityAnimation = useRef(new Animated.Value(0)).current;
|
||||
const opacityStyle = { opacity: opacityAnimation };
|
||||
const isTeamLead = useAppSelector((state) => state.user.isTeamLead);
|
||||
|
||||
const isAgentTLOrAM = true;
|
||||
useEffect(() => {
|
||||
animateElement();
|
||||
}, [selectedAgent, isTeamLead]);
|
||||
|
||||
const getHeaderLabel = () => {
|
||||
if (isVisitPlan) {
|
||||
@@ -33,19 +44,44 @@ const HeaderLabel: React.FC<HeaderLabelProps> = (props) => {
|
||||
const formattedDate = dateFormat(currentDate, DAY_MONTH_DATE_FORMAT);
|
||||
return formattedDate;
|
||||
}
|
||||
return `My Cases (${filteredListCount})`;
|
||||
return `${selectedAgent.name}${!loading ? ` (${filteredListCount})` : ''}`;
|
||||
};
|
||||
|
||||
if (isAgentTLOrAM && !isVisitPlan) {
|
||||
const animateElement = (iterations = 1) => {
|
||||
if (iterations === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Animated.timing(opacityAnimation, {
|
||||
toValue: 0.5,
|
||||
duration: 400,
|
||||
useNativeDriver: true,
|
||||
easing: Easing.linear,
|
||||
}).start(() => {
|
||||
Animated.timing(opacityAnimation, {
|
||||
toValue: 0,
|
||||
duration: 300,
|
||||
useNativeDriver: true,
|
||||
easing: Easing.linear,
|
||||
}).start(() => {
|
||||
animateElement(iterations - 1);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
if (isTeamLead && !isVisitPlan) {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
style={GenericStyles.centerAlignedRow}
|
||||
onPress={() => setShowAgentSelectionBottomSheet(true)}
|
||||
>
|
||||
<Animated.View style={[styles.animatedOverlay, opacityStyle]} />
|
||||
<Heading type="h3" style={[styles.headerLabel]}>
|
||||
{getHeaderLabel()}
|
||||
</Heading>
|
||||
<ArrowDownOutlineIcon />
|
||||
<View style={GenericStyles.mt2}>
|
||||
<ArrowDownOutlineIcon />
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
@@ -57,10 +93,18 @@ const HeaderLabel: React.FC<HeaderLabelProps> = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default HeaderLabel;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
headerLabel: {
|
||||
color: COLORS.BACKGROUND.PRIMARY,
|
||||
},
|
||||
animatedOverlay: {
|
||||
backgroundColor: COLORS.BACKGROUND.PRIMARY,
|
||||
position: 'absolute',
|
||||
width: '110%',
|
||||
height: '90%',
|
||||
borderRadius: 8,
|
||||
paddingHorizontal: 10,
|
||||
},
|
||||
});
|
||||
|
||||
export default HeaderLabel;
|
||||
|
||||
@@ -77,6 +77,7 @@ const ListItem: React.FC<IListItem> = (props) => {
|
||||
const isVisitPlanStatusLocked = useAppSelector(
|
||||
(state) => state.user?.lock?.visitPlanStatus === VisitPlanStatus.LOCKED
|
||||
);
|
||||
const isTeamLead = useAppSelector((state) => state.user.isTeamLead);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
@@ -174,7 +175,7 @@ const ListItem: React.FC<IListItem> = (props) => {
|
||||
const caseCompleted = COMPLETED_STATUSES.includes(caseStatus);
|
||||
|
||||
const showVisitPlanBtn =
|
||||
!(caseCompleted || isCaseItemPinnedMainView) && !isTodoItem && !isCompleted;
|
||||
!(caseCompleted || isCaseItemPinnedMainView) && !isTodoItem && !isCompleted && !isTeamLead;
|
||||
|
||||
return (
|
||||
<Pressable onPress={handleCaseClick}>
|
||||
|
||||
@@ -29,7 +29,7 @@ const AllCasesMain = () => {
|
||||
);
|
||||
const userState = useAppSelector((state: RootState) => state.user);
|
||||
const dispatch = useAppDispatch();
|
||||
const isAgentTLOrAM = true;
|
||||
const isTeamLead = useAppSelector((state) => state.user.isTeamLead);
|
||||
|
||||
const HOME_SCREENS: ITabScreen[] = useMemo(() => {
|
||||
const bottomSheetScreens = [
|
||||
@@ -41,7 +41,7 @@ const AllCasesMain = () => {
|
||||
icon: CasesIcon,
|
||||
},
|
||||
];
|
||||
if (!isAgentTLOrAM) {
|
||||
if (!isTeamLead) {
|
||||
bottomSheetScreens.push({
|
||||
name: BOTTOM_TAB_ROUTES.VisitPlan,
|
||||
component: () => <CasesList casesList={pinnedList} isVisitPlan />,
|
||||
@@ -54,7 +54,7 @@ const AllCasesMain = () => {
|
||||
icon: ProfileIcon,
|
||||
});
|
||||
return bottomSheetScreens;
|
||||
}, [pendingList, pinnedList, isAgentTLOrAM]);
|
||||
}, [pendingList, pinnedList, isTeamLead]);
|
||||
|
||||
const onTabPressHandler = (e: any) => {
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_TAB_SWITCH, {
|
||||
@@ -79,7 +79,7 @@ const AllCasesMain = () => {
|
||||
<FullScreenLoader loading={loading} />
|
||||
<BottomNavigator
|
||||
screens={HOME_SCREENS}
|
||||
initialRoute={isAgentTLOrAM ? BOTTOM_TAB_ROUTES.Cases : BOTTOM_TAB_ROUTES.VisitPlan}
|
||||
initialRoute={isTeamLead ? BOTTOM_TAB_ROUTES.Cases : BOTTOM_TAB_ROUTES.VisitPlan}
|
||||
onTabPress={(e) => onTabPressHandler(e)}
|
||||
/>
|
||||
<CasesActionButtons />
|
||||
|
||||
@@ -320,3 +320,15 @@ export interface ICaseItemAvatarCaseDetailObj extends IFetchDocumentCaseDetailOb
|
||||
export interface ICaseItemCaseDetailObj extends CaseDetail {
|
||||
isIntermediateOrSelectedTodoCaseItem?: boolean;
|
||||
}
|
||||
|
||||
export interface ISectionListData {
|
||||
title: string;
|
||||
data: IReportee[];
|
||||
}
|
||||
|
||||
export interface IReportee {
|
||||
agentReferenceId: string;
|
||||
name: string;
|
||||
agencyCode: string;
|
||||
agencyName: string;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CaseDetail, FeedbackStatus } from '../caseDetails/interface';
|
||||
import { ICaseItem } from './interface';
|
||||
import { ICaseItem, IReportee, ISectionListData } from './interface';
|
||||
|
||||
export const getAttemptedList = (
|
||||
filteredCasesList: ICaseItem[],
|
||||
@@ -27,3 +27,35 @@ export const getNonAttemptedList = (
|
||||
: true
|
||||
);
|
||||
};
|
||||
|
||||
export const sectionListTranformData = (agentList: IReportee[]): ISectionListData[] => {
|
||||
const result: ISectionListData[] = [];
|
||||
|
||||
// Create an object to map agency names to their corresponding data
|
||||
const agencyMap: { [key: string]: IReportee[] } = {};
|
||||
|
||||
for (const agent of agentList) {
|
||||
const agencyName = agent.agencyName;
|
||||
|
||||
if (!agencyMap[agencyName]) {
|
||||
agencyMap[agencyName] = [];
|
||||
}
|
||||
|
||||
agencyMap[agencyName].push({
|
||||
agentReferenceId: agent.agentReferenceId,
|
||||
name: agent.name,
|
||||
agencyCode: agent.agencyCode,
|
||||
agencyName: agent.agencyName,
|
||||
});
|
||||
}
|
||||
|
||||
// Transform the agencyMap into the desired result format
|
||||
for (const agencyName in agencyMap) {
|
||||
result.push({
|
||||
title: agencyName,
|
||||
data: agencyMap[agencyName],
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -50,10 +50,14 @@ const ProtectedRouter = () => {
|
||||
const { notificationsWithActions } = useAppSelector((state) => state.notifications);
|
||||
const isOnline = useIsOnline();
|
||||
const dispatch = useAppDispatch();
|
||||
const isTeamLead = useAppSelector((state) => state.user.isTeamLead);
|
||||
|
||||
// Gets unified data for new visit plan cases
|
||||
// TODO: Move this to another place
|
||||
useEffect(() => {
|
||||
if (isTeamLead) {
|
||||
return;
|
||||
}
|
||||
if (newVisitedCases?.length) {
|
||||
const loanAccountNumbers: string[] = [];
|
||||
newVisitedCases.forEach((caseId) => {
|
||||
|
||||
Reference in New Issue
Block a user