diff --git a/packages/core/src/routes/sign-in-settings.ts b/packages/core/src/routes/sign-in-settings.ts index 8a63be660..3d71b7dc8 100644 --- a/packages/core/src/routes/sign-in-settings.ts +++ b/packages/core/src/routes/sign-in-settings.ts @@ -1,7 +1,12 @@ import { ConnectorMetadata } from '@logto/connector-types'; import { SignInMode } from '@logto/schemas'; -import { adminConsoleApplicationId, adminConsoleSignInMethods } from '@logto/schemas/lib/seeds'; +import { + adminConsoleApplicationId, + adminConsoleSignInMethods, + demoAppApplicationId, +} from '@logto/schemas/lib/seeds'; import etag from 'etag'; +import i18next from 'i18next'; import { Provider, errors } from 'oidc-provider'; import { getConnectorInstances } from '@/connectors'; @@ -56,6 +61,17 @@ export default function signInSettingsRoutes( return next(); } + // Insert Notification Message to DemoApp + if (interaction?.params.client_id === demoAppApplicationId) { + ctx.body = { + ...signInExperience, + socialConnectors, + notification: i18next.t('demo_app.notification'), + }; + + return next(); + } + ctx.body = { ...signInExperience, socialConnectors }; return next(); diff --git a/packages/demo-app/src/App.tsx b/packages/demo-app/src/App.tsx index d9462f2f1..51301563b 100644 --- a/packages/demo-app/src/App.tsx +++ b/packages/demo-app/src/App.tsx @@ -1,5 +1,4 @@ import { LogtoProvider, useLogto, UserInfoResponse } from '@logto/react'; -import { signInNotificationStorageKey } from '@logto/schemas'; import { demoAppApplicationId } from '@logto/schemas/lib/seeds'; import React, { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; @@ -32,7 +31,6 @@ const Main = () => { setUser(userInfo); })(); } else { - sessionStorage.setItem(signInNotificationStorageKey, t('notification')); void signIn(window.location.href); } }, [fetchUserInfo, isAuthenticated, isInCallback, signIn, t]); diff --git a/packages/schemas/src/consts/index.ts b/packages/schemas/src/consts/index.ts deleted file mode 100644 index 52ab6a430..000000000 --- a/packages/schemas/src/consts/index.ts +++ /dev/null @@ -1 +0,0 @@ -export const signInNotificationStorageKey = 'logto:client:notification'; diff --git a/packages/schemas/src/index.ts b/packages/schemas/src/index.ts index 11f1e30e3..19f0dd248 100644 --- a/packages/schemas/src/index.ts +++ b/packages/schemas/src/index.ts @@ -1,4 +1,3 @@ -export * from './consts'; export * from './foundations'; export * from './db-entries'; export * from './types'; diff --git a/packages/ui/src/containers/AppNotification/index.test.tsx b/packages/ui/src/containers/AppNotification/index.test.tsx index 1185b5c69..656cc7e7b 100644 --- a/packages/ui/src/containers/AppNotification/index.test.tsx +++ b/packages/ui/src/containers/AppNotification/index.test.tsx @@ -1,23 +1,31 @@ -import { signInNotificationStorageKey } from '@logto/schemas'; -import { render, fireEvent } from '@testing-library/react'; +import { fireEvent } from '@testing-library/react'; import React from 'react'; -import AppNotification from '.'; +import renderWithPageContext from '@/__mocks__/RenderWithPageContext'; +import SettingsProvider from '@/__mocks__/RenderWithPageContext/SettingsProvider'; +import { mockSignInExperienceSettings } from '@/__mocks__/logto'; -describe('AppNotification', () => { - it('render properly', () => { - const message = 'This is a notification message'; - sessionStorage.setItem(signInNotificationStorageKey, message); - const { queryByText, getByText } = render(); +import Notification from './index'; - expect(queryByText(message)).not.toBeNull(); +describe('Notification', () => { + it('render Notification', () => { + const notification = 'text notification'; - const closeLink = getByText('action.got_it'); + const { queryByText, getByText } = renderWithPageContext( + + + + ); - expect(closeLink).not.toBeNull(); + expect(queryByText(notification)).not.toBeNull(); - fireEvent.click(closeLink); - - expect(queryByText(message)).toBeNull(); + const closeButton = getByText('action.got_it'); + fireEvent.click(closeButton); + expect(queryByText(notification)).toBeNull(); }); }); diff --git a/packages/ui/src/containers/AppNotification/index.tsx b/packages/ui/src/containers/AppNotification/index.tsx index 8cb3e1a73..c691af7f9 100644 --- a/packages/ui/src/containers/AppNotification/index.tsx +++ b/packages/ui/src/containers/AppNotification/index.tsx @@ -1,23 +1,27 @@ -import { Nullable } from '@silverhand/essentials'; -import React, { useState, useEffect, useCallback } from 'react'; +import React, { useCallback, useContext } from 'react'; import Notification from '@/components/Notification'; -import { getAppNotificationInfo, clearAppNotificationInfo } from '@/utils/session-storage'; +import { PageContext } from '@/hooks/use-page-context'; import * as styles from './index.module.scss'; const AppNotification = () => { - const [notification, setNotification] = useState>(null); + const { experienceSettings, setExperienceSettings } = useContext(PageContext); + const notification = experienceSettings?.notification; const onClose = useCallback(() => { - setNotification(null); - clearAppNotificationInfo(); - }, []); + // Clear notification + setExperienceSettings((settings) => { + if (!settings) { + return; + } - useEffect(() => { - const notification = getAppNotificationInfo(); - setNotification(notification); - }, []); + return { + ...settings, + notification: undefined, + }; + }); + }, [setExperienceSettings]); if (!notification) { return null; diff --git a/packages/ui/src/hooks/use-page-context.ts b/packages/ui/src/hooks/use-page-context.ts index b6e6708de..3656a0c1d 100644 --- a/packages/ui/src/hooks/use-page-context.ts +++ b/packages/ui/src/hooks/use-page-context.ts @@ -10,12 +10,12 @@ export type Context = { platform: Platform; termsAgreement: boolean; experienceSettings: SignInExperienceSettings | undefined; - setTheme: (theme: Theme) => void; - setToast: (message: string) => void; - setLoading: (loading: boolean) => void; - setPlatform: (platform: Platform) => void; - setTermsAgreement: (termsAgreement: boolean) => void; - setExperienceSettings: (settings: SignInExperienceSettings) => void; + setTheme: React.Dispatch>; + setToast: React.Dispatch>; + setLoading: React.Dispatch>; + setPlatform: React.Dispatch>; + setTermsAgreement: React.Dispatch>; + setExperienceSettings: React.Dispatch>; }; const noop = () => { diff --git a/packages/ui/src/types/index.ts b/packages/ui/src/types/index.ts index 11398edb8..2b04a2137 100644 --- a/packages/ui/src/types/index.ts +++ b/packages/ui/src/types/index.ts @@ -1,12 +1,4 @@ -import { - Branding, - LanguageInfo, - TermsOfUse, - SignInExperience, - ConnectorMetadata, - SignInMode, - Color, -} from '@logto/schemas'; +import { SignInExperience, ConnectorMetadata } from '@logto/schemas'; export type UserFlow = 'sign-in' | 'register'; export type SignInMethod = 'username' | 'email' | 'sms' | 'social'; @@ -28,15 +20,13 @@ export interface ConnectorData extends ConnectorMetadata { export type SignInExperienceSettingsResponse = SignInExperience & { socialConnectors: ConnectorData[]; + notification?: string; }; -export type SignInExperienceSettings = { - color: Color; - branding: Branding; - languageInfo: LanguageInfo; - termsOfUse: TermsOfUse; +export type SignInExperienceSettings = Omit< + SignInExperienceSettingsResponse, + 'id' | 'signInMethods' | 'socialSignInConnectorTargets' +> & { primarySignInMethod: SignInMethod; secondarySignInMethods: SignInMethod[]; - socialConnectors: ConnectorData[]; - signInMode: SignInMode; }; diff --git a/packages/ui/src/utils/session-storage.ts b/packages/ui/src/utils/session-storage.ts deleted file mode 100644 index 7113d326d..000000000 --- a/packages/ui/src/utils/session-storage.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { signInNotificationStorageKey } from '@logto/schemas'; - -export const getAppNotificationInfo = () => { - return sessionStorage.getItem(signInNotificationStorageKey); -}; - -export const clearAppNotificationInfo = () => { - sessionStorage.removeItem(signInNotificationStorageKey); -};