107 lines
4.3 KiB
TypeScript
107 lines
4.3 KiB
TypeScript
import { useEffect, useRef } from 'react';
|
|
|
|
import { useAppDispatch, useAppSelector } from '../app/hooks';
|
|
import {
|
|
bootstrapAuthSession,
|
|
loadSignInContext,
|
|
logoutSession,
|
|
} from '../modules/auth/store/authThunk';
|
|
import { selectIsAuthenticated } from '../modules/auth/store/authSelectors';
|
|
import { seedDashboardState } from '../modules/home/store/accountThunk';
|
|
import { seedBeneficiaries } from '../modules/transfer/store/transferThunk';
|
|
import { seedRecentPayees } from '../modules/payments/store/paymentsThunk';
|
|
import { seedDepositProducts } from '../modules/deposit/store/depositThunk';
|
|
import {
|
|
seedServiceRequests,
|
|
seedSupportMessages,
|
|
} from '../modules/services/store/serviceThunk';
|
|
import { seedLoanProducts } from '../modules/loan/store/loanThunk';
|
|
import { seedInsurancePlans } from '../modules/insurance/store/insuranceThunk';
|
|
import { seedCards } from '../modules/cards/store/cardsThunk';
|
|
import { seedUserProfile } from '../modules/profile/store/userThunk';
|
|
import { markAppReady } from '../modules/ui/store/uiThunk';
|
|
import { env } from '../config/env';
|
|
import { featureRemoteConfig } from '../features';
|
|
import { registerUnauthorizedHandler } from '../services/api/interceptors';
|
|
import { registerForPushNotifications } from '../services/notifications/pushNotifications';
|
|
import { useSessionTimeout } from './useSessionTimeout';
|
|
import { useToast } from './useToast';
|
|
|
|
/**
|
|
* Populates the modules that have no CBS backend behind them yet — the
|
|
* dashboard, cards, loans, insurance, deposits, service requests and the agent
|
|
* app. Registration, sign-in, accounts/MMID and payees are live and are not
|
|
* seeded from here.
|
|
*/
|
|
const seedAllData = (dispatch: ReturnType<typeof useAppDispatch>) => {
|
|
dispatch(seedUserProfile());
|
|
dispatch(seedDashboardState());
|
|
dispatch(seedBeneficiaries());
|
|
dispatch(seedRecentPayees());
|
|
dispatch(seedDepositProducts());
|
|
dispatch(seedServiceRequests());
|
|
dispatch(seedSupportMessages());
|
|
dispatch(seedLoanProducts());
|
|
dispatch(seedInsurancePlans());
|
|
dispatch(seedCards());
|
|
};
|
|
|
|
export const useAppBootstrap = () => {
|
|
const dispatch = useAppDispatch();
|
|
const toast = useToast();
|
|
const isAuthenticated = useAppSelector(selectIsAuthenticated);
|
|
const wasAuthenticated = useRef(false);
|
|
|
|
useSessionTimeout();
|
|
|
|
// Initial bootstrap on mount. `bootstrapAuthSession` also mints the device id
|
|
// and validates any stored session against the server before trusting it.
|
|
useEffect(() => {
|
|
void dispatch(bootstrapAuthSession());
|
|
seedAllData(dispatch);
|
|
dispatch(markAppReady());
|
|
|
|
void registerForPushNotifications();
|
|
}, [dispatch]);
|
|
|
|
useEffect(() => {
|
|
if (isAuthenticated && !wasAuthenticated.current) {
|
|
// Logout wipes all Redux state, so profile/dashboard/etc. need
|
|
// re-populating when the user signs back in.
|
|
seedAllData(dispatch);
|
|
|
|
// The startup fetch ran unauthenticated, so it could only carry the
|
|
// org-wide scope. Now that there is a session the server can also tell us
|
|
// what this customer's role and tenant are allowed to see.
|
|
void featureRemoteConfig.refresh({ useMock: env.useMockServer });
|
|
}
|
|
|
|
if (!isAuthenticated && wasAuthenticated.current) {
|
|
// Role-scoped switches belong to the session that is ending. Leaving them
|
|
// in force would apply one customer's entitlements to whoever signs in
|
|
// next on this handset. The org-wide layer stays — it gates the sign-in
|
|
// screen itself.
|
|
featureRemoteConfig.clearRoleScope();
|
|
|
|
// That same wipe takes the remembered mobile number and the biometric
|
|
// flag with it, which the sign-in screen needs. Only those two are
|
|
// re-read — a full bootstrap would raise the hydrating flag and blank the
|
|
// app behind a loader on the way out.
|
|
void dispatch(loadSignInContext());
|
|
}
|
|
|
|
wasAuthenticated.current = isAuthenticated;
|
|
}, [isAuthenticated, dispatch]);
|
|
|
|
useEffect(() => {
|
|
const unregister = registerUnauthorizedHandler(() => {
|
|
// A token the server rejected, not a customer leaving — so the session
|
|
// goes and the registration stays. See `LogoutReason`.
|
|
void dispatch(logoutSession('unauthorized'));
|
|
toast('Signed out', 'info', 'Your session ended. Please sign in again.');
|
|
});
|
|
|
|
return unregister;
|
|
}, [dispatch, toast]);
|
|
};
|