Files
monorepo/LCU.WebApps.Collections.RepoClient/src/actions/RepoAccountActions.ts
T
2026-03-17 11:09:46 -05:00

547 lines
23 KiB
TypeScript

import axios from "axios";
import { LocationChangeAction } from "connected-react-router";
import { toast } from "react-toastify";
import { ActionCreator, Dispatch } from "redux";
import { ThunkAction } from "redux-thunk";
import RepoAccountService from "../services/RepoAccountService";
import { ICollateral, IRefundStatus, IRepoAccount, IRepoAccountFilters, IRepoCompanySelection, IRepoCompanySelectionPostResponse } from "../services/service-types/RepoAccountTypes";
import Configuration from "../shared/configuration/Configuration";
import AsyncState from "../shared/enumerations/AsyncState";
import UrlFormatting from "../shared/formatting/UrlFormatting";
import ServerLogging from "../shared/logging/ServerLogging";
import ToastDefaults from "../shared/notifications/ToastDefaults";
import IAsyncStateContainer from "../shared/types/IAsyncStateContainer";
import { IPagedResponse } from "../shared/types/IPagedResponse";
import { IAppState } from "../store/Store";
import { IAuctionAssignmentInsertFromPost } from "./AuctionAssignmentActions";
import {getUser} from "../adalConfig";
// Create Action Constants
export enum RepoAccountActionTypes {
SET_SELECTED_ACCOUNT = "REPOACCOUNT_SET_SELECTED_ACCOUNT",
INSERT_ONE_ACCOUNT = "REPOACCOUNT_INSERT_ONE",
INSERT_ACCOUNTS = "REPOACCOUNT_INSERT_ACCOUNTS",
SET_FILTERED_ACCOUNTS = "REPOACCOUNT_SET_FILTERED_ACCOUNTS",
INSERT_COLLATERAL = "REPOACCOUNT_INSERT_COLLATERAL",
SET_FILTERS = "REPOACCOUNT_SET_FILTERS",
UPDATE_REFUND_STATUS = "REPOACCOUNT_UPDATE_REFUND_STATUS",
SET_SEARCH_PHRASE = "REPOACCOUNT_SET_SEARCH_PHRASE"
}
export interface IRepoAccountSelectAccountAction {
type: RepoAccountActionTypes.SET_SELECTED_ACCOUNT;
repoId: IAsyncStateContainer<number>;
}
export interface IRepoAccountSetFilteredAccountsAction {
type: RepoAccountActionTypes.SET_FILTERED_ACCOUNTS;
filteredAccounts: IAsyncStateContainer<IPagedResponse<number>>;
}
export interface IRepoAccountInsertOneAccount {
type: RepoAccountActionTypes.INSERT_ONE_ACCOUNT;
repoAccount: IRepoAccount;
}
export interface IRepoAccountInsertAccounts {
type: RepoAccountActionTypes.INSERT_ACCOUNTS;
repoAccounts: IRepoAccount[];
}
export interface IRepoAccountInsertCollateral {
type: RepoAccountActionTypes.INSERT_COLLATERAL;
collateral: ICollateral;
}
export interface IRepoAccountSetAccountFiltersAction {
type: RepoAccountActionTypes.SET_FILTERS;
filters: IRepoAccountFilters;
}
export interface IRepoAccountUpdateRefundStatus {
type: RepoAccountActionTypes.UPDATE_REFUND_STATUS;
refundStatus: IRefundStatus;
}
export interface IRepoAccountSetSearchPhraseAction {
type: RepoAccountActionTypes.SET_SEARCH_PHRASE;
searchPhrase: string;
}
/*
Combine the action types with a union (we assume there are more)
example: export type RepoAccountActions = IGetAllAction | IGetOneAction ...
*/
export type RepoAccountActions =
IRepoAccountSelectAccountAction |
IRepoAccountSetFilteredAccountsAction |
IAuctionAssignmentInsertFromPost |
IRepoAccountInsertOneAccount |
IRepoAccountInsertAccounts |
IRepoAccountInsertCollateral |
IRepoAccountSetAccountFiltersAction |
IRepoAccountUpdateRefundStatus |
IRepoAccountSetSearchPhraseAction |
LocationChangeAction;
export const getInitialRepoAccounts: ActionCreator<ThunkAction<Promise<any>, IAppState, {}, IRepoAccountInsertAccounts | IRepoAccountSetFilteredAccountsAction | IRepoAccountSetFilteredAccountsAction>> = () => {
return async (dispatch, getState) => {
// Clear filters, as this fetch will not match the current filters
const newFilter: IRepoAccountFilters = {onlyOpenAccounts: getState().repoAccountState.accountFilters.onlyOpenAccounts};
dispatch({
type: RepoAccountActionTypes.SET_FILTERED_ACCOUNTS,
filteredAccounts: {
state: getState().repoAccountState.filteredAccounts.state
}
});
await postFilteredAccountsFromURL(Configuration.PrefixRepoApiUrl(Configuration.Get.urls.repoApi.accounts_filter), newFilter, dispatch);
};
};
export const setSearchPhrase = (searchPhrase: string): IRepoAccountSetSearchPhraseAction => {
return {
type: RepoAccountActionTypes.SET_SEARCH_PHRASE,
searchPhrase: searchPhrase
};
};
export const goToNextRepoAccountPage: ActionCreator<ThunkAction<Promise<any>, IAppState, {}, IRepoAccountSetAccountFiltersAction | IRepoAccountSetFilteredAccountsAction | IRepoAccountInsertAccounts>> = () => {
return async (dispatch, getState) => {
const currentFilters = getState().repoAccountState.accountFilters;
const filterPageResponse = getState().repoAccountState.filteredAccounts.data;
if (filterPageResponse && filterPageResponse.nextPage) {
await postFilteredAccountsFromURL(filterPageResponse.nextPage, currentFilters, dispatch);
}
};
};
export const goToPreviousRepoAccountPage: ActionCreator<ThunkAction<Promise<any>, IAppState, {}, IRepoAccountSetAccountFiltersAction | IRepoAccountSetFilteredAccountsAction | IRepoAccountInsertAccounts>> = () => {
return async (dispatch, getState) => {
const currentFilters = getState().repoAccountState.accountFilters;
const filterPageResponse = getState().repoAccountState.filteredAccounts.data;
if (filterPageResponse && filterPageResponse.previousPage) {
await postFilteredAccountsFromURL(filterPageResponse.previousPage, currentFilters, dispatch);
}
};
};
export const fetchSelectedRepoAccount: ActionCreator<ThunkAction<Promise<any>, IAppState, {}, IRepoAccountInsertOneAccount | IRepoAccountSelectAccountAction>> = (repoId: number) => {
const singleRepoURL = UrlFormatting.ReplaceURLParams(
Configuration.PrefixRepoApiUrl(Configuration.Get.urls.repoApi.accounts_single),
{key: "repoId", value: repoId},
);
return async (dispatch) => {
// Since we are fetching the selected account,
// we will need to dispatch both to insert the retrieved
// account, as well as to update the selected account
dispatch({
type: RepoAccountActionTypes.SET_SELECTED_ACCOUNT,
repoId: {
state: AsyncState.Loading
}
});
try {
const response = await axios.get(singleRepoURL);
RepoAccountService.ConvertResponseToRepoAccount(response.data);
dispatch({
type: RepoAccountActionTypes.INSERT_ONE_ACCOUNT,
repoAccount: response.data
});
dispatch({
type: RepoAccountActionTypes.SET_SELECTED_ACCOUNT,
repoId: {
state: AsyncState.Success,
data: response.data.repoId
}
});
} catch (err) {
ServerLogging.ResolveErrorWithToast(err, {
action: "Fetch Selected Repo Account",
user: getUser().userName,
url: singleRepoURL,
arguments: repoId
});
dispatch({
type: RepoAccountActionTypes.SET_SELECTED_ACCOUNT,
repoId: {
state: AsyncState.Failure
}
});
}
};
};
export const searchRepoAccounts: ActionCreator<ThunkAction<Promise<any>, IAppState, {}, IRepoAccountSetFilteredAccountsAction | IRepoAccountSetAccountFiltersAction | IRepoAccountSetSearchPhraseAction | IRepoAccountInsertAccounts>> = (searchPhrase: string) => {
const parameterizedUrl = UrlFormatting.ReplaceURLParams(
Configuration.PrefixRepoApiUrl(Configuration.Get.urls.repoApi.accounts_search),
{ key: "searchPhrase", value: searchPhrase }
);
// Since we are fetching the currently filtered accounts,
// we will need to dispatch both to insert the retrieved
// account, as well as to update the currently filtered accounts
return async (dispatch) => {
dispatch({
type: RepoAccountActionTypes.SET_FILTERED_ACCOUNTS,
filteredAccounts: {
state: AsyncState.Loading
}
});
dispatch({
type: RepoAccountActionTypes.SET_FILTERS,
filters: {}
});
dispatch({
type: RepoAccountActionTypes.SET_SEARCH_PHRASE,
searchPhrase: searchPhrase
});
try {
const response = await axios.get(parameterizedUrl);
RepoAccountService.ConvertResponseToRepoAccounts(response.data);
dispatch({
type: RepoAccountActionTypes.INSERT_ACCOUNTS,
repoAccounts: response.data
});
dispatch({
type: RepoAccountActionTypes.SET_FILTERED_ACCOUNTS,
filteredAccounts: {
state: AsyncState.Success,
data: {
items: RepoAccountService.CreateRepoAccountIdMap(response.data),
totalItems: response.data.length,
currentPage: 1,
totalPages: 1
}
}
});
} catch (err) {
ServerLogging.ResolveErrorWithToast(err, {
action: "Search Repo Accoutns",
user: getUser().userName,
url: parameterizedUrl,
arguments: searchPhrase
});
dispatch({
type: RepoAccountActionTypes.SET_FILTERED_ACCOUNTS,
filteredAccounts: {
state: AsyncState.Failure
}
});
}
};
};
export const removeRepoAccountFromAlertFilter: ActionCreator<ThunkAction<Promise<any>, IAppState, {}, IRepoAccountSetFilteredAccountsAction>> = (alertMessage: string, repoId: number) => {
return async (dispatch, getState) => {
const filteredAccounts = getState().repoAccountState.filteredAccounts;
const accountFilters = getState().repoAccountState.accountFilters;
if (filteredAccounts.data && alertMessage === accountFilters.alertMessage) {
const indexOfEl = filteredAccounts.data.items.indexOf(repoId);
if (indexOfEl >= 0) {
const updatedAccountItems = filteredAccounts.data.items.slice();
updatedAccountItems.splice(indexOfEl, 1);
dispatch({
type: RepoAccountActionTypes.SET_FILTERED_ACCOUNTS,
filteredAccounts: {
data: {
...filteredAccounts.data,
totalItems: filteredAccounts.data.totalItems - 1,
items: updatedAccountItems
},
state: filteredAccounts.state
}
});
}
}
};
};
export const fetchRepoAccountsViaFilters: ActionCreator<ThunkAction<Promise<any>, IAppState, {}, IRepoAccountSetAccountFiltersAction | IRepoAccountSetFilteredAccountsAction | IRepoAccountSetSearchPhraseAction | IRepoAccountInsertAccounts>> =
(filters: IRepoAccountFilters) => {
return async (dispatch) => {
dispatch({
type: RepoAccountActionTypes.SET_FILTERS,
filters: filters
});
dispatch({
type: RepoAccountActionTypes.SET_SEARCH_PHRASE,
searchPhrase: ""
});
await postFilteredAccountsFromURL(Configuration.PrefixRepoApiUrl(Configuration.Get.urls.repoApi.accounts_filter), filters, dispatch);
};
};
export const postToNextFilterPage: ActionCreator<ThunkAction<Promise<any>, IAppState, {}, IRepoAccountSetFilteredAccountsAction | IRepoAccountInsertAccounts>> =
(nextPageUrl: string, filters: IRepoAccountFilters) => {
return async (dispatch: Dispatch<IRepoAccountSetAccountFiltersAction | IRepoAccountSetFilteredAccountsAction | IRepoAccountInsertAccounts>) => {
await postFilteredAccountsFromURL(nextPageUrl, filters, dispatch);
};
};
export const putRepoAccount: ActionCreator<ThunkAction<Promise<any>, IAppState, {}, IRepoAccountInsertOneAccount>> = (account: IRepoAccount) => {
const url = Configuration.PrefixRepoApiUrl(Configuration.Get.urls.repoApi.accounts) + "/" + account.repoId;
return async (dispatch: Dispatch<IRepoAccountInsertOneAccount>) => {
try {
const response = await axios.put(url, account);
RepoAccountService.ConvertResponseToRepoAccount(response.data);
dispatch({
type: RepoAccountActionTypes.INSERT_ONE_ACCOUNT,
repoAccount: response.data
});
toast.success("Account Updated.", ToastDefaults.baseParams);
} catch (err) {
ServerLogging.ResolveErrorWithToast(err, {
action: "Put Repo Account",
user: getUser().userName,
url: url,
arguments: account
});
}
};
};
export const putCollateral: ActionCreator<ThunkAction<Promise<any>, ICollateral, null, IRepoAccountInsertCollateral>> = (collateral: ICollateral) => {
const singleCollateralUrl = UrlFormatting.ReplaceURLParams(
Configuration.PrefixRepoApiUrl(Configuration.Get.urls.repoApi.collateral_single),
{key: "collateralId", value: collateral.collateralId},
);
return async (dispatch) => {
try {
const response = await axios.put(
singleCollateralUrl,
collateral
);
RepoAccountService.ConvertResponseToCollateral(response.data);
dispatch({
type: RepoAccountActionTypes.INSERT_COLLATERAL,
collateral: response.data
});
toast.success("Collateral Updated.", ToastDefaults.baseParams);
} catch (err) {
ServerLogging.ResolveErrorWithToast(err, {
action: "Put Collateral",
user: getUser().userName,
url: singleCollateralUrl,
arguments: collateral
});
}
};
};
export const putRepoCompanySelection: ActionCreator<ThunkAction<Promise<any>, IAppState, {}, IRepoAccountInsertCollateral>> = (repoCompanySelection: IRepoCompanySelection, collateral: ICollateral) => {
const repoCompanySelectionPutURL = UrlFormatting.ReplaceURLParams(
Configuration.PrefixRepoApiUrl(Configuration.Get.urls.repoApi.repo_company_selection_single),
{key: "repoCompanySelectionId", value: repoCompanySelection.id},
);
return async (dispatch) => {
try {
const response = await axios.put(
repoCompanySelectionPutURL,
repoCompanySelection
);
RepoAccountService.ConvertResponseToRepoCompanySelection(response.data);
dispatch({
type: RepoAccountActionTypes.INSERT_COLLATERAL,
collateral: RepoAccountService.CreateCollateralFromRepoCompanySelection(collateral, repoCompanySelection)
});
toast.success("Repo Selection Updated.", ToastDefaults.baseParams);
} catch (err) {
ServerLogging.ResolveErrorWithToast(err, {
action: "Put Repo Company Selection",
user: getUser().userName,
url: repoCompanySelectionPutURL,
arguments: [repoCompanySelection, collateral]
});
}
};
};
export const postRepoCompanySelection: ActionCreator<ThunkAction<Promise<any>, IAppState, {}, IRepoAccountInsertCollateral>> = (repoCompanySelection: IRepoCompanySelection, collateral: ICollateral) => {
const repoCompanySelectionPostURL = Configuration.PrefixRepoApiUrl(Configuration.Get.urls.repoApi.repo_company_selection);
return async (dispatch) => {
try {
const response = await axios.post(
repoCompanySelectionPostURL,
repoCompanySelection
);
let responseData = response.data as IRepoCompanySelectionPostResponse;
const repoCompanySelectionArray = [
responseData.newRepoCompanySelection
];
RepoAccountService.ConvertResponseToRepoCompanySelection(responseData.newRepoCompanySelection);
if (responseData.previousRepoCompanySelection) {
RepoAccountService.ConvertResponseToRepoCompanySelection(responseData.previousRepoCompanySelection);
repoCompanySelectionArray.push(responseData.previousRepoCompanySelection);
}
dispatch({
type: RepoAccountActionTypes.INSERT_COLLATERAL,
collateral: RepoAccountService.CreateCollateralFromRepoCompanySelection(collateral, repoCompanySelectionArray)
});
toast.success("Repo Selection Updated.", ToastDefaults.baseParams);
} catch (err) {
ServerLogging.ResolveErrorWithToast(err, {
action: "Post Repo Company Selection",
user: getUser().userName,
url: repoCompanySelectionPostURL,
arguments: [repoCompanySelection, collateral]
});
}
};
};
export const putRefundStatus: ActionCreator<ThunkAction<Promise<any>, IAppState, {}, IRepoAccountUpdateRefundStatus>> = (refundStatus: IRefundStatus) => {
const refundStatusPutUrl = UrlFormatting.ReplaceURLParams(
Configuration.PrefixRepoApiUrl(Configuration.Get.urls.repoApi.refund_status_single),
{key: "repoId", value: refundStatus.repoId}
);
return async (dispatch) => {
try {
const response = await axios.put(refundStatusPutUrl, refundStatus);
RepoAccountService.ConvertResponseToRefundStatus(response.data);
dispatch({
type: RepoAccountActionTypes.UPDATE_REFUND_STATUS,
refundStatus: response.data
});
toast.success("Refund Status Updated.", ToastDefaults.baseParams);
} catch (err) {
ServerLogging.ResolveErrorWithToast(err, {
action: "Put Refund Status",
user: getUser().userName,
url: refundStatusPutUrl,
arguments: refundStatus
});
}
};
};
export const postRefundStatus: ActionCreator<ThunkAction<Promise<any>, IAppState, {}, IRepoAccountUpdateRefundStatus>> = (refundStatus: IRefundStatus) => {
const refundStatusPutUrl = Configuration.PrefixRepoApiUrl(Configuration.Get.urls.repoApi.refund_status);
return async (dispatch) => {
try {
const response = await axios.post(refundStatusPutUrl, refundStatus);
RepoAccountService.ConvertResponseToRefundStatus(response.data);
dispatch({
type: RepoAccountActionTypes.UPDATE_REFUND_STATUS,
refundStatus: response.data
});
toast.success("Refund Status Created.", ToastDefaults.baseParams);
} catch (err) {
ServerLogging.ResolveErrorWithToast(err, {
action: "Post Refund Status",
user: getUser().userName,
url: refundStatusPutUrl,
arguments: refundStatus
});
}
};
};
export const refreshCollateral: ActionCreator<ThunkAction<Promise<any>, IAppState, {}, IRepoAccountInsertCollateral>> = (
collateral: ICollateral, memberNo: number, loanNo: number) => {
const coresCollateralUrl = UrlFormatting.ReplaceURLParams(
Configuration.PrefixCoreUrl(Configuration.Get.urls.core.loan_collateral),
{key: "loanNo", value: loanNo},
);
return async (dispatch) => {
try {
const singleRepoCollateralUrl = UrlFormatting.ReplaceURLParams(
Configuration.PrefixRepoApiUrl(Configuration.Get.urls.repoApi.collateral_single),
{key: "collateralId", value: collateral.collateralId},
);
const response = await axios.get(coresCollateralUrl);
const updatedCollateral = updateCollateralWithCoreDetails(response.data, collateral);
await axios.put(
singleRepoCollateralUrl,
updatedCollateral,
);
dispatch({
type: RepoAccountActionTypes.INSERT_COLLATERAL,
collateral: updatedCollateral,
});
toast.success("Collateral Refreshed.", ToastDefaults.baseParams);
} catch (err) {
ServerLogging.ResolveErrorWithToast(err, {
action: "Refresh Collateral",
user: getUser().userName,
url: coresCollateralUrl,
arguments: [collateral, memberNo, loanNo]
});
}
};
};
const updateCollateralWithCoreDetails = (data: any[], collateral: ICollateral): ICollateral => {
// eslint-disable-next-line
const found = data.find(c => c.collateralId == collateral.refCollateralId);
if (found.other.miscellaneousInformation != null) {
collateral.vin = found.other.miscellaneousInformation;
}
if (found.vehicle != null) {
collateral.make = found.vehicle.make;
collateral.model = found.vehicle.model;
collateral.vin = found.vehicle.vin;
collateral.year = found.vehicle.year;
}
return collateral;
};
const fetchFilteredAccountsFromAsyncCallback = async (
repoAccountFetch: () => Promise<IPagedResponse<IRepoAccount>>,
dispatch: Dispatch<IRepoAccountInsertAccounts | IRepoAccountSetFilteredAccountsAction>
) => {
dispatch({
type: RepoAccountActionTypes.SET_FILTERED_ACCOUNTS,
filteredAccounts: {
state: AsyncState.Loading
}
});
try {
const pagedResponse = await repoAccountFetch();
RepoAccountService.ConvertResponseToRepoAccounts(pagedResponse.items);
dispatch({
type: RepoAccountActionTypes.INSERT_ACCOUNTS,
repoAccounts: pagedResponse.items
});
dispatch({
type: RepoAccountActionTypes.SET_FILTERED_ACCOUNTS,
filteredAccounts: {
state: AsyncState.Success,
data: {
items: RepoAccountService.CreateRepoAccountIdMap(pagedResponse.items),
totalItems: pagedResponse.totalItems,
nextPage: pagedResponse.nextPage,
previousPage: pagedResponse.previousPage,
currentPage: pagedResponse.currentPage,
totalPages: pagedResponse.totalPages
}
}
});
} catch (err) {
ServerLogging.ResolveErrorWithToast(err, {
action: "Fetch Filtered Accounts With Async",
user: getUser().userName,
});
dispatch({
type: RepoAccountActionTypes.SET_FILTERED_ACCOUNTS,
filteredAccounts: {
state: AsyncState.Failure
}
});
}
};
const postFilteredAccountsFromURL = async (url: string, filters: IRepoAccountFilters, dispatch: Dispatch<IRepoAccountInsertAccounts | IRepoAccountSetFilteredAccountsAction>) => {
fetchFilteredAccountsFromAsyncCallback(async () => {
const response = await axios.post(url, filters);
return response.data as IPagedResponse<IRepoAccount>;
}, dispatch);
};