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..86b8cc091c 100644 --- a/src/ConnectWidget.tsx +++ b/src/ConnectWidget.tsx @@ -7,10 +7,11 @@ 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' +import 'src/styles/spacing.css' +import 'src/styles/styles.css' interface PostMessageContextType { postMessageEventOverrides?: PostMessageEventOverrides @@ -23,7 +24,6 @@ export const ConnectWidgetWithoutReduxProvider = ({ onPostMessage = () => {}, onAnalyticPageview = () => {}, postMessageEventOverrides, - showTooSmallDialog = true, webSocketConnection, ...props }: any) => { @@ -40,7 +40,6 @@ export const ConnectWidgetWithoutReduxProvider = ({ - {showTooSmallDialog && } diff --git a/src/ConnectedTokenProvider.tsx b/src/ConnectedTokenProvider.tsx index 2edc9a9fea..483b4c9105 100644 --- a/src/ConnectedTokenProvider.tsx +++ b/src/ConnectedTokenProvider.tsx @@ -2,7 +2,7 @@ import React from 'react' import { RootState } from 'src/redux/Store' import { useSelector } from 'react-redux' -import { Theme, ThemeProvider } from '@mui/material' +import { GlobalStyles, Theme, ThemeProvider } from '@mui/material' import { deepmerge } from '@mui/utils' import { createMXTheme, Icon, IconWeight } from '@mxenabled/mxui' import { TokenProvider, THEMES } from '@kyper/tokenprovider' @@ -99,8 +99,15 @@ const connectThemeOverrides = (palette: Theme['palette']) => ({ styleOverrides: { root: { '&.MuiFormControlLabel-labelPlacementStart': { + // TODO: Remove the custom margins once we are on MXUI v2. + marginBottom: '16px', marginLeft: 0, marginRight: 0, + // mxui's theme uses `spacing: 1`, so SelectionBox's internal `ml: 16` means 16px. + // Our 8px scale turns it into 128px, pushing the control out of the box. + '& .MuiRadio-root, & .MuiCheckbox-root': { + marginLeft: '16px', + }, }, }, }, @@ -127,6 +134,8 @@ const connectThemeOverrides = (palette: Theme['palette']) => ({ }, }, }, + // TODO: Remove this custom spacing scale once we are on MXUI v2. + spacing: (factor: number) => `${factor * 8}px`, }) interface Props { @@ -174,7 +183,26 @@ export const ConnectedTokenProvider = ({ children }: Props): React.ReactNode => theme={isDarkModeEnabled ? THEMES.DARK : colorScheme} tokenOverrides={kyperTokenOverrides} > - {children} + + {/* This block can be deleted once we are on MXUI v2. */} + + {children} + ) } diff --git a/src/components/ConfigError.module.css b/src/components/ConfigError.module.css new file mode 100644 index 0000000000..b6eb25fa5f --- /dev/null +++ b/src/components/ConfigError.module.css @@ -0,0 +1,4 @@ +.container:global(.MuiStack-root) { + margin-top: var(--spacing-4-point-5); + text-align: center; +} diff --git a/src/components/ConfigError.tsx b/src/components/ConfigError.tsx index ad1b52c958..da1ea76ed3 100644 --- a/src/components/ConfigError.tsx +++ b/src/components/ConfigError.tsx @@ -1,8 +1,8 @@ import React from 'react' -import { Text } from '@mxenabled/mxui' -import { useTokens } from '@kyper/tokenprovider' +import { Stack } from '@mui/material' +import { Icon, Text } from '@mxenabled/mxui' import { Container } from 'src/components/Container' -import { AttentionFilled } from '@kyper/icon/AttentionFilled' +import styles from 'src/components/ConfigError.module.css' interface ConfigError { title: string @@ -15,37 +15,19 @@ interface ConfigErrorProps { } export const ConfigError: React.FC = ({ error }) => { - const tokens = useTokens() - const styles = getStyles(tokens) return ( -
- - - {error.title} - - - {error.message} - -
+ + + + + {error.title} + + + {error.message} + + +
) } - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const getStyles = (tokens: any) => ({ - container: { - display: 'flex', - flexDirection: 'column', - alignItems: 'center', - justifyCcontent: 'center', - marginTop: '36px', - textAlign: 'center', - } as React.CSSProperties, - errorTitle: { - marginBottom: tokens.Spacing.Tiny, - }, - errorIcon: { - marginBottom: tokens.Spacing.Large, - }, -}) diff --git a/src/components/ConnectSuccessSurvey.module.css b/src/components/ConnectSuccessSurvey.module.css new file mode 100644 index 0000000000..5d14c77dfb --- /dev/null +++ b/src/components/ConnectSuccessSurvey.module.css @@ -0,0 +1,36 @@ +.toggleButtonGroup:global(.MuiToggleButtonGroup-root) { + align-items: center; + border-radius: 4px; + display: flex; + justify-content: center; + width: 100%; +} + +.boundLabels:global(.MuiStack-root) { + width: 100%; +} + +.textQuestion:global(.MuiStack-root) { + width: 100%; +} + +.errorMessage:global(.MuiStack-root) { + width: 100%; +} + +.toggleButton:global(.MuiToggleButton-root) { + align-items: center; + color: var(--mui-palette-primary-main); + display: flex; + flex: 1 0 0; + font-weight: 600; + height: 48px; + justify-content: center; + padding: var(--spacing-1-point-5); +} + +.toggleButton:global(.MuiToggleButton-root.Mui-selected) { + background-color: var(--mui-palette-primary-main); + box-shadow: none; + color: var(--mui-palette-primary-contrastText); +} diff --git a/src/components/ConnectSuccessSurvey.tsx b/src/components/ConnectSuccessSurvey.tsx index 54e1b92b2f..cd9d8a79de 100644 --- a/src/components/ConnectSuccessSurvey.tsx +++ b/src/components/ConnectSuccessSurvey.tsx @@ -1,14 +1,13 @@ import React, { useState, useImperativeHandle, useContext } from 'react' -import { Text } from '@mxenabled/mxui' -import { Button, TextField } from '@mui/material' +import { Icon, Text } from '@mxenabled/mxui' +import { Button, Stack, 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' import { ThankYouMessage } from 'src/components/ThankYouMessage' import { AnalyticContext } from 'src/Connect' +import styles from 'src/components/ConnectSuccessSurvey.module.css' interface ConnectSuccessSurveyProps { handleBack: () => void @@ -61,9 +60,6 @@ export const ConnectSuccessSurvey = React.forwardRef< const [showErrorMessage, setShowErrorMessage] = useState(false) const { onSubmitConnectSuccessSurvey } = useContext(AnalyticContext) - const tokens = useTokens() - const styles = getStyles(tokens) - useImperativeHandle(connectSuccessSurveyRef, () => { return { handleConnectSuccessSurveyBackButton() { @@ -102,171 +98,94 @@ export const ConnectSuccessSurvey = React.forwardRef< } const currentQuestion = SURVEY_QUESTIONS[currentQuestionIndex] + const isLastQuestion = currentQuestionIndex === SURVEY_QUESTIONS.length - 1 return (
{showThankYouMessage ? ( ) : ( - -
- - {currentQuestion.question()} - - {currentQuestion.type === 'number' ? ( - - - handleToggleButtonChange(currentQuestionIndex, newSelected) - } - style={styles.toggleButtonGroup} - value={answers[currentQuestionIndex]} - > - {Object.keys(SURVEY_RATING).map((key) => { - return ( - - {key} - - ) - })} - -
- - {__('Strongly disagree')} - - - {__('Strongly agree')} - -
-
- ) : ( -
- - {__('Please let us know how we can improve.')} - - handleTextFieldChange(currentQuestionIndex, e.target.value)} - rows={4} - value={answers[currentQuestionIndex]} - /> -
- )} - {showErrorMessage && ( -
- - - {__('Please select an option before continuing.')} - -
- )} - {currentQuestionIndex === SURVEY_QUESTIONS.length - 1 ? ( - - ) : ( - - )} -
-
+ + {__('Strongly disagree')} + + + {__('Strongly agree')} + + + + ) : ( + + + {__('Please let us know how we can improve.')} + + handleTextFieldChange(currentQuestionIndex, e.target.value)} + rows={4} + value={answers[currentQuestionIndex]} + /> + + )} + {showErrorMessage && ( + + + + {__('Please select an option before continuing.')} + + + )} + + + )}
) }) -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const getStyles = (tokens: any) => ({ - checkMarkIcon: { - display: 'flex', - justifyContent: 'center', - marginBottom: tokens.Spacing.XLarge, - }, - toggleButtonGroup: { - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - width: '100%', - borderRadius: '4px', - marginTop: tokens.Spacing.XLarge, - marginBottom: '10px', - }, - toggleButton: { - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - flex: '1 0 0', - height: '48px', - padding: '12px', - border: '1px solid #8994A2', - fontWeight: tokens.FontWeight.Semibold, - }, - surveyQuestion: { - display: 'flex', - flexDirection: 'column', - justifyContent: 'center', - alignItems: 'center', - } as React.CSSProperties, - thankYouContainer: { - display: 'flex', - flexDirection: 'column', - justifyContent: 'center', - alignItems: 'center', - }, - boundLabels: { - display: 'flex', - alignItems: 'center', - justifyContent: 'space-between', - width: '100%', - marginBottom: '10px', - }, - button: { - marginTop: tokens.Spacing.XLarge, - }, - errorMessage: { - display: 'flex', - alignItems: 'center', - width: '100%', - }, - errorIcon: { - marginRight: tokens.Spacing.Tiny, - }, - textQuestion: { - display: 'flex', - flexDirection: 'column', - width: '100%', - marginTop: tokens.Spacing.Large, - } as React.CSSProperties, - textQuestionTitle: { - marginBottom: tokens.Spacing.Medium, - }, -}) - ConnectSuccessSurvey.displayName = 'ConnectSuccessSurvey' diff --git a/src/components/DeleteMemberSurvey.js b/src/components/DeleteMemberSurvey.js index 6b76b5587f..8bc60982f2 100644 --- a/src/components/DeleteMemberSurvey.js +++ b/src/components/DeleteMemberSurvey.js @@ -1,12 +1,10 @@ import React, { useState, useEffect, useRef } from 'react' import PropTypes from 'prop-types' -import { Text } from '@mxenabled/mxui' -import { useTokens } from '@kyper/tokenprovider' +import { Icon, Text } from '@mxenabled/mxui' 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' +import { Button, FormLabel, FormControl, Stack } from '@mui/material' import { SelectionBox } from '@mxenabled/mxui' import { SlideDown } from 'src/components/SlideDown' @@ -17,6 +15,7 @@ import { useApi } from 'src/context/ApiContext' import useAnalyticsPath from 'src/hooks/useAnalyticsPath' import { PageviewInfo } from 'src/const/Analytics' import { ReadableStatuses } from 'src/const/Statuses' +import styles from 'src/components/DeleteMemberSurvey.module.css' export const DELETE_REASONS = { NO_LONGER_USE_ACCOUNT: "I no longer use this account or it's not mine", @@ -39,8 +38,6 @@ export const DeleteMemberSurvey = (props) => { error: null, }) const [isSubmitted, setIsSubmitted] = useState(false) - const tokens = useTokens() - const styles = getStyles(tokens) const CONNECTED_REASONS = [ __(DELETE_REASONS.NO_LONGER_USE_ACCOUNT), @@ -92,168 +89,143 @@ export const DeleteMemberSurvey = (props) => { } return ( containerRef.current }}> -
-
+ + {hasDeleteError ? ( -
- {__('Something went wrong')} -
- - - {__( - "Oops! We weren't able to disconnect this institution. Please try again later.", - )} - - + + + + {__('Something went wrong')} + + + + {__( + "Oops! We weren't able to disconnect this institution. Please try again later.", + )} + + + -
-
+
) : ( - - {__('Disconnect institution')} - - - - - {_p( - 'connect/deletesurvey/disclaimer/text', - 'Why do you want to disconnect %1?', - member.name, - )} - * - - -
- {reasonList.map((reason, i) => ( -
- setSelectedReason(e.target.value)} - selected={selectedReason === reason} - value={reason} - /> + + + {__('Disconnect institution')} + + + + + + {_p( + 'connect/deletesurvey/disclaimer/text', + 'Why do you want to disconnect %1?', + member.name, + )} + + * + + + +
+ {reasonList.map((reason, i) => ( +
+ setSelectedReason(e.target.value)} + selected={selectedReason === reason} + value={reason} + /> +
+ ))}
- ))} -
- - - - * {__('Required')} - + + + + + + * + {' '} + {__('Required')} + + {isSubmitted && !selectedReason && ( -
- -

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

-
+ + + + {__('Choose a reason for deleting')} + + )} - + + - + + )} -
-
+ + ) } -const getStyles = (tokens) => ({ - component: { - display: 'block', - whiteSpace: 'normal', - }, - container: { - zIndex: tokens.ZIndex.Modal, - position: 'absolute', - width: '100%', - backgroundColor: tokens.BackgroundColor.Container, - minHeight: '100%', - display: 'flex', - justifyContent: 'center', - }, - modal: { - backgroundColor: tokens.BackgroundColor.Modal, - color: tokens.TextColor.Default, - maxWidth: 400, - width: '100%', - padding: '20px', - display: 'flex', - flexDirection: 'column', - }, - reasons: { - marginTop: tokens.Spacing.Medium, - }, - button: { - width: '100%', - marginBottom: tokens.Spacing.XSmall, - marginTop: '20px', - }, - cancelButton: { - width: '100%', - }, - errorButton: { - width: '100%', - }, - errorHeader: { - fontSize: tokens.FontSize.H2, - fontWeight: tokens.FontWeight.Bold, - marginBottom: tokens.Spacing.XSmall, - }, - errorContent: { - color: tokens.TextColor.Error, - display: 'flex', - alignItems: 'center', - }, - errorMessage: { - marginLeft: tokens.Spacing.Tiny, - fontSize: tokens.FontSize.Small, - }, -}) - DeleteMemberSurvey.propTypes = { isOpen: PropTypes.bool.isRequired, member: PropTypes.object, diff --git a/src/components/DeleteMemberSurvey.module.css b/src/components/DeleteMemberSurvey.module.css new file mode 100644 index 0000000000..ddefac5caa --- /dev/null +++ b/src/components/DeleteMemberSurvey.module.css @@ -0,0 +1,23 @@ +.container:global(.MuiStack-root) { + background-color: var(--mui-palette-background-paper); + min-height: 100%; + position: absolute; + width: 100%; + z-index: 5000; +} + +.modal:global(.MuiStack-root) { + background-color: var(--mui-palette-background-paper); + color: var(--mui-palette-text-primary); + max-width: 400px; + padding: var(--spacing-2-point-5); + width: 100%; +} + +.requiredNote:global(.MuiTypography-root) { + margin-bottom: var(--spacing-1-point-5); +} + +.buttons:global(.MuiStack-root) { + margin-top: var(--spacing-2-point-5); +} diff --git a/src/components/GenericError.js b/src/components/GenericError.js index 8be005b22a..f6f961cd67 100644 --- a/src/components/GenericError.js +++ b/src/components/GenericError.js @@ -1,16 +1,13 @@ 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 { Stack } from '@mui/material' +import { Icon, Text } from '@mxenabled/mxui' import { isRunningE2ETests } from 'src/utilities/e2e' import { PageviewInfo } from 'src/const/Analytics' +import styles from 'src/components/GenericError.module.css' export const GenericError = ({ loadError, onAnalyticPageview, subtitle, title }) => { - const tokens = useTokens() - const styles = getStyles(tokens) - useEffect(() => { if (!isRunningE2ETests()) onAnalyticPageview( @@ -26,14 +23,9 @@ export const GenericError = ({ loadError, onAnalyticPageview, subtitle, title }) }, []) return ( -
- - + + + {title} {subtitle && ( @@ -41,28 +33,10 @@ export const GenericError = ({ loadError, onAnalyticPageview, subtitle, title }) {subtitle} )} -
+ ) } -function getStyles(tokens) { - return { - container: { - backgroundColor: tokens.BackgroundColor.Container, - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - flexDirection: 'column', - height: '100%', - padding: tokens.Spacing.XSMALL, - textAlign: 'center', - }, - icon: { - marginBottom: tokens.Spacing.XLarge, - }, - } -} - GenericError.propTypes = { loadError: PropTypes.object, onAnalyticPageview: PropTypes.func.isRequired, diff --git a/src/components/GenericError.module.css b/src/components/GenericError.module.css new file mode 100644 index 0000000000..228bafb042 --- /dev/null +++ b/src/components/GenericError.module.css @@ -0,0 +1,9 @@ +.container:global(.MuiStack-root) { + background-color: var(--mui-palette-background-paper); + height: 100%; + text-align: center; +} + +.title:global(.MuiTypography-root) { + margin-top: var(--spacing-4); +} diff --git a/src/components/InstructionalText.js b/src/components/InstructionalText.js index b22881af61..958b225330 100644 --- a/src/components/InstructionalText.js +++ b/src/components/InstructionalText.js @@ -2,20 +2,16 @@ import React, { useEffect } from 'react' import PropTypes from 'prop-types' import DOMPurify from 'dompurify' -import { useTokens } from '@kyper/tokenprovider' import { Text } from '@mxenabled/mxui' import { goToUrlLink } from 'src/utilities/global' +import styles from 'src/components/InstructionalText.module.css' export const InstructionalText = ({ instructionalText, setIsLeavingUrl, showExternalLinkPopup, - style = {}, }) => { - const tokens = useTokens() - const styles = getStyles(tokens) - const sanitizedInstructionalText = DOMPurify.sanitize(instructionalText, { ALLOWED_TAGS: ['a'], // Only allow ALLOWED_ATTR: ['href', 'id'], // Only allow href and id attributes @@ -41,8 +37,6 @@ export const InstructionalText = ({ if (!instructionalLink) return () => {} - Object.assign(instructionalLink.style, styles.instructionalLink) - instructionalLink.addEventListener('click', handleInstructionalTextClick) return () => removeEventListener('click', handleInstructionalTextClick) @@ -50,30 +44,18 @@ export const InstructionalText = ({ return ( ) } -const getStyles = (tokens) => ({ - instructionalLink: { - display: 'inline', - whiteSpace: 'normal', - height: 'auto', - fontSize: tokens.FontSize.Small, - textAlign: 'left', - color: tokens.TextColor.ButtonLink, - }, -}) - InstructionalText.propTypes = { instructionalText: PropTypes.string.isRequired, setIsLeavingUrl: PropTypes.func.isRequired, showExternalLinkPopup: PropTypes.bool.isRequired, - style: PropTypes.object, } diff --git a/src/components/InstructionalText.module.css b/src/components/InstructionalText.module.css new file mode 100644 index 0000000000..28b8d54e9d --- /dev/null +++ b/src/components/InstructionalText.module.css @@ -0,0 +1,12 @@ +.text:global(.MuiTypography-root) { + margin-bottom: var(--spacing-1); +} + +.text a { + color: var(--mui-palette-primary-main); + display: inline; + font-size: 13px; + height: auto; + text-align: left; + white-space: normal; +} diff --git a/src/components/LeavingNoticeFlat.js b/src/components/LeavingNoticeFlat.js index 409091ca20..35b118d90b 100644 --- a/src/components/LeavingNoticeFlat.js +++ b/src/components/LeavingNoticeFlat.js @@ -4,72 +4,69 @@ import PropTypes from 'prop-types' import { __ } from 'src/utilities/Intl' -import { Text } from '@mxenabled/mxui' -import { AttentionFilled } from '@kyper/icon/AttentionFilled' -import { Button } from '@mui/material' -import { useTokens } from '@kyper/tokenprovider' +import { Text, Icon } from '@mxenabled/mxui' +import { Button, Stack } from '@mui/material' import { SlideDown } from 'src/components/SlideDown' import { GoBackButton } from 'src/components/GoBackButton' import { getDelay } from 'src/utilities/getDelay' +import styles from 'src/components/LeavingNoticeFlat.module.css' export const LeavingNoticeFlat = ({ onContinue, onCancel, portalTo = 'connect-wrapper' }) => { - const tokens = useTokens() - const styles = getStyles(tokens) - const getNextDelay = getDelay() return createPortal( -
-
+
+
-
+ + + + {__('You are leaving')} + + + - {__('You are leaving')} + {__( + 'Selecting Continue will take you to an external website with a different privacy policy, security measures, and terms and conditions.', + )} - -
- - {__( - 'Selecting Continue will take you to an external website with a different privacy policy, security measures, and terms and conditions.', - )} - +
- - + + + +
, @@ -77,43 +74,6 @@ export const LeavingNoticeFlat = ({ onContinue, onCancel, portalTo = 'connect-wr ) } -const getStyles = (tokens) => { - return { - container: { - top: 0, - margin: '0 auto', - height: '100%', - width: '100%', - position: 'absolute', - zIndex: tokens.ZIndex.Modal, - backgroundColor: tokens.BackgroundColor.Container, - }, - content: { - maxWidth: '400px', - margin: `${tokens.Spacing.Medium}px auto 0`, - padding: '0 24px', - }, - header: { - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - marginBottom: tokens.Spacing.Medium, - }, - text: { - marginBottom: tokens.Spacing.Small, - }, - padding: { - marginBottom: tokens.Spacing.XLarge, - }, - continueButton: { - marginTop: tokens.Spacing.Large, - }, - cancelButton: { - marginTop: tokens.Spacing.XSmall, - }, - } -} - LeavingNoticeFlat.propTypes = { onCancel: PropTypes.func.isRequired, onContinue: PropTypes.func.isRequired, diff --git a/src/components/LeavingNoticeFlat.module.css b/src/components/LeavingNoticeFlat.module.css new file mode 100644 index 0000000000..69ac760662 --- /dev/null +++ b/src/components/LeavingNoticeFlat.module.css @@ -0,0 +1,19 @@ +.container { + background-color: var(--mui-palette-background-paper); + height: 100%; + margin: 0 auto; + position: absolute; + top: 0; + width: 100%; + z-index: 5000; +} + +.content { + margin: var(--spacing-2) auto 0; + max-width: 400px; + padding: 0 var(--spacing-3); +} + +.buttons:global(.MuiStack-root) { + margin-top: var(--spacing-3); +} diff --git a/src/components/RequiredFieldNote.module.css b/src/components/RequiredFieldNote.module.css new file mode 100644 index 0000000000..add0777e81 --- /dev/null +++ b/src/components/RequiredFieldNote.module.css @@ -0,0 +1,12 @@ +.container:global(.MuiBox-root) { + margin-bottom: var(--spacing-4); + margin-top: var(--spacing-2); +} + +.note:global(.MuiTypography-root) { + color: var(--mui-palette-text-secondary); +} + +.asterisk:global(.MuiTypography-root) { + color: var(--mui-palette-error-main); +} diff --git a/src/components/RequiredFieldNote.tsx b/src/components/RequiredFieldNote.tsx index 7267f9a65a..919bd4d0c0 100644 --- a/src/components/RequiredFieldNote.tsx +++ b/src/components/RequiredFieldNote.tsx @@ -1,38 +1,18 @@ import React from 'react' import { Typography, Box } from '@mui/material' import { __ } from 'src/utilities/Intl' +import styles from 'src/components/RequiredFieldNote.module.css' interface RequiredFieldNoteProps { - styles?: object + className?: string + styles?: React.CSSProperties } -const RequiredFieldNote: React.FC = ({ styles }) => { - // TODO: Replace with MXUI color tokens. - const requiredFieldNoteColor = '#666' - const asteriskColor = '#E32727' - +const RequiredFieldNote: React.FC = ({ className, styles: overrides }) => { return ( - - - + + + * {' '} {__('Required')} diff --git a/src/components/ViewTitle.js b/src/components/ViewTitle.js index 87b605996a..9c733418c9 100644 --- a/src/components/ViewTitle.js +++ b/src/components/ViewTitle.js @@ -1,19 +1,24 @@ import React from 'react' import PropTypes from 'prop-types' -import { Text } from '@mxenabled/mxui' +import { Stack } from '@mui/material' +import { Icon, Text } from '@mxenabled/mxui' import { useTokens } from '@kyper/tokenprovider' import { InfoFilled } from '@kyper/icon/InfoFilled' -import { AttentionFilled } from '@kyper/icon/AttentionFilled' import { ReadableStatuses } from 'src/const/Statuses' +import styles from 'src/components/ViewTitle.module.css' export const ViewTitle = ({ connectionStatus, title }) => { const tokens = useTokens() - const styles = getStyles(tokens) return ( -
+ {title} @@ -21,21 +26,12 @@ export const ViewTitle = ({ connectionStatus, title }) => { )} {connectionStatus === ReadableStatuses.REJECTED && ( - + )} -
+ ) } -const getStyles = (tokens) => ({ - container: { - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - marginBottom: tokens.Spacing.Tiny, - }, -}) - ViewTitle.propTypes = { connectionStatus: PropTypes.number, title: PropTypes.string.isRequired, diff --git a/src/components/ViewTitle.module.css b/src/components/ViewTitle.module.css new file mode 100644 index 0000000000..88f3af64c4 --- /dev/null +++ b/src/components/ViewTitle.module.css @@ -0,0 +1,3 @@ +.container:global(.MuiStack-root) { + margin-bottom: var(--spacing-point-5); +} 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/styles/spacing.css b/src/styles/spacing.css new file mode 100644 index 0000000000..600a852008 --- /dev/null +++ b/src/styles/spacing.css @@ -0,0 +1,13 @@ +:root { + --spacing-point-25: calc(var(--mui-spacing) * 0.25); + --spacing-point-5: calc(var(--mui-spacing) * 0.5); + --spacing-1: calc(var(--mui-spacing) * 1); + --spacing-1-point-25: calc(var(--mui-spacing) * 1.25); + --spacing-1-point-5: calc(var(--mui-spacing) * 1.5); + --spacing-2: calc(var(--mui-spacing) * 2); + --spacing-2-point-5: calc(var(--mui-spacing) * 2.5); + --spacing-3: calc(var(--mui-spacing) * 3); + --spacing-4: calc(var(--mui-spacing) * 4); + --spacing-4-point-5: calc(var(--mui-spacing) * 4.5); + --spacing-6: calc(var(--mui-spacing) * 6); +} diff --git a/src/styles/styles.css b/src/styles/styles.css new file mode 100644 index 0000000000..5dfff02a14 --- /dev/null +++ b/src/styles/styles.css @@ -0,0 +1,6 @@ +/* TODO: Remove this file once we are on MXUI v2 */ +:root { + --mui-palette-common-white: #ffffff; + --mui-palette-common-black: #000000; + --mui-spacing: 8px; +} 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/actionableError/ActionableError.module.css b/src/views/actionableError/ActionableError.module.css new file mode 100644 index 0000000000..8a40457dac --- /dev/null +++ b/src/views/actionableError/ActionableError.module.css @@ -0,0 +1,21 @@ +.logoWrapper:global(.MuiStack-root) { + margin-top: var(--spacing-2-point-5); +} + +.badge :global(.MuiBadge-badge) { + border: 2px solid var(--mui-palette-background-paper); + border-radius: 100%; + font-size: 18px; + font-weight: bold; + height: 28px; + width: 28px; + margin: var(--spacing-point-5); +} + +.textGroup:global(.MuiStack-root) { + text-align: center; +} + +.buttons:global(.MuiStack-root) { + margin-bottom: var(--spacing-1); +} diff --git a/src/views/actionableError/ActionableError.tsx b/src/views/actionableError/ActionableError.tsx index 349286154b..30a7cc9403 100644 --- a/src/views/actionableError/ActionableError.tsx +++ b/src/views/actionableError/ActionableError.tsx @@ -1,12 +1,12 @@ import React, { useContext, useEffect } from 'react' import { useSelector } from 'react-redux' import { InstitutionLogo, Text } from '@mxenabled/mxui' -import { useTokens } from '@kyper/tokenprovider' -import { Button, Badge } from '@mui/material' +import { Button, Badge, Stack } from '@mui/material' import { SlideDown } from 'src/components/SlideDown' import { PostMessageContext } from 'src/ConnectWidget' import { useActionableErrorMap } from 'src/views/actionableError/useActionableErrorMap' +import styles from 'src/views/actionableError/ActionableError.module.css' import { ACTIONABLE_ERROR_CODES_READABLE } from 'src/views/actionableError/consts' import { PageviewInfo } from 'src/const/Analytics' @@ -26,8 +26,6 @@ export const ActionableError = () => { error_code: jobDetailCode, readable_error: ACTIONABLE_ERROR_CODES_READABLE[jobDetailCode], }) - const tokens = useTokens() - const styles = getStyles(tokens) const getNextDelay = getDelay() const errorDetails = useActionableErrorMap(jobDetailCode) @@ -42,92 +40,57 @@ export const ActionableError = () => { }, [jobDetailCode]) return ( - <> + -
- + + -
+
- - {errorDetails?.title} - - - {errorDetails?.userMessage || currentMember.error.user_message} - + + + {errorDetails?.title} + + + {errorDetails?.userMessage || currentMember.error.user_message} + + - - {errorDetails?.secondaryActions && ( + - )} + {errorDetails?.secondaryActions && ( + + )} + - + ) } - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const getStyles = (tokens: any) => ({ - logoWrapper: { - display: 'flex', - justifyContent: 'center', - marginBottom: tokens.Spacing.XLarge, - marginTop: 20, - width: '100%', - }, - badge: { - '& .MuiBadge-badge': { - fontWeight: 'bold', - borderRadius: '100%', - border: `2px solid ${tokens.BackgroundColor.Container}`, - fontSize: tokens.FontSize.H3, - margin: tokens.Spacing.Tiny, - height: tokens.Spacing.Large + tokens.Spacing.Tiny, - width: tokens.Spacing.Large + tokens.Spacing.Tiny, - }, - }, - title: { - marginBottom: tokens.Spacing.Tiny, - textAlign: 'center' as const, - }, - paragraph: { - marginBottom: tokens.Spacing.XLarge, - textAlign: 'center' as const, - }, -}) 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/Credentials.js b/src/views/credentials/Credentials.js index 9c0e665a00..4a554b1c5c 100644 --- a/src/views/credentials/Credentials.js +++ b/src/views/credentials/Credentials.js @@ -12,9 +12,8 @@ import { useSelector } from 'react-redux' import { Text } from '@mxenabled/mxui' import { MessageBox } from '@kyper/messagebox' -import { useTokens } from '@kyper/tokenprovider' import { TextField } from 'src/privacy/input' -import { Button } from '@mui/material' +import { Button, Stack } from '@mui/material' import { __ } from 'src/utilities/Intl' import { getInstitutionLoginUrl } from 'src/utilities/Institution' @@ -58,6 +57,7 @@ import { usePasswordInputValidation } from 'src/views/credentials/usePasswordInp import useAnalyticsEvent from 'src/hooks/useAnalyticsEvent' import { PostMessageContext } from 'src/ConnectWidget' import RequiredFieldNote from 'src/components/RequiredFieldNote' +import styles from 'src/views/credentials/Credentials.module.css' export const Credentials = React.forwardRef( ( @@ -81,7 +81,6 @@ export const Credentials = React.forwardRef( usePasswordInputValidation() // Redux Selectors/Dispatch const connectConfig = useSelector(selectConnectConfig) - const isSmall = useSelector((state) => state.browser.size) === 'small' const institution = useSelector(getSelectedInstitution) const showExternalLinkPopup = useSelector( (state) => state.profiles.clientProfile.show_external_link_popup, @@ -109,8 +108,6 @@ export const Credentials = React.forwardRef( const [needToSendAnalyticEvent, setNeedToSendAnalyticEvent] = useState(true) const [needToSendPasswordAnalyticEvent, setPasswordAnalyticEvent] = useState(true) - const tokens = useTokens() - const styles = getStyles(tokens, isSmall) const getNextDelay = getDelay(0, 100) const initialValues = buildInitialValues(credentials) const formSchema = buildFormSchema(credentials) @@ -371,17 +368,14 @@ export const Credentials = React.forwardRef( - + @@ -416,8 +410,8 @@ export const Credentials = React.forwardRef( {shouldShowMessageBox(error, currentMember, connectConfig.mode) && ( @@ -437,16 +431,21 @@ export const Credentials = React.forwardRef( )} {loginFieldCount > 0 ? ( -
e.preventDefault()} - style={styles.form} + spacing={3} + useFlexGap={true} > {credentials.map((field) => ( {field.field_type === CREDENTIAL_FIELD_TYPES.PASSWORD ? ( -
+
}} autoCapitalize="none" @@ -482,7 +481,7 @@ export const Credentials = React.forwardRef( />
) : ( -
+
))} - + - + ) : ( @@ -535,7 +532,7 @@ export const Credentials = React.forwardRef( )} -
+ {credentialRecovery()} {showDisconnectOption && (
+
{ - return { - headerText: { - paddingBottom: tokens.Spacing.XSmall, - }, - form: { - paddingTop: tokens.Spacing.Large, - flexDirection: 'column', - gap: tokens.Spacing.Large, - display: 'flex', - }, - inputError: { - marginBottom: tokens.Spacing.Large, - marginTop: tokens.Spacing.XSmall, - }, - passwordInputError: { - marginTop: tokens.Spacing.XSmall, - }, - buttonBack: { - marginTop: tokens.Spacing.Medium, - marginBottom: '12px', - }, - actionColumn: { - display: 'flex', - flexDirection: 'column', - alignItems: 'center', - marginBottom: tokens.Spacing.Tiny, - }, - text: { - paddingLeft: tokens.Spacing.XSmall, - color: tokens.Color.Primary300, - }, - hr: { - borderTop: `1px solid ${tokens.BackgroundColor.HrLight}`, - }, - credentialsError: { - marginTop: tokens.Spacing.Medium, - }, - } -} - Credentials.propTypes = { credentials: PropTypes.array, error: PropTypes.object, diff --git a/src/views/credentials/Credentials.module.css b/src/views/credentials/Credentials.module.css new file mode 100644 index 0000000000..33e94e738e --- /dev/null +++ b/src/views/credentials/Credentials.module.css @@ -0,0 +1,33 @@ +.headerText:global(.MuiTypography-root) { + padding-bottom: var(--spacing-1); +} + +.credentialsError { + margin-top: var(--spacing-2); +} + +.form:global(.MuiStack-root) { + padding-top: var(--spacing-3); +} + +.passwordInputError { + margin-top: var(--spacing-1); +} + +.inputError { + margin-bottom: var(--spacing-3); + margin-top: var(--spacing-1); +} + +.actionColumn:global(.MuiStack-root) { + margin-bottom: var(--spacing-point-5); +} + +.requiredFieldNote.requiredFieldNote:global(.MuiBox-root) { + margin-bottom: var(--spacing-1-point-5); + margin-top: 0; +} + +.continueButton:global(.MuiButton-root) { + margin-bottom: var(--spacing-1); +} 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..87d80e517d 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..e25b6a2337 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/microdeposits/AccountInfo.js b/src/views/microdeposits/AccountInfo.js index cd6899376c..9879d44cd5 100644 --- a/src/views/microdeposits/AccountInfo.js +++ b/src/views/microdeposits/AccountInfo.js @@ -6,7 +6,7 @@ import { useTokens } from '@kyper/tokenprovider' import { Text } from '@mxenabled/mxui' import { ChevronRight } from '@kyper/icon/ChevronRight' import { TextField, SelectionBox } from 'src/privacy/input' -import { Button, RadioGroup, FormControl, FormLabel } from '@mui/material' +import { Button, RadioGroup, FormControl, FormLabel, Stack } from '@mui/material' import useAnalyticsPath from 'src/hooks/useAnalyticsPath' @@ -26,6 +26,7 @@ import { import { useForm } from 'src/hooks/useForm' import { getDelay } from 'src/utilities/getDelay' import RequiredFieldNote from 'src/components/RequiredFieldNote' +import styles from 'src/views/microdeposits/AccountInfo.module.css' export const AccountInfo = (props) => { const { accountDetails, focus, onContinue } = props @@ -59,7 +60,6 @@ export const AccountInfo = (props) => { initialForm, ) const tokens = useTokens() - const styles = getStyles(tokens) const getNextDelay = getDelay() function handleContinue() { @@ -77,37 +77,18 @@ export const AccountInfo = (props) => { } return ( -
+ -
- - {__('Enter account information')} - -
+ + {__('Enter account information')} +
e.preventDefault()}> - + {__('Account type')} - .ph-no-capture': { - width: '48%', - }, - }} - > + { -
- -
-
- -
+ +
+ +
+
+ +
+
@@ -179,10 +162,10 @@ export const AccountInfo = (props) => {
+ ) } -const getStyles = (tokens) => ({ - header: { - display: 'flex', - flexDirection: 'column', - }, - title: { - marginBottom: tokens.Spacing.Medium, - }, - label: { - fontSize: tokens.FontSize.InputLabel, - backgroundColor: tokens.BackgroundColor.InputLabelDefault, - color: tokens.TextColor.InputLabel, - lineHeight: tokens.LineHeight.Small, - }, - selectBoxes: { - display: 'flex', - justifyContent: 'space-between', - padding: '0 0 32px 0', - marginTop: tokens.Spacing.XSmall, - }, - selectBox: { - width: '48%', - }, - inputStyle: { - marginBottom: tokens.Spacing.XLarge, - }, - button: { - marginBottom: tokens.Spacing.Small, - }, -}) - AccountInfo.propTypes = { accountDetails: PropTypes.object, focus: PropTypes.string, diff --git a/src/views/microdeposits/AccountInfo.module.css b/src/views/microdeposits/AccountInfo.module.css new file mode 100644 index 0000000000..5a44ee82a2 --- /dev/null +++ b/src/views/microdeposits/AccountInfo.module.css @@ -0,0 +1,17 @@ +.formControl:global(.MuiFormControl-root) { + width: 100%; +} + +.radioGroup:global(.MuiFormGroup-root) { + justify-content: space-between; + margin-top: var(--spacing-1); + padding-bottom: var(--spacing-2); +} + +.radioGroup > :global(.ph-no-capture) { + width: 48%; +} + +.button:global(.MuiButton-root) { + margin-bottom: var(--spacing-1-point-5); +} diff --git a/src/views/oauth/experiments/PredirectInstructions.module.css b/src/views/oauth/experiments/PredirectInstructions.module.css new file mode 100644 index 0000000000..612d454190 --- /dev/null +++ b/src/views/oauth/experiments/PredirectInstructions.module.css @@ -0,0 +1,7 @@ +.title:global(.MuiTypography-root) { + margin-bottom: var(--spacing-1-point-5); +} + +.institutionName:global(.MuiTypography-root) { + color: var(--mui-palette-common-white); +} diff --git a/src/views/oauth/experiments/PredirectInstructions.tsx b/src/views/oauth/experiments/PredirectInstructions.tsx index 2af88d7f85..f97b4fcfce 100644 --- a/src/views/oauth/experiments/PredirectInstructions.tsx +++ b/src/views/oauth/experiments/PredirectInstructions.tsx @@ -1,6 +1,7 @@ import React from 'react' import 'src/views/oauth/experiments/PredirectInstructions.css' +import styles from 'src/views/oauth/experiments/PredirectInstructions.module.css' import { Text } from '@mxenabled/mxui' import { __ } from 'src/utilities/Intl' @@ -63,7 +64,7 @@ function PredirectInstructions( return ( <> - + {__('Log in at %1', props.institution.name)}
@@ -82,7 +83,12 @@ function PredirectInstructions( {/* Inline color and font styles on the header and text because this is a dynamic area */}
-
diff --git a/src/views/search/views/SearchFailed.js b/src/views/search/views/SearchFailed.js index a161fc25a5..b150e814dd 100644 --- a/src/views/search/views/SearchFailed.js +++ b/src/views/search/views/SearchFailed.js @@ -1,63 +1,29 @@ import React from 'react' -import { useTokens } from '@kyper/tokenprovider' -import { AttentionFilled } from '@kyper/icon/AttentionFilled' +import { Stack } from '@mui/material' +import { Icon, Text } from '@mxenabled/mxui' import { __ } from 'src/utilities/Intl' import useAnalyticsPath from 'src/hooks/useAnalyticsPath' import { PageviewInfo } from 'src/const/Analytics' +import styles from 'src/views/search/views/SearchFailed.module.css' export const SearchFailed = () => { useAnalyticsPath(...PageviewInfo.CONNECT_SEARCH_FAILED) - const tokens = useTokens() - const styles = getStyles(tokens) return ( -
-
- -
-
-
{__('Search isn’t working')}
-
{__('Something went wrong. Please try again.')}
-
-
+ + + + + + + {__('Search isn’t working')} + + + {__('Something went wrong. Please try again.')} + + + ) } - -const getStyles = (tokens) => { - return { - container: { - display: 'flex', - justifyContent: 'flex-start', - alignItems: 'flex-start', - marginTop: tokens.Spacing.ContainerSidePadding, - }, - iconContainer: { - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - minHeight: '48px', - minWidth: '48px', - marginRight: tokens.Spacing.Small, - borderRadius: tokens.BorderRadius.Medium, - backgroundColor: tokens.BackgroundColor.ButtonDestructive, - }, - textContainer: { - display: 'flex', - flexDirection: 'column', - marginTop: tokens.Spacing.Tiny, - }, - title: { - color: tokens.TextColor.Default, - fontSize: tokens.FontSize.Body, - fontWeight: tokens.FontWeight.Bold, - lineHeight: tokens.LineHeight.ParagraphSmall, - }, - subTitle: { - color: tokens.TextColor.Default, - fontSize: tokens.FontSize.Small, - lineHeight: tokens.LineHeight.ParagraphSmall, - }, - } -} diff --git a/src/views/search/views/SearchFailed.module.css b/src/views/search/views/SearchFailed.module.css new file mode 100644 index 0000000000..45573848cb --- /dev/null +++ b/src/views/search/views/SearchFailed.module.css @@ -0,0 +1,16 @@ +.container:global(.MuiStack-root) { + margin-top: var(--spacing-3); +} + +.iconContainer:global(.MuiStack-root) { + background-color: var(--mui-palette-error-main); + border-radius: 4px; + color: var(--mui-palette-error-contrastText); + margin-right: var(--spacing-1-point-5); + min-height: 48px; + min-width: 48px; +} + +.textContainer:global(.MuiStack-root) { + margin-top: var(--spacing-point-5); +} diff --git a/src/views/verification/VerifyExistingMember.module.css b/src/views/verification/VerifyExistingMember.module.css new file mode 100644 index 0000000000..54cfbb238c --- /dev/null +++ b/src/views/verification/VerifyExistingMember.module.css @@ -0,0 +1,28 @@ +.header:global(.MuiTypography-root) { + margin-bottom: var(--spacing-1-point-5); +} + +.description:global(.MuiTypography-root) { + margin-bottom: var(--spacing-3); +} + +.connectedCount:global(.MuiTypography-root) { + margin-bottom: var(--spacing-point-5); +} + +.listItemButton:global(.MuiButtonBase-root) { + border-radius: 8px; + margin: 0; + min-height: 72px; + padding-left: 0; + padding-right: 0; +} + +.avatar:global(.MuiListItemAvatar-root) { + min-height: 48px; + min-width: 48px; +} + +.searchButton:global(.MuiButton-root) { + margin-top: var(--spacing-3); +} diff --git a/src/views/verification/VerifyExistingMember.tsx b/src/views/verification/VerifyExistingMember.tsx index dda45dddc3..0f920353d5 100644 --- a/src/views/verification/VerifyExistingMember.tsx +++ b/src/views/verification/VerifyExistingMember.tsx @@ -1,13 +1,18 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ import React, { useState, useEffect, useCallback, useMemo } from 'react' import PropTypes from 'prop-types' import { useDispatch, useSelector } from 'react-redux' -import { useTokens } from '@kyper/tokenprovider' -import { List, ListItem, ListItemAvatar, ListItemButton, ListItemText } from '@mui/material' +import { + Button, + List, + ListItem, + ListItemAvatar, + ListItemButton, + ListItemText, + Stack, +} from '@mui/material' import { Text } from '@mxenabled/mxui' import { InstitutionLogo } from '@kyper/institutionlogo' -import { Button } from '@mui/material' import { selectConfig } from 'src/redux/reducers/configSlice' import { startOauth, verifyExistingConnection } from 'src/redux/actions/Connect' @@ -21,6 +26,7 @@ import { PageviewInfo } from 'src/const/Analytics' import { PrivateAndSecure } from 'src/components/PrivateAndSecure' import { LoadingSpinner } from 'src/components/LoadingSpinner' import { GenericError } from 'src/components/GenericError' +import styles from 'src/views/verification/VerifyExistingMember.module.css' interface VerifyExistingMemberProps { members: MemberResponseType[] @@ -30,8 +36,6 @@ interface VerifyExistingMemberProps { const VerifyExistingMember: React.FC = (props) => { useAnalyticsPath(...PageviewInfo.CONNECT_VERIFY_EXISTING_MEMBER) const { api } = useApi() - const tokens = useTokens() - const styles = getStyles(tokens) const config = useSelector(selectConfig) const dispatch = useDispatch() const { members, onAddNew } = props @@ -119,13 +123,13 @@ const VerifyExistingMember: React.FC = (props) => { } return ( -
+ = (props) => { {__('Select your institution')} @@ -145,9 +149,10 @@ const VerifyExistingMember: React.FC = (props) => {
@@ -163,10 +168,10 @@ const VerifyExistingMember: React.FC = (props) => { return ( handleMemberClick(member)} - style={styles.listItemButton} > - + = (props) => { })} -
+ ) } -const getStyles = (tokens: any) => { - return { - container: { - display: 'flex', - flexDirection: 'column', - } as React.CSSProperties, - listItemButton: { - borderRadius: tokens.BorderRadius.Large, - margin: 0, - paddingLeft: 0, - paddingRight: 0, - minHeight: 72, - }, - buttonSpacing: { - marginTop: tokens.Spacing.Large, - }, - } -} - VerifyExistingMember.propTypes = { members: PropTypes.array.isRequired, onAddNew: PropTypes.func.isRequired, 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'