diff --git a/ProtectedRouter.tsx b/ProtectedRouter.tsx index a468f542..8affe824 100644 --- a/ProtectedRouter.tsx +++ b/ProtectedRouter.tsx @@ -10,7 +10,7 @@ import Widget from './src/components/form'; import { registerNavigateAndDispatch } from './src/components/utlis/apiHelper'; import { getLoanIdToValueFromLocal } from './src/components/utlis/registerPaymentUtils'; import { setGlobalUserData } from './src/constants/Global'; -import { useAppDispatch } from './src/hooks'; +import { useAppDispatch, useAppSelector } from './src/hooks'; import useFirestoreUpdates from './src/hooks/useFirestoreUpdates'; import { setLoanIdToValue } from './src/reducer/paymentSlice'; import { setDeviceId } from './src/reducer/userSlice'; @@ -29,6 +29,8 @@ import TodoList from './src/screens/todoList/TodoList'; import { RootState } from './src/store/store'; import { CaseAllocationType } from "./src/screens/allCases/interface"; import { getTemplateRoute } from "./src/components/utlis/navigationUtlis"; +import { resetNewVisitedCases } from './src/reducer/allCasesSlice'; +import { getCaseUnifiedData, UnifiedCaseDetailsTypes } from './src/action/caseApiActions'; const ANIMATION_DURATION = 300; @@ -45,6 +47,25 @@ const ProtectedRouter = () => { const user = useSelector( (state: RootState) => state.user, ); + const { newVisitedCases, caseDetails } = useAppSelector(state => state.allCases); + + useEffect(() => { + if(newVisitedCases?.length) { + const loanAccountNumbers: string[] = []; + newVisitedCases.forEach(caseId => { + const { loanAccountNumber } = caseDetails[caseId]; + if(!loanAccountNumber) { + return; + } + loanAccountNumbers.push(loanAccountNumber); + }); + if(loanAccountNumbers.length) { + const { EMI_SCHEDULE, REPAYMENTS, ADDRESS_AND_GEOLOCATIONS, FEEDBACKS } = UnifiedCaseDetailsTypes; + dispatch(getCaseUnifiedData(loanAccountNumbers, [EMI_SCHEDULE, REPAYMENTS, ADDRESS_AND_GEOLOCATIONS, FEEDBACKS])) + } + dispatch(resetNewVisitedCases()); + } + }, [newVisitedCases]) const avTemplate = useSelector( (state: RootState) => state.case.templateData[CaseAllocationType.ADDRESS_VERIFICATION_CASE], diff --git a/src/action/caseApiActions.ts b/src/action/caseApiActions.ts index 25244f38..d7355cd4 100644 --- a/src/action/caseApiActions.ts +++ b/src/action/caseApiActions.ts @@ -45,13 +45,13 @@ const setUnifiedDataLoading = (queryParams: Record, loanAccountNumbers: string[]) => (dispatch: AppDispatch) => { if (queryParams[UnifiedCaseDetailsTypes.EMI_SCHEDULE]) { - dispatch(setEmiScheduleLoading(true)); + dispatch(setEmiScheduleLoading({loanAccountNumbers, isLoading : true})); } if (queryParams[UnifiedCaseDetailsTypes.FEEDBACKS]) { - dispatch(setFeedbackHistoryLoading(true)); + dispatch(setFeedbackHistoryLoading({loanAccountNumbers, isLoading : true})); } if (queryParams[UnifiedCaseDetailsTypes.REPAYMENTS]) { - dispatch(setRepaymentsLoading(true)); + dispatch(setRepaymentsLoading({loanAccountNumbers, isLoading : true})); } if (queryParams[UnifiedCaseDetailsTypes.ADDRESS_AND_GEOLOCATIONS]) { dispatch(setAddressLoading({loanAccountNumbers, isLoading : true})); @@ -116,9 +116,9 @@ export const getCaseUnifiedData = Promise.allSettled(promisesList).then(res => { dispatch(setUnifiedData(queryParams, loanAccountNumbers, res)); }).finally(() => { - dispatch(setEmiScheduleLoading(false)); - dispatch(setFeedbackHistoryLoading(false)); - dispatch(setRepaymentsLoading(false)); + dispatch(setEmiScheduleLoading({isLoading:false, loanAccountNumbers})); + dispatch(setFeedbackHistoryLoading({isLoading:false, loanAccountNumbers})); + dispatch(setRepaymentsLoading({isLoading:false, loanAccountNumbers})); dispatch(setAddressLoading({isLoading:false, loanAccountNumbers})) }); }; diff --git a/src/action/dataActions.ts b/src/action/dataActions.ts index c4cd28ec..3156c28a 100644 --- a/src/action/dataActions.ts +++ b/src/action/dataActions.ts @@ -21,18 +21,12 @@ import {logError} from '../components/utlis/errorUtils'; import {setFilters} from "../reducer/filtersSlice"; import { toast } from "../../RN-UI-LIB/src/components/toast"; import { ToastMessages } from '../screens/allCases/contants'; -import { getCaseUnifiedData, UnifiedCaseDetailsTypes } from './caseApiActions'; export const postPinnedList = - (pinnedCases: IPinnedCasesPayload[], updatedCaseList: ICaseItem[], type: string, newlyPinnedCasesLANs?: string[]) => + (pinnedCases: IPinnedCasesPayload[], updatedCaseList: ICaseItem[], type: string) => (dispatch: AppDispatch) => { dispatch(setVisitPlansUpdating(true)); - if(newlyPinnedCasesLANs?.length) { - const { EMI_SCHEDULE, REPAYMENTS, ADDRESS_AND_GEOLOCATIONS, FEEDBACKS } = UnifiedCaseDetailsTypes; - getCaseUnifiedData(newlyPinnedCasesLANs, [EMI_SCHEDULE, REPAYMENTS, ADDRESS_AND_GEOLOCATIONS, FEEDBACKS]); - } - const url = getApiUrl(ApiKeys.PINNED_CASES); axiosInstance .post(url, pinnedCases) diff --git a/src/reducer/allCasesSlice.ts b/src/reducer/allCasesSlice.ts index f607e05d..1ace7d65 100644 --- a/src/reducer/allCasesSlice.ts +++ b/src/reducer/allCasesSlice.ts @@ -10,6 +10,7 @@ import { navigateToScreen, } from '../components/utlis/navigationUtlis'; import { CaseUpdates } from '../hooks/useFirestoreUpdates'; +import { COMPLETED_STATUSES } from '../screens/allCases/contants'; import { CaseStatuses, @@ -28,7 +29,6 @@ export type ICasesMap = { [key: string]: ICaseItem }; interface IAllCasesSlice { casesList: ICaseItem[]; - pinnedList: ICaseItem[]; casesListMap: ICasesMap; intermediateTodoList: ICaseItem[]; intermediateTodoListMap: ICasesMap; @@ -44,11 +44,14 @@ interface IAllCasesSlice { searchQuery: string; isOnboarded: boolean; visitPlansUpdating: boolean; + pendingList:ICaseItem[]; + completedList:ICaseItem[]; + pinnedList:ICaseItem[]; + newVisitedCases: string[]; } const initialState: IAllCasesSlice = { casesList: [], - pinnedList: [], casesListMap: {}, intermediateTodoList: [], intermediateTodoListMap: {}, @@ -64,6 +67,27 @@ const initialState: IAllCasesSlice = { searchQuery: '', isOnboarded: false, visitPlansUpdating: false, + pendingList: [], + completedList: [], + pinnedList: [], + newVisitedCases: [] +}; + +const getCaseListComponents = (casesList: ICaseItem[], caseDetails: Record) => { + const pendingList: ICaseItem[] = []; + const completedList: ICaseItem[] = []; + const pinnedList: ICaseItem[] = []; + casesList.forEach(item => { + const { caseReferenceId, pinRank } = item; + const { caseStatus } = caseDetails[caseReferenceId]; + const isCaseCompleted = COMPLETED_STATUSES.includes(caseStatus); + isCaseCompleted + ? completedList.push(item) + : pinRank + ? pinnedList.push(item) + : pendingList.push(item); + }); + return { pendingList, completedList, pinnedList }; }; const getPinnedListDetails = (casesList: ICaseItem[]) => { @@ -207,7 +231,8 @@ const allCasesSlice = createSlice({ if (state.loading) { state.loading = false; } - let newVisitedCases = 0; + let newVisitCaseCount: number = 0; + let newVisitCases: string[] = []; let removedVisitedCases = 0; caseUpdates.forEach(({ updateType, updatedCaseDetail }) => { const { caseType, caseReferenceId, id, pinRank } = @@ -221,7 +246,10 @@ const allCasesSlice = createSlice({ ); if (index !== -1) { if (pinRank && !state.casesList[index].pinRank) { - newVisitedCases++; + newVisitCaseCount++; + if(caseType === CaseAllocationType.COLLECTION_CASE) { + newVisitCases.push(caseId); + } } if(!pinRank && state.casesList[index].pinRank) { removedVisitedCases++; @@ -253,6 +281,9 @@ const allCasesSlice = createSlice({ if (state.caseDetails[caseId]) { return; } + if(pinRank && caseType === CaseAllocationType.COLLECTION_CASE) { + newVisitCases.push(caseId); + } const caseListItem = { caseReferenceId: caseId, pinRank: pinRank || null, @@ -298,11 +329,17 @@ const allCasesSlice = createSlice({ break; } }); - if (newVisitedCases) { + const { pendingList, completedList, pinnedList } = getCaseListComponents(state.casesList, state.caseDetails); + state.pendingList = pendingList; + state.completedList = completedList; + state.pinnedList = pinnedList; + state.newVisitedCases = newVisitCases; + + if (newVisitCaseCount) { toast({ type: 'info', - text1: `${newVisitedCases} case${ - newVisitedCases > 1 ? 's' : '' + text1: `${newVisitCaseCount} case${ + newVisitCaseCount > 1 ? 's' : '' } added to the visit plan`, }); return; @@ -438,7 +475,6 @@ const allCasesSlice = createSlice({ }, resetCasesData: state => { state.casesList = []; - state.pinnedList = []; state.casesListMap = {}; state.intermediateTodoList = []; state.intermediateTodoListMap = {}; @@ -453,10 +489,17 @@ const allCasesSlice = createSlice({ state.caseDetails = {}; state.searchQuery = ''; state.isOnboarded = state.isOnboarded; + state.newVisitedCases = []; + state.pendingList = []; + state.pinnedList = []; + state.completedList = []; }, setVisitPlansUpdating: (state, action) => { state.visitPlansUpdating = action.payload; }, + resetNewVisitedCases: (state) => { + state.newVisitedCases = []; + } }, }); @@ -476,7 +519,8 @@ export const { toggleNewlyAddedCase, resetCasesData, updateCaseDetailBeforeApiCall, - setVisitPlansUpdating + setVisitPlansUpdating, + resetNewVisitedCases, } = allCasesSlice.actions; export default allCasesSlice.reducer; diff --git a/src/reducer/emiScheduleSlice.ts b/src/reducer/emiScheduleSlice.ts index aec621e0..9d656258 100644 --- a/src/reducer/emiScheduleSlice.ts +++ b/src/reducer/emiScheduleSlice.ts @@ -1,17 +1,12 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; + interface IEmiScheduleState { - //TODO: update interface of EMISchedule instead of any - data: Record; - isLoading: boolean; - timestamp: string; + //TODO: update interface of EmiSchedule instead of any + [loanAccountNumber: string] : {data : any, isLoading: boolean, timestamp: string }; } -const initialState: IEmiScheduleState = { - data: {}, - isLoading: false, - timestamp: '' -}; +const initialState: IEmiScheduleState = {}; const EmiScheduleSlice = createSlice({ name: 'emiSchedule', @@ -19,12 +14,13 @@ const EmiScheduleSlice = createSlice({ reducers: { setEmiSchedule: (state, action) => { const { loanAccountNumber, emiSchedule } = action.payload; - state.timestamp = new Date().toISOString(); - state.data[loanAccountNumber] = emiSchedule; - state.isLoading = false; + state[loanAccountNumber] = {data: emiSchedule, timestamp: new Date().toISOString(),isLoading: false } }, - setEmiScheduleLoading: (state, action: PayloadAction) => { - state.isLoading = action.payload; + setEmiScheduleLoading: (state, action: PayloadAction<{ loanAccountNumbers: string[], isLoading: boolean }>) => { + const payloadData = action.payload + payloadData.loanAccountNumbers.forEach((loanAccNumber)=>{ + state[loanAccNumber] = {...(state?.[loanAccNumber] || []), isLoading: payloadData.isLoading} + }) }, }, }); diff --git a/src/reducer/feedbackHistorySlice.ts b/src/reducer/feedbackHistorySlice.ts index 7531405a..4256bbab 100644 --- a/src/reducer/feedbackHistorySlice.ts +++ b/src/reducer/feedbackHistorySlice.ts @@ -2,16 +2,10 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; interface IFeedbackHistoryState { //TODO: update interface of FeedbackHistory instead of any - data: Record; - isLoading: boolean; - timestamp: string; + [loanAccountNumber: string] : {data : any, isLoading: boolean, timestamp: string }; } -const initialState: IFeedbackHistoryState = { - data: {}, - isLoading: false, - timestamp: '' -}; +const initialState: IFeedbackHistoryState = {}; const FeedbackHistorySlice = createSlice({ name: 'feedbackHistory', @@ -19,12 +13,13 @@ const FeedbackHistorySlice = createSlice({ reducers: { setFeedbackHistory: (state, action) => { const { loanAccountNumber, feedbacks } = action.payload; - state.timestamp = new Date().toISOString(); - state.data[loanAccountNumber] = feedbacks; - state.isLoading = false; + state[loanAccountNumber] = {data: feedbacks, timestamp: new Date().toISOString(),isLoading: false } }, - setFeedbackHistoryLoading: (state, action: PayloadAction) => { - state.isLoading = action.payload; + setFeedbackHistoryLoading: (state, action: PayloadAction<{ loanAccountNumbers: string[], isLoading: boolean }>) => { + const payloadData = action.payload + payloadData.loanAccountNumbers.forEach((loanAccNumber)=>{ + state[loanAccNumber] = {...(state?.[loanAccNumber] || []), isLoading: payloadData.isLoading} + }) }, }, }); diff --git a/src/reducer/repaymentsSlice.ts b/src/reducer/repaymentsSlice.ts index bbce1d57..6bb14269 100644 --- a/src/reducer/repaymentsSlice.ts +++ b/src/reducer/repaymentsSlice.ts @@ -2,16 +2,10 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; interface IRepaymentsState { //TODO: update interface of Repayments instead of any - data: Record; - isLoading: boolean; - timestamp: string; + [loanAccountNumber: string] : {data : any, isLoading: boolean, timestamp: string }; } -const initialState: IRepaymentsState = { - data: {}, - isLoading: false, - timestamp: '' -}; +const initialState: IRepaymentsState = {}; const RepaymentsSlice = createSlice({ name: 'repayments', @@ -19,12 +13,13 @@ const RepaymentsSlice = createSlice({ reducers: { setRepayments: (state, action) => { const { loanAccountNumber, repayments } = action.payload; - state.timestamp = new Date().toISOString(); - state.data[loanAccountNumber] = repayments; - state.isLoading = false; + state[loanAccountNumber] = {data: repayments, timestamp: new Date().toISOString(),isLoading: false } }, - setRepaymentsLoading: (state, action: PayloadAction) => { - state.isLoading = action.payload; + setRepaymentsLoading: (state, action: PayloadAction<{ loanAccountNumbers: string[], isLoading: boolean }>) => { + const payloadData = action.payload + payloadData.loanAccountNumbers.forEach((loanAccNumber)=>{ + state[loanAccNumber] = {...(state?.[loanAccNumber] || []), isLoading: payloadData.isLoading} + }) }, }, }); diff --git a/src/screens/allCases/index.tsx b/src/screens/allCases/index.tsx index e608083b..1eb5071b 100644 --- a/src/screens/allCases/index.tsx +++ b/src/screens/allCases/index.tsx @@ -1,7 +1,6 @@ import React, { useEffect, useMemo } from 'react'; import { useAppDispatch, useAppSelector } from '../../hooks'; import CasesList from './CasesList'; -import { ICaseItem } from './interface'; import { RootState } from '../../store/store'; import { initCrashlytics } from '../../components/utlis/firebaseUtils'; import Layout from '../layout/Layout'; @@ -12,14 +11,13 @@ import CasesIcon from '../../../RN-UI-LIB/src/Icons/CasesIcon'; import Profile from '../Profile'; import ProfileIcon from '../../../RN-UI-LIB/src/Icons/ProfileIcon'; import VisitPlanIcon from '../../../RN-UI-LIB/src/Icons/VisitPlanIcon'; -import { COMPLETED_STATUSES, ListHeaderItems } from './contants'; import CasesActionButtons from './CasesActionButtons'; import FullScreenLoader from '../../../RN-UI-LIB/src/components/FullScreenLoader'; import { getCurrentScreen } from '../../components/utlis/navigationUtlis'; import { resetSelectedTodoList, resetTodoList, setLoading, setVisitPlansUpdating } from '../../reducer/allCasesSlice'; const AllCasesMain = () => { - const { casesList, caseDetails, loading } = useAppSelector(state => state.allCases); + const { pendingList, completedList, pinnedList, loading } = useAppSelector(state => state.allCases); const userState = useAppSelector((state: RootState) => state.user); const dispatch = useAppDispatch(); @@ -27,23 +25,6 @@ const AllCasesMain = () => { (state: RootState) => state.allCases, ); - const { pendingList, completedList, pinnedList } = useMemo(() => { - const pendingList: ICaseItem[] = []; - const completedList: ICaseItem[] = []; - const pinnedList: ICaseItem[] = []; - casesList.forEach(item => { - const { caseReferenceId, pinRank } = item; - const { caseStatus } = caseDetails[caseReferenceId]; - const isCaseCompleted = COMPLETED_STATUSES.includes(caseStatus); - isCaseCompleted - ? completedList.push(item) - : pinRank - ? pinnedList.push(item) - : pendingList.push(item); - }); - return { pendingList, completedList, pinnedList }; - }, [casesList, caseDetails, selectedTodoListCount]); - const HOME_SCREENS: ITabScreen[] = useMemo( () => [ { diff --git a/src/screens/caseDetails/feedback/FeedbackListContainer.tsx b/src/screens/caseDetails/feedback/FeedbackListContainer.tsx index 7aa5f576..7bd4ee87 100644 --- a/src/screens/caseDetails/feedback/FeedbackListContainer.tsx +++ b/src/screens/caseDetails/feedback/FeedbackListContainer.tsx @@ -85,6 +85,9 @@ const FeedbackListContainer: React.FC = ({ loanAccountNu } useEffect(() => { + if(!loanAccountNumber) { + return; + } if (isOnline || !feedbackList) { dispatch(getCaseUnifiedData([loanAccountNumber], [UnifiedCaseDetailsTypes.FEEDBACKS])) } diff --git a/src/screens/todoList/TodoList.tsx b/src/screens/todoList/TodoList.tsx index 2a1c1e1c..a7922727 100644 --- a/src/screens/todoList/TodoList.tsx +++ b/src/screens/todoList/TodoList.tsx @@ -63,7 +63,6 @@ const TodoList = () => { } const updatedPinnedList: ICaseItem[] = []; const pinnedCasesPayload: IPinnedCasesPayload[] = []; - const newlyPinnedCasesLANs: string[] = []; const updatedCaseList = casesList.map(caseItem => { const { caseReferenceId } = caseItem; const pinnedItem = @@ -83,9 +82,6 @@ const TodoList = () => { updatedPinnedList.push(pinnedItem); pinnedCasePayload.pinRank = pinnedItem.pinRank; pinnedCasesPayload.push(pinnedCasePayload); - if(caseType === CaseAllocationType.COLLECTION_CASE && loanAccountNumber) { - newlyPinnedCasesLANs.push(loanAccountNumber); - } } return pinnedItem ? pinnedItem : caseItem; }); @@ -97,7 +93,7 @@ const TodoList = () => { return caseA.pinRank - caseB.pinRank }, ); - dispatch(postPinnedList(sortedPinnedCasesPayload, updatedCaseList, 'ADDED', newlyPinnedCasesLANs)); + dispatch(postPinnedList(sortedPinnedCasesPayload, updatedCaseList, 'ADDED')); }; const handleCancelTodoList = () => {