diff --git a/package-lock.json b/package-lock.json index 23aa82ad55..6bfd592629 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "@kyper/utilityrow": "^2.1.0", "@mui/icons-material": "^6.1.5", "@mui/material": "^6.1.5", - "@mxenabled/mxui": "^1.6.0", + "@mxenabled/mxui": "^1.7.0", "@reduxjs/toolkit": "^2.2.7", "@types/node": "^22.1.0", "bowser": "^2.11.0", @@ -865,7 +865,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -882,7 +881,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -899,7 +897,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -916,7 +913,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -933,7 +929,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -949,7 +944,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -966,7 +960,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -983,7 +976,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1000,7 +992,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1017,7 +1008,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1034,7 +1024,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1051,7 +1040,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1068,7 +1056,6 @@ "cpu": [ "mips64el" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1085,7 +1072,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1102,7 +1088,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1119,7 +1104,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1136,7 +1120,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1153,7 +1136,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1170,7 +1152,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1187,7 +1168,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1204,7 +1184,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1221,7 +1200,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1238,7 +1216,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1255,7 +1232,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1272,7 +1248,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1289,7 +1264,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2800,9 +2774,9 @@ } }, "node_modules/@mxenabled/mxui": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@mxenabled/mxui/-/mxui-1.6.0.tgz", - "integrity": "sha512-y5BD01eRwjBXrUJzBh516KC5dF/wfFOMtLBSio5udxW+Xf97h0VSVu1eCNb5Z1jq43WDdHvQltCpEj3siQt2cw==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@mxenabled/mxui/-/mxui-1.7.0.tgz", + "integrity": "sha512-qpy9BduXIBvlhr5OPWG6aWs3IjOfyaYQzAn1/TgHR7vcyA5v/YBMrt0vs3u4XSETTB3bGRWfHOvmKU+raLhpMw==", "license": "MIT", "dependencies": { "@emotion/react": "^11.14.0", @@ -3349,7 +3323,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3363,7 +3336,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3377,7 +3349,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3391,7 +3362,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3405,7 +3375,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3419,7 +3388,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3433,7 +3401,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3447,7 +3414,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3461,7 +3427,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3475,7 +3440,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3489,7 +3453,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3503,7 +3466,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3517,7 +3479,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3531,7 +3492,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3545,7 +3505,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3559,7 +3518,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3573,7 +3531,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3587,7 +3544,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3601,7 +3557,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3615,7 +3570,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3629,7 +3583,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3643,7 +3596,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3657,7 +3609,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3671,7 +3622,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3685,7 +3635,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -8391,7 +8340,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -9965,7 +9913,6 @@ "version": "2.6.1", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", - "dev": true, "optional": true, "bin": { "jiti": "lib/jiti-cli.mjs" @@ -17829,7 +17776,7 @@ "version": "2.8.3", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", - "dev": true, + "devOptional": true, "license": "ISC", "bin": { "yaml": "bin.mjs" diff --git a/package.json b/package.json index 8ec254fe72..5694a6b849 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "@kyper/utilityrow": "^2.1.0", "@mui/icons-material": "^6.1.5", "@mui/material": "^6.1.5", - "@mxenabled/mxui": "^1.6.0", + "@mxenabled/mxui": "^1.7.0", "@reduxjs/toolkit": "^2.2.7", "@types/node": "^22.1.0", "bowser": "^2.11.0", diff --git a/src/ConnectedTokenProvider.tsx b/src/ConnectedTokenProvider.tsx index ee8bfc8404..81b4c1515f 100644 --- a/src/ConnectedTokenProvider.tsx +++ b/src/ConnectedTokenProvider.tsx @@ -21,6 +21,8 @@ declare module '@mui/material/styles' { } } +export const muiListItemButtonPadding = 12 + const connectThemeOverrides = (palette: Theme['palette']) => ({ components: { MuiTypography: { @@ -144,6 +146,15 @@ const connectThemeOverrides = (palette: Theme['palette']) => ({ }, }, }, + MuiListItemButton: { + styleOverrides: { + root: { + borderRadius: 8, + paddingLeft: muiListItemButtonPadding, + paddingRight: muiListItemButtonPadding, + }, + }, + }, }, // TODO: Remove this custom spacing scale once we are on MXUI v2. spacing: (factor: number) => `${factor * 8}px`, @@ -195,10 +206,11 @@ export const ConnectedTokenProvider = ({ children }: Props): React.ReactNode => tokenOverrides={kyperTokenOverrides} > - {/* This block can be deleted once we are on MXUI v2. */} ', () => { + it('renders its children', () => { + const childContent = 'Child content' + + render( + +
{childContent}
+
, + ) + + expect(screen.getByText(childContent)).toBeInTheDocument() + }) +}) diff --git a/src/shared/MuiList/FlushListContainer.tsx b/src/shared/MuiList/FlushListContainer.tsx new file mode 100644 index 0000000000..68b986fc79 --- /dev/null +++ b/src/shared/MuiList/FlushListContainer.tsx @@ -0,0 +1,7 @@ +import React, { ReactNode } from 'react' + +import styles from 'src/shared/MuiList/FlushListContainer.module.css' + +export const FlushListContainer = ({ children }: { children: ReactNode }) => ( +
{children}
+) diff --git a/src/views/manualAccount/ManualAccountMenu.js b/src/views/manualAccount/ManualAccountMenu.js deleted file mode 100644 index 7849c7ba6c..0000000000 --- a/src/views/manualAccount/ManualAccountMenu.js +++ /dev/null @@ -1,114 +0,0 @@ -import React, { useEffect } from 'react' -import PropTypes from 'prop-types' -import { __ } from 'src/utilities/Intl' - -import { Icon, Text } from '@mxenabled/mxui' -import { UtilityRow } from '@kyper/utilityrow' - -import { fadeOut } from 'src/utilities/Animation' - -import { SlideDown } from 'src/components/SlideDown' - -import { getDelay } from 'src/utilities/getDelay' -import { focusElement } from 'src/utilities/Accessibility' -import { AccountTypeNames, AccountTypes } from 'src/views/manualAccount/constants' -import { StyledAccountTypeIcon } from 'src/components/StyledAccountTypeIcon' -import { Stack } from '@mui/material' - -export const ManualAccountMenu = React.forwardRef((props, ref) => { - const getNextDelay = getDelay() - - const typeList = - props.availableAccountTypes?.length !== 0 - ? props.availableAccountTypes - : [ - AccountTypes.CHECKING, - AccountTypes.SAVINGS, - AccountTypes.LOAN, - AccountTypes.CREDIT_CARD, - AccountTypes.INVESTMENT, - AccountTypes.LINE_OF_CREDIT, - AccountTypes.MORTGAGE, - AccountTypes.PROPERTY, - AccountTypes.CASH, - AccountTypes.INSURANCE, - AccountTypes.PREPAID, - AccountTypes.UNKNOWN, - ] - - const getIcon = { - [AccountTypes.CHECKING]: , - [AccountTypes.SAVINGS]: , - [AccountTypes.LOAN]: , - [AccountTypes.CREDIT_CARD]: , - [AccountTypes.INVESTMENT]: , - [AccountTypes.LINE_OF_CREDIT]: , - [AccountTypes.MORTGAGE]: , - [AccountTypes.PROPERTY]: , - [AccountTypes.CASH]: , - [AccountTypes.INSURANCE]: , - [AccountTypes.PREPAID]: , - [AccountTypes.UNKNOWN]: , - } - - useEffect(() => { - const timer = setTimeout(() => { - focusElement(document.querySelector('[data-test="back-button"]:first-of-type')) - }, 300) - - return () => clearTimeout(timer) - }, []) - - return ( -
- - - - - - {__('Add account manually')} - - - {__("Track accounts, assets, and other things that don't have a live connection.")} - - - - - - - {typeList.map((account_type, i) => ( - - fadeOut(ref.current, 'up', 300).then(props.handleAccountTypeSelect(account_type)) - } - rightChildren={} - title={AccountTypeNames[account_type]()} - /> - ))} - - -
- ) -}) - -ManualAccountMenu.propTypes = { - availableAccountTypes: PropTypes.array, - handleAccountTypeSelect: PropTypes.func.isRequired, -} - -ManualAccountMenu.displayName = 'ManualAccountMenu' diff --git a/src/views/manualAccount/ManualAccountMenu.test.tsx b/src/views/manualAccount/ManualAccountMenu.test.tsx new file mode 100644 index 0000000000..a999e8e436 --- /dev/null +++ b/src/views/manualAccount/ManualAccountMenu.test.tsx @@ -0,0 +1,28 @@ +import React from 'react' + +import { screen, render } from 'src/utilities/testingLibrary' + +import { ManualAccountConnect } from 'src/views/manualAccount/ManualAccountConnect' + +describe('manualAccountMenu', () => { + it.each([ + 'Checking', + 'Savings', + 'Loan', + 'Credit Card', + 'Investment', + 'Line of Credit', + 'Mortgage', + 'Property', + 'Cash', + 'Insurance', + 'Prepaid', + 'Other', + ])('shows the %s form when the %s menu button is clicked', async (formType) => { + const { user } = render() + + await user.click(await screen.findByRole('button', { name: formType })) + + expect(await screen.findByTestId('manual-account-form-header')).toHaveTextContent(formType) + }) +}) diff --git a/src/views/manualAccount/ManualAccountMenu.tsx b/src/views/manualAccount/ManualAccountMenu.tsx new file mode 100644 index 0000000000..c7e6149d25 --- /dev/null +++ b/src/views/manualAccount/ManualAccountMenu.tsx @@ -0,0 +1,127 @@ +import React, { Fragment, useEffect } from 'react' +import { __ } from 'src/utilities/Intl' +import { Icon, Text } from '@mxenabled/mxui' +import { + List, + ListItem, + ListItemAvatar, + ListItemButton, + ListItemIcon, + ListItemText, +} from '@mui/material' + +import { SlideDown } from 'src/components/SlideDown' + +import { getDelay } from 'src/utilities/getDelay' +import { focusElement } from 'src/utilities/Accessibility' +import { AccountTypeNames, AccountTypes } from 'src/views/manualAccount/constants' +import { StyledAccountTypeIcon } from 'src/components/StyledAccountTypeIcon' +import { Stack } from '@mui/material' +import { FlushListContainer } from 'src/shared/MuiList/FlushListContainer' + +interface ManualAccountMenuProps { + availableAccountTypes?: number[] + handleAccountTypeSelect: (accountType: number) => void +} + +export const ManualAccountMenu = React.forwardRef( + (props, ref) => { + const getNextDelay = getDelay() + + const typeList = + props.availableAccountTypes?.length !== 0 + ? props.availableAccountTypes + : [ + AccountTypes.CHECKING, + AccountTypes.SAVINGS, + AccountTypes.LOAN, + AccountTypes.CREDIT_CARD, + AccountTypes.INVESTMENT, + AccountTypes.LINE_OF_CREDIT, + AccountTypes.MORTGAGE, + AccountTypes.PROPERTY, + AccountTypes.CASH, + AccountTypes.INSURANCE, + AccountTypes.PREPAID, + AccountTypes.UNKNOWN, + ] + + const iconSize = 24 + + const getIcon: { [key: number]: React.ReactElement } = { + [AccountTypes.CHECKING]: , + [AccountTypes.SAVINGS]: , + [AccountTypes.LOAN]: , + [AccountTypes.CREDIT_CARD]: , + [AccountTypes.INVESTMENT]: , + [AccountTypes.LINE_OF_CREDIT]: , + [AccountTypes.MORTGAGE]: , + [AccountTypes.PROPERTY]: , + [AccountTypes.CASH]: , + [AccountTypes.INSURANCE]: , + [AccountTypes.PREPAID]: , + [AccountTypes.UNKNOWN]: , + } + + useEffect(() => { + const timer = setTimeout(() => { + focusElement(document.querySelector('[data-test="back-button"]:first-of-type')) + }, 300) + + return () => clearTimeout(timer) + }, []) + + return ( +
+ + + + + + {__('Add account manually')} + + + {__("Track accounts, assets, and other things that don't have a live connection.")} + + + + {typeList?.map((account_type) => ( + + + props.handleAccountTypeSelect(account_type)} + > + {getIcon[account_type]} + + {AccountTypeNames[account_type]()} + + + + + + + + ))} + + + + + +
+ ) + }, +) + +ManualAccountMenu.displayName = 'ManualAccountMenu' diff --git a/src/views/manualAccount/__tests__/manualAccountMenu-test.tsx b/src/views/manualAccount/__tests__/manualAccountMenu-test.tsx deleted file mode 100644 index f7e1ce38fb..0000000000 --- a/src/views/manualAccount/__tests__/manualAccountMenu-test.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react' - -import { screen, render } from 'src/utilities/testingLibrary' - -import { ManualAccountMenu } from 'src/views/manualAccount/ManualAccountMenu' - -const handleAccountTypeSelect = vi.fn() - -const accountMenuProps = { - handleAccountTypeSelect, - availableAccountTypes: [], -} - -describe('manualAccountMenu', () => { - it('renders manual account menu and clicks on a checking account', async () => { - const ref = React.createRef() - - const { user } = render() - - await user.click(await screen.findByRole('button', { name: 'Checking' })) - expect(handleAccountTypeSelect).toHaveBeenCalled() - }) -})