From b28d0a2483cb7936a4663c3b4ced5887634222f9 Mon Sep 17 00:00:00 2001 From: Filip Naumovski Date: Thu, 1 Jun 2023 15:48:54 +0200 Subject: [PATCH] feat: add initial handling for simultaneous login websocket --- src/components/Root/Root.tsx | 13 +++++- src/services/inplayer.account.service.ts | 4 +- src/stores/AccountController.ts | 22 +++++++--- src/stores/NotificationsController.ts | 55 +++++++++++++----------- 4 files changed, 62 insertions(+), 32 deletions(-) diff --git a/src/components/Root/Root.tsx b/src/components/Root/Root.tsx index cea81670c..95c2fe5d4 100644 --- a/src/components/Root/Root.tsx +++ b/src/components/Root/Root.tsx @@ -1,4 +1,4 @@ -import React, { FC, useEffect, useMemo } from 'react'; +import React, { FC, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useQuery } from 'react-query'; import { useSearchParams } from 'react-router-dom'; @@ -14,6 +14,8 @@ import { loadAndValidateConfig } from '#src/utils/configLoad'; import { initSettings } from '#src/stores/SettingsController'; import AppRoutes from '#src/containers/AppRoutes/AppRoutes'; import registerCustomScreens from '#src/screenMapping'; +import { useAccountStore } from '#src/stores/AccountStore'; +import { subscribeToNotifications } from '#src/stores/NotificationsController'; const Root: FC = () => { const { t } = useTranslation('error'); @@ -45,6 +47,15 @@ const Root: FC = () => { registerCustomScreens(); }, []); + const user = useAccountStore((state) => state.user); + const [isSubscribed, setIsSubscribed] = useState(false); + useEffect(() => { + if (!isSubscribed && user?.id && user?.uuid) { + subscribeToNotifications(user.uuid); + setIsSubscribed(true); + } + }, [user?.id, user?.uuid, isSubscribed]); + const IS_DEMO_OR_PREVIEW = IS_DEMO_MODE || IS_PREVIEW_MODE; // Show the spinner while loading except in demo mode (the demo config shows its own loading status) diff --git a/src/services/inplayer.account.service.ts b/src/services/inplayer.account.service.ts index 20e1f4368..60b76288c 100644 --- a/src/services/inplayer.account.service.ts +++ b/src/services/inplayer.account.service.ts @@ -94,8 +94,8 @@ export const register: Register = async ({ config, email, password }) => { export const logout = async () => { try { - await InPlayer.Account.signOut(); - return InPlayer.Notifications.unsubscribe(); + InPlayer.Notifications.unsubscribe(); + InPlayer.Account.signOut(); } catch { throw new Error('Failed to sign out.'); } diff --git a/src/stores/AccountController.ts b/src/stores/AccountController.ts index 6b8f42e6b..e99076ab3 100644 --- a/src/stores/AccountController.ts +++ b/src/stores/AccountController.ts @@ -178,12 +178,24 @@ export const refreshJwtToken = async (auth: AuthData) => { export const getAccount = async (auth: AuthData) => { await useService(async ({ accountService, config, accessModel }) => { - const response = await accountService.getUser({ config, auth }); - if (response) { - await afterLogin(auth, response.user, response.customerConsents, accessModel); - } + try { + const response = await accountService.getUser({ config, auth }); + if (response) { + await afterLogin(auth, response.user, response.customerConsents, accessModel); + } - useAccountStore.setState({ loading: false }); + useAccountStore.setState({ loading: false }); + } catch (error: unknown) { + useAccountStore.setState({ + auth: null, + user: null, + subscription: null, + transactions: null, + activePayment: null, + customerConsents: null, + publisherConsents: null, + }); + } }); }; diff --git a/src/stores/NotificationsController.ts b/src/stores/NotificationsController.ts index a88db006d..282e850e6 100644 --- a/src/stores/NotificationsController.ts +++ b/src/stores/NotificationsController.ts @@ -1,7 +1,8 @@ -import { reloadActiveSubscription } from './AccountController'; +import { getAccount, reloadActiveSubscription } from './AccountController'; import useService from '#src/hooks/useService'; import { addQueryParams } from '#src/utils/formatting'; +import useAccount from '#src/hooks/useAccount'; export enum NotificationsTypes { ACCESS_GRANTED = 'access.granted', @@ -14,30 +15,36 @@ export enum NotificationsTypes { } export const subscribeToNotifications = async (uuid: string = '') => { - return await useService(async ({ accountService }) => { - return await accountService.subscribeToNotifications(uuid, async (message) => { - if (message) { - const notification = JSON.parse(message); - switch (notification.type) { - case NotificationsTypes.FAILED: - case NotificationsTypes.SUBSCRIBE_FAILED: - window.location.href = addQueryParams(window.location.href, { u: 'payment-error', message: notification.resource?.message }); - break; - case NotificationsTypes.ACCESS_GRANTED: - await reloadActiveSubscription(); - window.location.href = addQueryParams(window.location.href, { u: 'welcome' }); - break; - case NotificationsTypes.ACCESS_REVOKED: - await reloadActiveSubscription(); - break; - case NotificationsTypes.CARD_REQUIRES_ACTION: - case NotificationsTypes.SUBSCRIBE_REQUIRES_ACTION: - window.location.href = notification.resource?.redirect_to_url; - break; - default: - break; + return await useAccount(async ({ auth }) => { + return await useService(async ({ accountService }) => { + return await accountService.subscribeToNotifications(uuid, async (message) => { + if (message) { + const notification = JSON.parse(message); + switch (notification.type) { + case NotificationsTypes.FAILED: + case NotificationsTypes.SUBSCRIBE_FAILED: + window.location.href = addQueryParams(window.location.href, { u: 'payment-error', message: notification.resource?.message }); + break; + case NotificationsTypes.ACCOUNT_LOGOUT: + await getAccount(auth); + // redirect to login page with message + break; + case NotificationsTypes.ACCESS_GRANTED: + await reloadActiveSubscription(); + window.location.href = addQueryParams(window.location.href, { u: 'welcome' }); + break; + case NotificationsTypes.ACCESS_REVOKED: + await reloadActiveSubscription(); + break; + case NotificationsTypes.CARD_REQUIRES_ACTION: + case NotificationsTypes.SUBSCRIBE_REQUIRES_ACTION: + window.location.href = notification.resource?.redirect_to_url; + break; + default: + break; + } } - } + }); }); }); };