diff --git a/README.md b/README.md index a9303824d5..132aa1ff78 100644 --- a/README.md +++ b/README.md @@ -46,8 +46,7 @@ const App = () => { | `onShowConnectSuccessSurvey` | [`AnalyticContextType`](./typings/connectProps.d.ts#L100) | The connect widget provides a way to let your analytics provider know that the connect success survey was shown. [More details](./docs/ANALYTICS.md#onShowConnectSuccessSurvey) | | `onSubmitConnectSuccessSurvey` | [`AnalyticContextType`](./typings/connectProps.d.ts#L101) | The connect widget provides a way to submit connect success survey responses using your own analytics provider. [More details](./docs/ANALYTICS.md#onSubmitConnectSuccessSurvey) | | | `profiles` | [`ProfilesTypes`](./typings/connectProps.d.ts) | The connect widget uses the profiles to set the initial state of the widget. [More details](./docs/PROFILES.md) | See more details | -| `userFeatures` | [`UserFeaturesType`](./typings/connectProps.d.ts) | The connect widget uses user features to determine the behavior of the widget. [More details](./docs/USER_FEATURES.md) | See more details | -| `showTooSmallDialog` | `boolean` | The connect widget can show a warning when the widget size is below the supported 320px. | `true` | +| `userFeatures` | [`UserFeaturesType`](./typings/connectProps.d.ts) | The connect widget uses user features to determine the behavior of the widget. [More details](./docs/USER_FEATURES.md) | See more details | `webSocketConnection` | `object` | An object containing `isConnected()` function and `webSocketMessages$` observable for real-time updates. | `null` | | `experimentalFeatures` | `object` | An object to enable or disable experimental features like `useWebSockets: true`. | `null` | diff --git a/src/ConnectWidget.tsx b/src/ConnectWidget.tsx index 13a6b193cd..b1b37dace1 100644 --- a/src/ConnectWidget.tsx +++ b/src/ConnectWidget.tsx @@ -7,7 +7,6 @@ import Connect from 'src/Connect' import { WidgetDimensionObserver } from 'src/components/app/WidgetDimensionObserver' import { initGettextLocaleData } from 'src/utilities/Personalization' import { ConnectedTokenProvider } from 'src/ConnectedTokenProvider' -import { TooSmallDialog } from 'src/components/app/TooSmallDialog' import { setLocalizedContent } from 'src/redux/reducers/localizedContentSlice' import { WebSocketProvider } from 'src/context/WebSocketContext' import './sharedVariables.css' @@ -23,7 +22,6 @@ export const ConnectWidgetWithoutReduxProvider = ({ onPostMessage = () => {}, onAnalyticPageview = () => {}, postMessageEventOverrides, - showTooSmallDialog = true, webSocketConnection, ...props }: any) => { @@ -40,7 +38,6 @@ export const ConnectWidgetWithoutReduxProvider = ({ - {showTooSmallDialog && } diff --git a/src/components/ConfigError.tsx b/src/components/ConfigError.tsx index ad1b52c958..5b4d4cbbb7 100644 --- a/src/components/ConfigError.tsx +++ b/src/components/ConfigError.tsx @@ -1,8 +1,7 @@ import React from 'react' -import { Text } from '@mxenabled/mxui' +import { Icon, Text } from '@mxenabled/mxui' import { useTokens } from '@kyper/tokenprovider' import { Container } from 'src/components/Container' -import { AttentionFilled } from '@kyper/icon/AttentionFilled' interface ConfigError { title: string @@ -20,7 +19,12 @@ export const ConfigError: React.FC = ({ error }) => { return (
- + {error.title} @@ -45,7 +49,4 @@ const getStyles = (tokens: any) => ({ errorTitle: { marginBottom: tokens.Spacing.Tiny, }, - errorIcon: { - marginBottom: tokens.Spacing.Large, - }, }) diff --git a/src/components/ConnectSuccessSurvey.tsx b/src/components/ConnectSuccessSurvey.tsx index 54e1b92b2f..d780d9b597 100644 --- a/src/components/ConnectSuccessSurvey.tsx +++ b/src/components/ConnectSuccessSurvey.tsx @@ -1,9 +1,8 @@ import React, { useState, useImperativeHandle, useContext } from 'react' -import { Text } from '@mxenabled/mxui' +import { Icon, Text } from '@mxenabled/mxui' import { Button, TextField } from '@mui/material' import ToggleButton from '@mui/material/ToggleButton' import ToggleButtonGroup from '@mui/material/ToggleButtonGroup' -import { AttentionFilled } from '@kyper/icon/AttentionFilled' import { useTokens } from '@kyper/tokenprovider' import { __ } from 'src/utilities/Intl' @@ -170,7 +169,12 @@ export const ConnectSuccessSurvey = React.forwardRef< )} {showErrorMessage && (
- + {__('Please select an option before continuing.')} @@ -255,9 +259,6 @@ const getStyles = (tokens: any) => ({ alignItems: 'center', width: '100%', }, - errorIcon: { - marginRight: tokens.Spacing.Tiny, - }, textQuestion: { display: 'flex', flexDirection: 'column', diff --git a/src/components/DeleteMemberSurvey.js b/src/components/DeleteMemberSurvey.js index 6b76b5587f..3229202e11 100644 --- a/src/components/DeleteMemberSurvey.js +++ b/src/components/DeleteMemberSurvey.js @@ -1,9 +1,8 @@ import React, { useState, useEffect, useRef } from 'react' import PropTypes from 'prop-types' -import { Text } from '@mxenabled/mxui' +import { Icon, Text } from '@mxenabled/mxui' import { useTokens } from '@kyper/tokenprovider' import { MessageBox } from '@kyper/messagebox' -import { AttentionFilled } from '@kyper/icon/AttentionFilled' import { defer } from 'rxjs' import FocusTrap from 'focus-trap-react' import { Button, FormLabel, FormControl } from '@mui/material' @@ -171,7 +170,7 @@ export const DeleteMemberSurvey = (props) => { {isSubmitted && !selectedReason && (
- +

{__('Choose a reason for deleting')}

)} diff --git a/src/components/GenericError.js b/src/components/GenericError.js index 8be005b22a..a25044e3c3 100644 --- a/src/components/GenericError.js +++ b/src/components/GenericError.js @@ -1,8 +1,7 @@ import React, { useEffect } from 'react' import PropTypes from 'prop-types' -import { AttentionFilled } from '@kyper/icon/AttentionFilled' import { useTokens } from '@kyper/tokenprovider' -import { Text } from '@mxenabled/mxui' +import { Icon, Text } from '@mxenabled/mxui' import { isRunningE2ETests } from 'src/utilities/e2e' import { PageviewInfo } from 'src/const/Analytics' @@ -27,11 +26,11 @@ export const GenericError = ({ loadError, onAnalyticPageview, subtitle, title }) return (
- {title} @@ -57,9 +56,6 @@ function getStyles(tokens) { padding: tokens.Spacing.XSMALL, textAlign: 'center', }, - icon: { - marginBottom: tokens.Spacing.XLarge, - }, } } diff --git a/src/components/LeavingNoticeFlat.js b/src/components/LeavingNoticeFlat.js index 409091ca20..1489a21a7d 100644 --- a/src/components/LeavingNoticeFlat.js +++ b/src/components/LeavingNoticeFlat.js @@ -4,8 +4,7 @@ import PropTypes from 'prop-types' import { __ } from 'src/utilities/Intl' -import { Text } from '@mxenabled/mxui' -import { AttentionFilled } from '@kyper/icon/AttentionFilled' +import { Text, Icon } from '@mxenabled/mxui' import { Button } from '@mui/material' import { useTokens } from '@kyper/tokenprovider' @@ -36,7 +35,7 @@ export const LeavingNoticeFlat = ({ onContinue, onCancel, portalTo = 'connect-wr > {__('You are leaving')} - +
{ )} {connectionStatus === ReadableStatuses.REJECTED && ( - + )}
) diff --git a/src/components/app/TooSmallDialog.tsx b/src/components/app/TooSmallDialog.tsx deleted file mode 100644 index 3fa38eb8ad..0000000000 --- a/src/components/app/TooSmallDialog.tsx +++ /dev/null @@ -1,175 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import React, { useEffect, useReducer, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { Action } from 'redux' -import { getUnixTime } from 'date-fns' -import { defer } from 'rxjs' - -import { AttentionFilled } from '@kyper/icon/AttentionFilled' -import { Text } from '@mxenabled/mxui' -import { useTokens } from '@kyper/tokenprovider' -import { Button } from '@mui/material' - -import { getTrueWidth } from 'src/redux/selectors/Browser' -import { updateUserProfile } from 'src/redux/reducers/profilesSlice' - -import { __ } from 'src/utilities/Intl' -import { shouldShowTooSmallDialogFromSnooze } from 'src/utilities/Browser' -import { getEnvironment, Environments } from 'src/utilities/global' -import { PageviewInfo } from 'src/const/Analytics' -import { APP_MIN_WIDTH } from 'src/const/app' -import { useApi } from 'src/context/ApiContext' - -interface TooSmallDialogProps { - onAnalyticPageview: (_path: string, _metadata: object) => void -} - -export const TooSmallDialog = (props: TooSmallDialogProps) => { - const [state, dispatch] = useReducer(reducer, { - showDialog: false, - tooSmallDialogDismissedThisSession: false, - isDismissing: false, - }) - const reduxDispatch = useDispatch() - const trueWidth = useSelector(getTrueWidth) - const userProfile = useSelector((state: any) => state.profiles.userProfile) - const widgetProfile = useSelector((state: any) => state.profiles.widgetProfile) - const [pageviewSent, setPagviewSent] = useState(false) - const tokens = useTokens() - const styles = getStyles(tokens) - const { api } = useApi() - - useEffect(() => { - const shouldShowtooSmallConsiderSnooze = shouldShowTooSmallDialogFromSnooze( - userProfile?.too_small_modal_dismissed_at || null, - widgetProfile?.too_small_modal_threshold_days, - ) - const isProdEnvironment = (getEnvironment() as unknown) === Environments.PRODUCTION - const shouldShowTooSmallDialog = - shouldShowtooSmallConsiderSnooze && trueWidth < APP_MIN_WIDTH && !isProdEnvironment - - if (shouldShowTooSmallDialog) { - // user decreased size - if (!pageviewSent) { - props.onAnalyticPageview('/connect' + PageviewInfo.CONNECT_UNSUPPORTED_RESOLUTION[1], {}) - setPagviewSent(true) - } - dispatch({ type: 'showDialog' }) - } else { - // user increased size - dispatch({ type: 'hideDialog' }) - } - }, [trueWidth]) - - // eslint-disable-next-line consistent-return - useEffect(() => { - if (state.isDismissing) { - const dismissModal$ = defer(() => - api.updateUserProfile({ - ...userProfile, - too_small_modal_dismissed_at: getUnixTime(new Date()), - }), - ).subscribe( - (data) => { - reduxDispatch(updateUserProfile(data)) - dispatch({ type: 'dismissDialogSuccess' }) - }, - () => { - // If error, we still dismiss the modal for this session. - //User will see modal next session and can try again to dismiss. - dispatch({ type: 'dismissDialogSuccess' }) - }, - ) - - return () => dismissModal$.unsubscribe() - } - }, [state.isDismissing]) - - return state.showDialog ? ( -
- - - {__('Unsupported Resolution')} - - - {__( - 'Your screen zoom setting may not be compatible with the current screen size. The minimum supported width is 320 pixels. Please reduce your screen zoom setting to view all the content.', - )} - - -
- ) : null -} - -const getStyles = (tokens: any) => { - return { - container: { - background: tokens.BackgroundColor.Modal, - display: 'flex', - flexDirection: 'column', - alignItems: 'center', - padding: `0 ${tokens.Spacing.ContainerSidePadding}px`, - position: 'fixed', - top: 0, - left: 0, - right: 0, - bottom: 0, - textAlign: 'center', - maxWidth: '352px', // Our max content width (does not include side margin) - minWidth: '270px', // Our min content width (does not include side margin) - zIndex: tokens.ZIndex.MessageBox, - } as React.CSSProperties, - title: { - marginBottom: tokens.Spacing.Tiny, - }, - dismissButton: { - marginTop: tokens.Spacing.XLarge, - marginBottom: tokens.Spacing.Medium, - }, - icon: { - marginBottom: tokens.Spacing.Large, - marginTop: tokens.Spacing.Jumbo, - paddingTop: tokens.Spacing.Tiny, - }, - } -} - -const reducer = (state: any, action: Action) => { - switch (action.type) { - case 'showDialog': - return { - ...state, - showDialog: true, - } - - case 'hideDialog': - return { - ...state, - showDialog: false, - } - - case 'dismissDialog': - return { - ...state, - isDismissing: true, - } - - case 'dismissDialogSuccess': - return { - ...state, - isDismissing: false, - showDialog: false, - tooSmallModalDismissedThisSession: true, - } - - default: - return state - } -} diff --git a/src/components/app/__tests__/TooSmallDialog-test.tsx b/src/components/app/__tests__/TooSmallDialog-test.tsx deleted file mode 100644 index 471550f694..0000000000 --- a/src/components/app/__tests__/TooSmallDialog-test.tsx +++ /dev/null @@ -1,56 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import React from 'react' - -import { render, screen } from 'src/utilities/testingLibrary' -import { waitFor } from '@testing-library/react' - -import * as globalUtilities from 'src/utilities/global' -import * as browserUtils from 'src/utilities/Browser' -import { TooSmallDialog } from 'src/components/app/TooSmallDialog' - -describe('TooSmallDialog', () => { - it('should not show the dialog if trueWidth is greater than 320px', async () => { - vi.spyOn(browserUtils, 'getTrueWindowWidth').mockReturnValueOnce(322) - const onAnalyticPageview = vi.fn() - render() - expect(screen.queryByText('Unsupported Resolution')).not.toBeInTheDocument() - expect(onAnalyticPageview).not.toHaveBeenCalled() - }) - describe('Less than 320px trueWidth', () => { - beforeEach(() => { - vi.spyOn(browserUtils, 'getTrueWindowWidth').mockReturnValueOnce(300) - }) - it('should show the dialog if the environemt is other than production', async () => { - vi.spyOn(globalUtilities, 'getEnvironment').mockReturnValueOnce( - globalUtilities.Environments.INTEGRATION, - ) - render( {}} />) - expect(screen.queryByText('Unsupported Resolution')).toBeInTheDocument() - }) - it('should not show the dialog if the environemt is production', async () => { - vi.spyOn(globalUtilities, 'getEnvironment').mockReturnValue( - globalUtilities.Environments.PRODUCTION, - ) - render( {}} />) - expect(screen.queryByText('Unsupported Resolution')).not.toBeInTheDocument() - }) - it('should dismiss the dialog if the dismiss button is clicked', async () => { - vi.spyOn(globalUtilities, 'getEnvironment').mockReturnValue( - globalUtilities.Environments.INTEGRATION, - ) - const { user } = render( {}} />) - await user.click(screen.getByText('Dismiss')) - await waitFor(() => { - expect(screen.queryByText('Unsupported Resolution')).not.toBeInTheDocument() - }) - }) - it('should call onAnalyticPageview if the environemt is other than production', async () => { - vi.spyOn(globalUtilities, 'getEnvironment').mockReturnValueOnce( - globalUtilities.Environments.INTEGRATION, - ) - const onAnalyticPageview = vi.fn() - render() - await waitFor(() => expect(onAnalyticPageview).toHaveBeenCalled()) - }) - }) -}) diff --git a/src/utilities/Browser.js b/src/utilities/Browser.js index 71b0324a85..181be36455 100644 --- a/src/utilities/Browser.js +++ b/src/utilities/Browser.js @@ -1,8 +1,5 @@ import Bowser from 'bowser' import { light as tokens } from '@mxenabled/design-tokens' -import differenceInDays from 'date-fns/differenceInDays' -import fromUnixTime from 'date-fns/fromUnixTime' -import startOfDay from 'date-fns/startOfDay' import { Style } from 'src/const/Style' @@ -119,17 +116,3 @@ const getScrollBarWidth = () => { // Removes the px from the breakpoint (Ex. 576px -> 576) export const breakpointNumberOnly = (breakpoint) => breakpoint.split('').splice(0, 3).join('') - -export const shouldShowTooSmallDialogFromSnooze = (dismissedAt, thresholdDays, now = null) => { - if (!dismissedAt || !thresholdDays) { - return true - } - - const currentDate = now || new Date(Date.now()) - const dismissalDate = - typeof dismissedAt === 'string' ? new Date(dismissedAt) : fromUnixTime(dismissedAt) - - const daysSinceDismissal = differenceInDays(currentDate, startOfDay(dismissalDate)) - - return daysSinceDismissal > thresholdDays -} diff --git a/src/utilities/__tests__/Browser-test.js b/src/utilities/__tests__/Browser-test.js index 765a66ce7a..cff27b30c1 100644 --- a/src/utilities/__tests__/Browser-test.js +++ b/src/utilities/__tests__/Browser-test.js @@ -1,5 +1,5 @@ import { light as tokens } from '@mxenabled/design-tokens' -import { getWindowSize, shouldShowTooSmallDialogFromSnooze } from 'src/utilities/Browser' +import { getWindowSize } from 'src/utilities/Browser' describe('Browser', () => { it('returns "small" when window width is less than Med breakpoint', () => { @@ -25,25 +25,4 @@ describe('Browser', () => { expect(windowSize).toEqual('large') }) - - describe('shouldShowTooSmallModalFromSnooze', () => { - const nowDate = new Date(1680195964443) - const yesterdayDate = new Date(1680109564000) - const thirtyDaysAgoDate = new Date(1677607564000) - const threeDaysAgo = new Date(1679936764000) - - it('defaults true when no "dismissed at" or "threshold days" given', () => { - expect(shouldShowTooSmallDialogFromSnooze(null, 10)).toBe(true) - expect(shouldShowTooSmallDialogFromSnooze(threeDaysAgo, null)).toBe(true) - expect(shouldShowTooSmallDialogFromSnooze(threeDaysAgo, 0)).toBe(true) - }) - - it('should show modal if days since dismissal exceeds client set threshold', () => { - expect(shouldShowTooSmallDialogFromSnooze(thirtyDaysAgoDate, 15, nowDate)).toBe(false) - }) - - it('should not show modal if days since dismissal is below client set threshold', () => { - expect(shouldShowTooSmallDialogFromSnooze(yesterdayDate, 15, nowDate)).toBe(false) - }) - }) }) diff --git a/src/views/credentials/CreateMemberForm-test.tsx b/src/views/credentials/CreateMemberForm-test.tsx index c3cb85247a..074980464b 100644 --- a/src/views/credentials/CreateMemberForm-test.tsx +++ b/src/views/credentials/CreateMemberForm-test.tsx @@ -159,7 +159,6 @@ describe('', () => { ...masterData, clientProfile: { ...masterData.clientProfile, uses_oauth: false }, }} - showTooSmallDialog={false} userFeatures={{}} />, { apiValue: baseApiValue, store: createTestReduxStore() }, diff --git a/src/views/credentials/UpdateMemberForm-test.tsx b/src/views/credentials/UpdateMemberForm-test.tsx index 959e63bd79..fd399e328a 100644 --- a/src/views/credentials/UpdateMemberForm-test.tsx +++ b/src/views/credentials/UpdateMemberForm-test.tsx @@ -157,7 +157,6 @@ describe('', () => { ...masterData, clientProfile: { ...masterData.clientProfile, uses_oauth: false }, }} - showTooSmallDialog={false} userFeatures={{}} />, { apiValue: baseApiValue, store: createTestReduxStore() }, diff --git a/src/views/mfa/MFAImages.js b/src/views/mfa/MFAImages.js index 64534aab3d..ca586eb44a 100644 --- a/src/views/mfa/MFAImages.js +++ b/src/views/mfa/MFAImages.js @@ -12,9 +12,8 @@ import useAnalyticsEvent from 'src/hooks/useAnalyticsEvent' import { PageviewInfo, AnalyticEvents } from 'src/const/Analytics' import { CheckmarkFilled } from '@kyper/icon/CheckmarkFilled' -import { AttentionFilled } from '@kyper/icon/AttentionFilled' import { useTokens } from '@kyper/tokenprovider' -import { Text } from '@mxenabled/mxui' +import { Icon, Text } from '@mxenabled/mxui' import { Button } from '@mui/material' export const MFAImages = (props) => { @@ -106,7 +105,7 @@ export const MFAImages = (props) => {
{isSubmitted && _isEmpty(selectedOption) && (
- +

{__('Choose an image')}

)} diff --git a/src/views/mfa/MFAOptions.js b/src/views/mfa/MFAOptions.js index 8594d36e5a..3b3d24378b 100644 --- a/src/views/mfa/MFAOptions.js +++ b/src/views/mfa/MFAOptions.js @@ -4,8 +4,7 @@ import PropTypes from 'prop-types' import { sha256 } from 'js-sha256' import { useTokens } from '@kyper/tokenprovider' -import { Text } from '@mxenabled/mxui' -import { AttentionFilled } from '@kyper/icon/AttentionFilled' +import { Icon, Text } from '@mxenabled/mxui' import { SelectionBox } from 'src/privacy/input' import { Button, FormLabel } from '@mui/material' @@ -120,7 +119,7 @@ export const MFAOptions = (props) => { {isSubmitted && _isEmpty(selectedOption) && (
- +

{isSAS ? __('Account selection is required.') : __('Choose an option')}

diff --git a/src/views/search/views/SearchFailed.js b/src/views/search/views/SearchFailed.js index a161fc25a5..3faf7c0aae 100644 --- a/src/views/search/views/SearchFailed.js +++ b/src/views/search/views/SearchFailed.js @@ -1,7 +1,7 @@ import React from 'react' +import { Icon } from '@mxenabled/mxui' import { useTokens } from '@kyper/tokenprovider' -import { AttentionFilled } from '@kyper/icon/AttentionFilled' import { __ } from 'src/utilities/Intl' import useAnalyticsPath from 'src/hooks/useAnalyticsPath' @@ -15,7 +15,7 @@ export const SearchFailed = () => { return (
- +
{__('Search isn’t working')}
diff --git a/typings/connectProps.d.ts b/typings/connectProps.d.ts index 7d1f1f7387..b90a5ff70c 100644 --- a/typings/connectProps.d.ts +++ b/typings/connectProps.d.ts @@ -3,7 +3,6 @@ interface ConnectWidgetPropTypes extends ConnectProps { language?: LanguageType onPostMessage: (event: string, data?: object) => void - showTooSmallDialog: boolean webSocketConnection?: any } diff --git a/typings/kyper.d.ts b/typings/kyper.d.ts index 7c42923d70..e9b6e8122a 100644 --- a/typings/kyper.d.ts +++ b/typings/kyper.d.ts @@ -16,7 +16,6 @@ declare module '@kyper/icon/Notarized' declare module '@kyper/icon/Image' declare module '@kyper/icon/Health' declare module '@kyper/icon/Grid' -declare module '@kyper/icon/AttentionFilled' declare module '@kyper/progressindicators' declare module '@kyper/icon/ChevronLeft' declare module '@kyper/icon/Lock'