diff --git a/src/App.tsx b/src/App.tsx index fed6afc22..559ec89ee 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -10,6 +10,7 @@ import './i18n/config'; import './styles/main.scss'; import { initializeWatchHistory } from './stores/WatchHistoryStore'; import { initializeFavorites } from './stores/FavoritesStore'; +import { initializeAccount } from './stores/AccountStore'; interface State { error: Error | null; @@ -30,6 +31,7 @@ class App extends Component { } initializeFavorites(); + initializeAccount(); } configLoadingHandler = (isLoading: boolean) => { diff --git a/src/services/account.service.ts b/src/services/account.service.ts index 0546b4bce..9523a0195 100644 --- a/src/services/account.service.ts +++ b/src/services/account.service.ts @@ -1,4 +1,12 @@ -import type { ChangePassword, GetCustomer, Login, Register, ResetPassword, UpdateCustomer } from '../../types/account'; +import type { + ChangePassword, + GetCustomer, + Login, + RefreshToken, + Register, + ResetPassword, + UpdateCustomer, +} from '../../types/account'; import { post, put, patch, get } from './cleeng.service'; @@ -25,3 +33,7 @@ export const updateCustomer: UpdateCustomer = async (payload, sandbox, jwt) => { export const getCustomer: GetCustomer = async (payload, sandbox, jwt) => { return get(sandbox, `/customers/${payload.customerId}`, jwt); }; + +export const refreshToken: RefreshToken = async (payload, sandbox) => { + return post(sandbox, '/auths/refresh_token', JSON.stringify(payload)); +}; diff --git a/src/stores/AccountStore.ts b/src/stores/AccountStore.ts index 693629ea0..8ee889cf6 100644 --- a/src/stores/AccountStore.ts +++ b/src/stores/AccountStore.ts @@ -3,9 +3,12 @@ import jwtDecode from 'jwt-decode'; import * as accountService from '../services/account.service'; import type { AuthData, Customer, JwtDetails } from '../../types/account'; +import * as persist from '../utils/persist'; import { ConfigStore } from './ConfigStore'; +const PERSIST_KEY_ACCOUNT = 'auth'; + type AccountStore = { auth: AuthData | null; user: Customer | null; @@ -16,10 +19,55 @@ export const AccountStore = new Store({ user: null, }); +export const initializeAccount = async () => { + const { config } = ConfigStore.getRawState(); + const storedSession: AuthData | null = persist.getItem(PERSIST_KEY_ACCOUNT) as AuthData | null; + let refreshTimeout: number; + + AccountStore.subscribe( + (state) => state.auth, + (authData) => { + window.clearTimeout(refreshTimeout); + + if (authData) { + refreshTimeout = window.setTimeout(() => refreshJwtToken(config.cleengSandbox, authData), 60 * 1000); + } + + persist.setItem(PERSIST_KEY_ACCOUNT, authData); + }, + ); + + // restore session from localStorage + if (storedSession) { + const refreshedAuthData = await getFreshJwtToken(config.cleengSandbox, storedSession); + + if (refreshedAuthData) { + await afterLogin(config.cleengSandbox, refreshedAuthData); + } + } +}; + +const getFreshJwtToken = async (sandbox: boolean, auth: AuthData) => { + const result = await accountService.refreshToken({ refreshToken: auth.refreshToken }, sandbox); + + if (result?.responseData) { + return result.responseData; + } +}; + +const refreshJwtToken = async (sandbox: boolean, auth: AuthData) => { + const authData = await getFreshJwtToken(sandbox, auth); + + if (authData) { + AccountStore.update(s => { + s.auth = { ...s.auth, ...authData }; + }); + } +}; + const afterLogin = async (sandbox: boolean, auth: AuthData) => { const decodedToken: JwtDetails = jwtDecode(auth.jwt); const customerId = decodedToken.customerId.toString(); - const response = await accountService.getCustomer({ customerId }, sandbox, auth.jwt); if (response.errors.length) throw new Error(response.errors[0]); diff --git a/types/account.d.ts b/types/account.d.ts index 1e3a1f8e5..637c893c1 100644 --- a/types/account.d.ts +++ b/types/account.d.ts @@ -3,6 +3,7 @@ import type { Offer } from './checkout'; export type AuthData = { jwt: string; customerToken: string; + refreshToken: string; }; export type JwtDetails = { @@ -69,6 +70,10 @@ export type UpdateCustomerPayload = { lastName?: string; }; +export type RefreshTokenPayload = { + refreshToken: string; +}; + export type Customer = { id: string; email: string; @@ -88,3 +93,4 @@ type ResetPassword = CleengRequest type ChangePassword = CleengRequest>; type GetCustomer = CleengAuthRequest; type UpdateCustomer = CleengAuthRequest; +type RefreshToken = CleengRequest;