diff --git a/packages/ui-react/src/containers/AccountModal/AccountModal.tsx b/packages/ui-react/src/containers/AccountModal/AccountModal.tsx index 68e4ccfd4..84d093c72 100644 --- a/packages/ui-react/src/containers/AccountModal/AccountModal.tsx +++ b/packages/ui-react/src/containers/AccountModal/AccountModal.tsx @@ -1,37 +1,16 @@ -import React, { useEffect, useMemo, useRef } from 'react'; +import React, { Suspense, useEffect, useMemo, useRef } from 'react'; import { useLocation, useNavigate } from 'react-router'; import { shallow } from '@jwp/ott-common/src/utils/compare'; import { useConfigStore } from '@jwp/ott-common/src/stores/ConfigStore'; import { useAccountStore } from '@jwp/ott-common/src/stores/AccountStore'; -import { modalURLFromLocation, createURLFromLocation } from '@jwp/ott-ui-react/src/utils/location'; +import { createURLFromLocation, modalURLFromLocation } from '@jwp/ott-ui-react/src/utils/location'; import useEventCallback from '@jwp/ott-hooks-react/src/useEventCallback'; import useQueryParam from '@jwp/ott-ui-react/src/hooks/useQueryParam'; import LoadingOverlay from '../../components/LoadingOverlay/LoadingOverlay'; -import Welcome from '../../components/Welcome/Welcome'; -import PaymentFailed from '../../components/PaymentFailed/PaymentFailed'; import Dialog from '../../components/Dialog/Dialog'; -import DeleteAccountModal from '../../components/DeleteAccountModal/DeleteAccountModal'; -import FinalizePayment from '../../components/FinalizePayment/FinalizePayment'; -import WaitingForPayment from '../../components/WaitingForPayment/WaitingForPayment'; -import UpgradeSubscription from '../../components/UpgradeSubscription/UpgradeSubscription'; -import DeleteAccountPasswordWarning from '../../components/DeleteAccountPasswordWarning/DeleteAccountPasswordWarning'; -import UpdatePaymentMethod from '../UpdatePaymentMethod/UpdatePaymentMethod'; - -import EditCardDetails from './forms/EditCardDetails'; -import EditPassword from './forms/EditPassword'; -import RenewSubscription from './forms/RenewSubscription'; -import CancelSubscription from './forms/CancelSubscription'; -import ResetPassword from './forms/ResetPassword'; -import Checkout from './forms/Checkout'; -import ChooseOffer from './forms/ChooseOffer'; -import PersonalDetails from './forms/PersonalDetails'; -import Registration from './forms/Registration'; -import Login from './forms/Login'; -import styles from './AccountModal.module.scss'; -// @todo: connect with route typings -const PUBLIC_VIEWS = ['login', 'create-account', 'forgot-password', 'reset-password', 'send-confirmation', 'edit-password']; +import styles from './AccountModal.module.scss'; export type AccountModals = { login: 'login'; @@ -63,19 +42,24 @@ export type AccountModals = { 'finalize-payment': 'finalize-payment'; }; -const AccountModal = () => { +type ModalDef = { + key: string; + component: React.ReactNode; + public?: boolean; + hideBanner?: boolean; + size?: 'large' | 'small'; +}; + +const AccountModal = ({ modals }: { modals: ModalDef[] }) => { const navigate = useNavigate(); const location = useLocation(); const viewParam = useQueryParam('u'); const viewParamRef = useRef(viewParam); - const message = useQueryParam('message'); const { loading, user } = useAccountStore(({ loading, user }) => ({ loading, user }), shallow); const config = useConfigStore((s) => s.config); const { assets: { banner }, - siteName, } = config; - const isPublicView = viewParam && PUBLIC_VIEWS.includes(viewParam); const toLogin = useEventCallback(() => { navigate(modalURLFromLocation(location, 'login')); @@ -87,6 +71,11 @@ const AccountModal = () => { return viewParamRef.current; }, [viewParam]); + const currentModal = useMemo(() => modals.find(({ key }) => key === view), [view, modals]); + const isPublicView = !!currentModal?.public; + const shouldShowBanner = !!currentModal?.hideBanner; + const dialogSize = currentModal?.size || 'small'; + useEffect(() => { if (!!viewParam && !loading && !user && !isPublicView) { toLogin(); @@ -97,82 +86,30 @@ const AccountModal = () => { navigate(createURLFromLocation(location, { u: null, message: null })); }); + const fallback = ( +
+ +
+ ); + const renderForm = () => { if (!user && loading && !isPublicView) { - return ( -
- -
- ); + return fallback; } - switch (view) { - case 'login': - return ; - case 'create-account': - return ; - case 'personal-details': - return ; - case 'choose-offer': - return ; - case 'edit-card': - return ; - case 'upgrade-subscription': - return ; - case 'upgrade-subscription-error': - return ; - case 'upgrade-subscription-success': - return ; - case 'upgrade-subscription-pending': - return ; - case 'checkout': - return ; - case 'payment-error': - return ; - case 'payment-cancelled': - return ; - case 'welcome': - return ; - case 'reset-password': - return ; - case 'forgot-password': - return ; - case 'add-password': - return ; - case 'delete-account': - case 'delete-account-confirmation': - return ; - case 'warning-account-deletion': - return ; - case 'send-confirmation': - return ; - case 'edit-password': - return ; - case 'unsubscribe': - return ; - case 'renew-subscription': - return ; - case 'payment-method': - case 'payment-method-success': - return ; - case 'waiting-for-payment': - return ; - case 'finalize-payment': - return ; - } - }; + if (!currentModal) return null; - const shouldShowBanner = !['delete-account', 'delete-account-confirmation', 'edit-card', 'warning-account-deletion'].includes(view ?? ''); - const dialogSize = ['delete-account-confirmation'].includes(view ?? '') ? 'large' : 'small'; + return currentModal.component; + }; return ( - {shouldShowBanner && banner && ( + {!shouldShowBanner && banner && (
)} - {renderForm()} + {renderForm()}
); }; diff --git a/platforms/web/src/accountModals.tsx b/platforms/web/src/accountModals.tsx new file mode 100644 index 000000000..344bfaf43 --- /dev/null +++ b/platforms/web/src/accountModals.tsx @@ -0,0 +1,113 @@ +import React from 'react'; + +type ModalDef = { + key: string; + component: React.ReactNode; + public?: boolean; + hideBanner?: boolean; + size?: 'large' | 'small'; +}; + +const Login = React.lazy(() => import('@jwp/ott-ui-react/src/containers/AccountModal/forms/Login')); +const Registration = React.lazy(() => import('@jwp/ott-ui-react/src/containers/AccountModal/forms/Registration')); +const PersonalDetails = React.lazy(() => import('@jwp/ott-ui-react/src/containers/AccountModal/forms/PersonalDetails')); +const EditCard = React.lazy(() => import('@jwp/ott-ui-react/src/containers/AccountModal/forms/EditCardDetails')); +const Checkout = React.lazy(() => import('@jwp/ott-ui-react/src/containers/AccountModal/forms/Checkout')); +const Welcome = React.lazy(() => import('@jwp/ott-ui-react/src/components/Welcome/Welcome')); + +const ChooseOffer = React.lazy(() => import('@jwp/ott-ui-react/src/containers/AccountModal/forms/ChooseOffer')); +const ResetPassword = React.lazy(() => import('@jwp/ott-ui-react/src/containers/AccountModal/forms/ResetPassword')); +const EditPassword = React.lazy(() => import('@jwp/ott-ui-react/src/containers/AccountModal/forms/EditPassword')); +const UpgradeSubscription = React.lazy(() => import('@jwp/ott-ui-react/src/components/UpgradeSubscription/UpgradeSubscription')); +const PaymentFailed = React.lazy(() => import('@jwp/ott-ui-react/src/components/PaymentFailed/PaymentFailed')); +const DeleteAccountModal = React.lazy(() => import('@jwp/ott-ui-react/src/components/DeleteAccountModal/DeleteAccountModal')); +const DeleteAccountPasswordWarning = React.lazy(() => import('@jwp/ott-ui-react/src/components/DeleteAccountPasswordWarning/DeleteAccountPasswordWarning')); +const UpdatePaymentMethod = React.lazy(() => import('@jwp/ott-ui-react/src/containers/UpdatePaymentMethod/UpdatePaymentMethod')); + +const closeModal = () => { + // todo + console.warn('Close modal should be moved to component...'); +}; + +const accountModals: ModalDef[] = [ + { + key: 'login', + public: true, + component: , + }, + { + key: 'create-account', + public: true, + component: , + }, + { + key: 'personal-details', + component: , + }, + { key: 'choose-offer', component: }, + { + key: 'edit-card', + hideBanner: true, + component: , + }, + { + key: 'checkout', + component: , + }, + { key: 'welcome', component: }, + + { key: 'upgrade-subscription', component: }, + { + key: 'upgrade-subscription-error', + component: , + }, + { + key: 'upgrade-subscription-success', + component: , + }, + { + key: 'upgrade-subscription-pending', + component: , + }, + + { + key: 'payment-error', + component: , + }, + { + key: 'payment-cancelled', + component: , + }, + + { key: 'reset-password', public: true, component: }, + { key: 'forgot-password', public: true, component: }, + { key: 'edit-password', public: true, component: }, + { key: 'send-confirmation', public: true, component: }, + { key: 'add-password', component: }, + + { key: 'delete-account', hideBanner: true, component: }, + { key: 'delete-account-confirmation', hideBanner: true, size: 'large', component: }, + { key: 'warning-account-deletion', hideBanner: true, component: }, + + // { + // key: 'unsubscribe', + // component: React.lazy(() => import('@jwp/ott-ui-react/src/containers/AccountModal/forms/CancelSubscription')), + // }, + // { + // key: 'renew-subscription', + // component: React.lazy(() => import('@jwp/ott-ui-react/src/containers/AccountModal/forms/RenewSubscription')), + // }, + + { key: 'payment-method', component: }, + { key: 'payment-method-success', component: }, + // { + // key: 'waiting-for-payment', + // component: React.lazy(() => import('@jwp/ott-ui-react/src/components/WaitingForPayment/WaitingForPayment')), + // }, + // { + // key: 'finalize-payment', + // component: React.lazy(() => import('@jwp/ott-ui-react/src/components/FinalizePayment/FinalizePayment')), + // }, +]; + +export default accountModals; diff --git a/platforms/web/src/containers/Root/Root.tsx b/platforms/web/src/containers/Root/Root.tsx index 90857290f..2ce3fbf5d 100644 --- a/platforms/web/src/containers/Root/Root.tsx +++ b/platforms/web/src/containers/Root/Root.tsx @@ -14,6 +14,7 @@ import AppRoutes from '../AppRoutes/AppRoutes'; import registerCustomScreens from '#src/screenMapping'; import { useTrackConfigKeyChange } from '#src/hooks/useTrackConfigKeyChange'; +import accountModals from '#src/accountModals'; const IS_DEMO_OR_PREVIEW = IS_DEMO_MODE || IS_PREVIEW_MODE; @@ -93,7 +94,7 @@ const Root: FC = () => { return ( <> {isReady && } - {isReady && } + {isReady && } {/*This is moved to a separate, parallel component to reduce rerenders */}