From f51b8aa33d7636b217025f134b149fddd95f534c Mon Sep 17 00:00:00 2001 From: Andrei Tarasov Date: Mon, 23 Dec 2024 18:08:11 +0100 Subject: [PATCH 1/8] refactor(DEV-13634): pass functional customization via new theme config --- packages/sdk-react/mui-styles.d.ts | 1 - .../sdk-react/src/core/theme/monite/index.ts | 8 ++++++ .../src/core/theme/mui-monite/index.ts | 2 +- packages/sdk-react/src/core/theme/types.ts | 25 ++++++------------- .../src/ui/table/TablePagination.tsx | 20 +-------------- .../sdk-react/src/utils/storybook-utils.tsx | 5 ++++ 6 files changed, 22 insertions(+), 39 deletions(-) diff --git a/packages/sdk-react/mui-styles.d.ts b/packages/sdk-react/mui-styles.d.ts index 0ae4b6e56..73cee29bc 100644 --- a/packages/sdk-react/mui-styles.d.ts +++ b/packages/sdk-react/mui-styles.d.ts @@ -8,7 +8,6 @@ import { type MonitePayableDetailsInfoProps, type MonitePayableStatusChipProps, type MonitePayableTableProps, - type MoniteTablePaginationProps, } from '@/core/theme/types'; import { type MoniteIconWrapperProps } from '@/ui/iconWrapper/IconWrapper'; import { diff --git a/packages/sdk-react/src/core/theme/monite/index.ts b/packages/sdk-react/src/core/theme/monite/index.ts index 32ad2ea76..6062c3c58 100644 --- a/packages/sdk-react/src/core/theme/monite/index.ts +++ b/packages/sdk-react/src/core/theme/monite/index.ts @@ -63,5 +63,13 @@ export const getTheme = (theme: ThemeConfig) => { lineHeight: theme.typography?.body2?.lineHeight || '20px', }, }, + + components: { + TablePagination: { + pageSizeOptions: theme.components?.TablePagination?.pageSizeOptions || [ + 15, 30, 100, + ], + }, + }, }; }; diff --git a/packages/sdk-react/src/core/theme/mui-monite/index.ts b/packages/sdk-react/src/core/theme/mui-monite/index.ts index 050b76ca4..935a6a080 100644 --- a/packages/sdk-react/src/core/theme/mui-monite/index.ts +++ b/packages/sdk-react/src/core/theme/mui-monite/index.ts @@ -714,7 +714,7 @@ export const getTheme = (theme: ThemeConfig): ThemeOptions => { }, MoniteTablePagination: { defaultProps: { - pageSizeOptions: [15, 30, 100], + pageSizeOptions: moniteTheme.components.TablePagination.pageSizeOptions, }, }, MuiDataGrid: { diff --git a/packages/sdk-react/src/core/theme/types.ts b/packages/sdk-react/src/core/theme/types.ts index 766492750..a6df88bfd 100644 --- a/packages/sdk-react/src/core/theme/types.ts +++ b/packages/sdk-react/src/core/theme/types.ts @@ -1,5 +1,5 @@ import { components, Services } from '@/api'; -import { ChipProps, SelectProps } from '@mui/material'; +import { ChipProps } from '@mui/material'; type TypographyStyle = { fontSize?: string | number; @@ -38,6 +38,12 @@ export type ThemeConfig = { body1?: TypographyStyle; body2?: TypographyStyle; }; + + components?: { + TablePagination?: { + pageSizeOptions?: number[]; + }; + }; }; export type MonitePalette = { @@ -93,23 +99,6 @@ export type MonitePalette = { divider: string; }; -interface MoniteTablePaginationRootSlotProps { - pageSizeOptions?: number[]; -} - -interface MoniteTablePaginationSlotProps { - slotProps?: { - pageSizeSelect?: Omit< - SelectProps, - 'value' | 'defaultValue' | 'aria-label' | 'ref' | 'components' - >; - }; -} - -export interface MoniteTablePaginationProps - extends MoniteTablePaginationSlotProps, - MoniteTablePaginationRootSlotProps {} - interface BaseChipProps { /** The variant of the Chip. */ variant?: ChipProps['variant']; diff --git a/packages/sdk-react/src/ui/table/TablePagination.tsx b/packages/sdk-react/src/ui/table/TablePagination.tsx index a0fb4b6a3..738357733 100644 --- a/packages/sdk-react/src/ui/table/TablePagination.tsx +++ b/packages/sdk-react/src/ui/table/TablePagination.tsx @@ -16,7 +16,6 @@ import { } from '@mui/material'; import { styled, useThemeProps } from '@mui/material/styles'; -// eslint-disable-next-line lingui/no-unlocalized-strings const componentName = 'MoniteTablePagination' as const; const DEFAULT_PAGE_SIZE = 10 as const; @@ -56,24 +55,7 @@ interface TablePaginationProps extends MoniteTablePaginationProps { * @param paginationModel The current pagination model. It should contain the current page and the page size. * @param nextPage The next page number. If undefined, the next page button will be disabled. * @param prevPage The previous page number. If undefined, the previous page button will be disabled. - * @param pageSizeOptions The page size options. If not provided, will be used from MUI theme or hidden if only one option is available. - * @example MUI theming - * // You can configure the component through MUI theming like this: - * createTheme(myTheme, { - * components: { - * MoniteTablePagination: { - * defaultProps: { - * // The default page size options - * pageSizeOptions: [5, 10, 15, 20], - * slotProps: { - * pageSizeSelect: { - * size: 'small', - * }, - * }, - * }, - * } - * } - * } + * @param pageSizeOptions The page size options. If not provided, will be used from theme or hidden if only one option is available. */ export const TablePagination = ({ onPaginationModelChange, diff --git a/packages/sdk-react/src/utils/storybook-utils.tsx b/packages/sdk-react/src/utils/storybook-utils.tsx index 05397eb45..1ab5757fb 100644 --- a/packages/sdk-react/src/utils/storybook-utils.tsx +++ b/packages/sdk-react/src/utils/storybook-utils.tsx @@ -74,6 +74,11 @@ const defaultThemeConfig: ThemeConfig = { text: '#401d6d', }, + components: { + TablePagination: { + pageSizeOptions: [10, 20, 100], + }, + }, }; export const GlobalStorybookDecorator = (props: { From f20a833fb0ca41e5d4d5106fc46fa5ab530cf521 Mon Sep 17 00:00:00 2001 From: Andrei Tarasov Date: Mon, 23 Dec 2024 18:57:25 +0100 Subject: [PATCH 2/8] refactor(DEV-13634): remove theme provider form iframe --- packages/sdk-drop-in/src/apps/MoniteIframeApp.tsx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/sdk-drop-in/src/apps/MoniteIframeApp.tsx b/packages/sdk-drop-in/src/apps/MoniteIframeApp.tsx index ec8031760..8235c08d1 100644 --- a/packages/sdk-drop-in/src/apps/MoniteIframeApp.tsx +++ b/packages/sdk-drop-in/src/apps/MoniteIframeApp.tsx @@ -7,15 +7,12 @@ import { moniteIframeAppComponents } from '@/lib/moniteIframeAppComponents'; import { useMoniteIframeAppSlots } from '@/lib/useIframeAppSlots'; import { css, Global } from '@emotion/react'; import { type APISchema } from '@monite/sdk-react'; -import { createTheme, CssBaseline, ThemeProvider } from '@mui/material'; +import { CssBaseline } from '@mui/material'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { EntityIdLoader, SDKDemoAPIProvider } from '@team-monite/sdk-demo'; import { DropInMoniteProvider } from '../lib/DropInMoniteProvider'; -// todo::implement google fonts support -// import { getFontFaceStyles } from './fontStyles.ts'; - export const MoniteIframeApp = () => { const queryClient = useMemo(() => new QueryClient(), []); @@ -76,7 +73,7 @@ const MoniteIframeAppComponent = ({ fetchToken, }} > - + <> - + ); }; From cba246312e55439ca07d541233af6ca0c75be325 Mon Sep 17 00:00:00 2001 From: Andrei Tarasov Date: Tue, 24 Dec 2024 18:36:49 +0100 Subject: [PATCH 3/8] feat(DEV-13634): add componentSettings and set page size for components --- packages/sdk-react/mui-styles.d.ts | 3 -- .../ApprovalPoliciesTable.tsx | 12 +++--- .../ApprovalRequestsTable.tsx | 14 +++--- .../CounterpartsTable/CounterpartsTable.tsx | 10 ++--- .../payables/PayablesTable/PayablesTable.tsx | 10 ++--- .../products/ProductsTable/ProductsTable.tsx | 11 ++--- .../CreditNotesTable/CreditNotesTable.tsx | 10 ++--- .../FinancedInvoicesTable.tsx | 10 ++--- .../InvoicesTable/InvoicesTable.tsx | 10 ++--- .../receivables/QuotesTable/QuotesTable.tsx | 10 ++--- .../components/tags/TagsTable/TagsTable.tsx | 10 ++--- .../UserRolesTable/UserRolesTable.tsx | 10 ++--- .../src/core/componentSettings/index.ts | 43 +++++++++++++++++++ .../src/core/context/MoniteContext.tsx | 8 +++- .../src/core/context/MoniteProvider.tsx | 40 ++++++++++++++++- .../sdk-react/src/core/theme/monite/index.ts | 8 ---- .../src/core/theme/mui-monite/index.ts | 5 --- packages/sdk-react/src/core/theme/types.ts | 6 --- .../src/ui/table/TablePagination.tsx | 17 +------- .../sdk-react/src/utils/storybook-utils.tsx | 28 +++++++++--- 20 files changed, 164 insertions(+), 111 deletions(-) create mode 100644 packages/sdk-react/src/core/componentSettings/index.ts diff --git a/packages/sdk-react/mui-styles.d.ts b/packages/sdk-react/mui-styles.d.ts index 73cee29bc..700a760df 100644 --- a/packages/sdk-react/mui-styles.d.ts +++ b/packages/sdk-react/mui-styles.d.ts @@ -38,7 +38,6 @@ declare module '@mui/material/styles' { MoniteInvoiceStatusChip: 'root'; MonitePayableStatusChip: 'root'; MoniteApprovalRequestStatusChip: 'root'; - MoniteTablePagination: 'root' | 'menu'; MonitePayableDetailsInfo: 'never'; MoniteInvoiceRecurrenceStatusChip: 'root'; MoniteInvoiceRecurrenceIterationStatusChip: 'root'; @@ -55,7 +54,6 @@ declare module '@mui/material/styles' { MoniteInvoiceStatusChip: Partial; MonitePayableStatusChip: Partial; MoniteApprovalRequestStatusChip: Partial; - MoniteTablePagination: Partial; MonitePayableDetailsInfo: Partial; MoniteInvoiceRecurrenceStatusChip: Partial; MoniteInvoiceRecurrenceIterationStatusChip: Partial; @@ -73,7 +71,6 @@ declare module '@mui/material/styles' { MoniteInvoiceStatusChip?: ComponentType<'MoniteInvoiceStatusChip'>; MonitePayableStatusChip?: ComponentType<'MonitePayableStatusChip'>; MoniteApprovalRequestStatusChip?: ComponentType<'MoniteApprovalRequestStatusChip'>; - MoniteTablePagination?: ComponentType<'MoniteTablePagination'>; MonitePayableDetailsInfo?: ComponentType<'MonitePayableDetailsInfo'>; MonitePayableTable?: ComponentType<'MonitePayableTable'>; MoniteInvoiceRecurrenceStatusChip?: ComponentType<'MoniteInvoiceRecurrenceStatusChip'>; diff --git a/packages/sdk-react/src/components/approvalPolicies/ApprovalPoliciesTable/ApprovalPoliciesTable.tsx b/packages/sdk-react/src/components/approvalPolicies/ApprovalPoliciesTable/ApprovalPoliciesTable.tsx index d1d89f81d..4cf7ed2f2 100644 --- a/packages/sdk-react/src/components/approvalPolicies/ApprovalPoliciesTable/ApprovalPoliciesTable.tsx +++ b/packages/sdk-react/src/components/approvalPolicies/ApprovalPoliciesTable/ApprovalPoliciesTable.tsx @@ -9,10 +9,7 @@ import { useMoniteContext } from '@/core/context/MoniteContext'; import { MoniteScopedProviders } from '@/core/context/MoniteScopedProviders'; import { DataGridEmptyState } from '@/ui/DataGridEmptyState'; import { GetNoRowsOverlay } from '@/ui/DataGridEmptyState/GetNoRowsOverlay'; -import { - TablePagination, - useTablePaginationThemeDefaultPageSize, -} from '@/ui/table/TablePagination'; +import { TablePagination } from '@/ui/table/TablePagination'; import { hasSelectedText } from '@/utils/text-selection'; import { t } from '@lingui/macro'; import { useLingui } from '@lingui/react'; @@ -98,14 +95,14 @@ const ApprovalPoliciesTableBase = ({ onCreateClick, }: ApprovalPoliciesTableProps) => { const { i18n } = useLingui(); + const { api, locale, componentSettings } = useMoniteContext(); const [currentPaginationToken, setCurrentPaginationToken] = useState< string | null >(null); const [pageSize, setPageSize] = useState( - useTablePaginationThemeDefaultPageSize() + componentSettings.approvalPolicies.pageSizeOptions[0] ); const [currentFilters, setCurrentFilters] = useState({}); - const { api, locale } = useMoniteContext(); const { data: approvalPolicies, @@ -277,6 +274,9 @@ const ApprovalPoliciesTableBase = ({ slots={{ pagination: () => ( { - const { api, locale } = useMoniteContext(); + const { api, locale, componentSettings } = useMoniteContext(); const { i18n } = useLingui(); const { formatCurrencyToDisplay } = useCurrencies(); const { data: user } = useEntityUserByAuthToken(); @@ -108,7 +105,7 @@ const ApprovalRequestsTableBase = ({ string | null >(null); const [pageSize, setPageSize] = useState( - useTablePaginationThemeDefaultPageSize() + componentSettings.approvalRequests.pageSizeOptions[0] ); const [currentFilter, setCurrentFilter] = useState({}); @@ -290,6 +287,8 @@ const ApprovalRequestsTableBase = ({ ); } + console.log(componentSettings); + return ( ( { const { i18n } = useLingui(); + const { componentSettings } = useMoniteContext(); const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false); const [selectedCounterpart, setSelectedCounterpart] = useState< CounterpartResponse | undefined @@ -130,7 +129,7 @@ const CounterpartsTableBase = ({ string | null >(null); const [pageSize, setPageSize] = useState( - useTablePaginationThemeDefaultPageSize() + componentSettings.counterparts.pageSizeOptions[0] ); const [currentSort] = useState(null); const [currentFilter, setCurrentFilter] = useState({}); @@ -415,6 +414,7 @@ const CounterpartsTableBase = ({ slots={{ pagination: () => ( { const { i18n } = useLingui(); - const { api, locale, queryClient } = useMoniteContext(); + const { api, locale, queryClient, componentSettings } = useMoniteContext(); const { isShowingSummaryCards, fieldOrder, summaryCardFilters } = usePayableTableThemeProps(inProps); @@ -164,7 +161,7 @@ const PayablesTableBase = ({ string | null >(null); const [pageSize, setPageSize] = useState( - useTablePaginationThemeDefaultPageSize() + componentSettings.payables.pageSizeOptions[0] ); const [sortModel, setSortModel] = useState({ field: 'created_at', @@ -480,6 +477,7 @@ const PayablesTableBase = ({ slots={{ pagination: () => ( { const { i18n } = useLingui(); + const { api, componentSettings } = useMoniteContext(); const [currentPaginationToken, setCurrentPaginationToken] = useState< string | null >(null); const [pageSize, setPageSize] = useState( - useTablePaginationThemeDefaultPageSize() + componentSettings.products.pageSizeOptions[0] ); const [currentFilter, setCurrentFilter] = useState({}); const [sortModel, setSortModel] = useState< @@ -144,8 +142,6 @@ const ProductsTableBase = ({ entityUserId: user?.id, }); - const { api } = useMoniteContext(); - const { data: products, isLoading, @@ -312,6 +308,7 @@ const ProductsTableBase = ({ slots={{ pagination: () => ( { const { i18n } = useLingui(); - const { locale } = useMoniteContext(); + const { locale, componentSettings } = useMoniteContext(); const [paginationToken, setPaginationToken] = useState( undefined ); const [pageSize, setPageSize] = useState( - useTablePaginationThemeDefaultPageSize() + componentSettings.receivables.pageSizeOptions[0] ); const [sortModel, setSortModel] = useState({ @@ -258,6 +255,7 @@ const CreditNotesTableBase = ({ slots={{ pagination: () => ( { const { i18n } = useLingui(); - const { locale } = useMoniteContext(); + const { locale, componentSettings } = useMoniteContext(); const [paginationToken, setPaginationToken] = useState( undefined ); const [pageSize, setPageSize] = useState( - useTablePaginationThemeDefaultPageSize() + componentSettings.receivables.pageSizeOptions[0] ); const [sortModel, setSortModel] = useState({ @@ -250,6 +247,7 @@ const FinancedInvoicesTableBase = ({ slots={{ pagination: () => ( { - const { locale } = useMoniteContext(); + const { locale, componentSettings } = useMoniteContext(); const { i18n } = useLingui(); const [paginationToken, setPaginationToken] = useState( @@ -101,7 +98,7 @@ const InvoicesTableBase = ({ ); const [pageSize, setPageSize] = useState( - useTablePaginationThemeDefaultPageSize() + componentSettings.receivables.pageSizeOptions[0] ); const [sortModel, setSortModel] = useState({ @@ -340,6 +337,7 @@ const InvoicesTableBase = ({ slots={{ pagination: () => ( { const { i18n } = useLingui(); - const { locale } = useMoniteContext(); + const { locale, componentSettings } = useMoniteContext(); const [paginationToken, setPaginationToken] = useState( undefined ); const [pageSize, setPageSize] = useState( - useTablePaginationThemeDefaultPageSize() + componentSettings.receivables.pageSizeOptions[0] ); const [sortModel, setSortModel] = useState({ @@ -272,6 +269,7 @@ const QuotesTableBase = ({ slots={{ pagination: () => ( { const { i18n } = useLingui(); + const { api, locale, componentSettings } = useMoniteContext(); const [currentPaginationToken, setCurrentPaginationToken] = useState< string | null >(null); const [pageSize, setPageSize] = useState( - useTablePaginationThemeDefaultPageSize() + componentSettings.tags.pageSizeOptions[0] ); const [selectedTag, setSelectedTag] = useState< components['schemas']['TagReadSchema'] | undefined @@ -81,7 +79,6 @@ const TagsTableBase = ({ const closeDeleteModal = useCallback(() => { setDeleteModalOpened(false); }, []); - const { api, locale } = useMoniteContext(); const { data: tags, @@ -240,6 +237,7 @@ const TagsTableBase = ({ slots={{ pagination: () => ( { const { i18n } = useLingui(); - const { api, locale } = useMoniteContext(); + const { api, locale, componentSettings } = useMoniteContext(); const [currentPaginationToken, setCurrentPaginationToken] = useState< string | null >(null); const [pageSize, setPageSize] = useState( - useTablePaginationThemeDefaultPageSize() + componentSettings.userRoles.pageSizeOptions[0] ); const [currentFilter, setCurrentFilter] = useState({}); const [sortModel, setSortModel] = useState({ @@ -249,6 +246,7 @@ const UserRolesTableBase = ({ slots={{ pagination: () => ( +) => ({ + approvalPolicies: { + pageSizeOptions: + componentSettings?.approvalPolicies?.pageSizeOptions || + defaultPageSizeOptions, + }, + approvalRequests: { + pageSizeOptions: + componentSettings?.approvalRequests?.pageSizeOptions || + defaultPageSizeOptions, + }, + counterparts: { + pageSizeOptions: + componentSettings?.counterparts?.pageSizeOptions || + defaultPageSizeOptions, + }, + payables: { + pageSizeOptions: + componentSettings?.payables?.pageSizeOptions || defaultPageSizeOptions, + }, + products: { + pageSizeOptions: + componentSettings?.products?.pageSizeOptions || defaultPageSizeOptions, + }, + receivables: { + pageSizeOptions: + componentSettings?.receivables?.pageSizeOptions || defaultPageSizeOptions, + }, + tags: { + pageSizeOptions: + componentSettings?.tags?.pageSizeOptions || defaultPageSizeOptions, + }, + userRoles: { + pageSizeOptions: + componentSettings?.userRoles?.pageSizeOptions || defaultPageSizeOptions, + }, +}); diff --git a/packages/sdk-react/src/core/context/MoniteContext.tsx b/packages/sdk-react/src/core/context/MoniteContext.tsx index 1be3e47e3..414490feb 100644 --- a/packages/sdk-react/src/core/context/MoniteContext.tsx +++ b/packages/sdk-react/src/core/context/MoniteContext.tsx @@ -7,6 +7,7 @@ import { } from 'react'; import { createAPIClient, CreateMoniteAPIClientResult } from '@/api/client'; +import { getDefaultComponentSettings } from '@/core/componentSettings'; import { createQueryClient } from '@/core/context/createQueryClient'; import { MoniteQraftContext } from '@/core/context/MoniteAPIProvider'; import { @@ -25,7 +26,7 @@ import type { QueryClient } from '@tanstack/react-query'; import type { Locale as DateFnsLocale } from 'date-fns'; -import { MoniteSettings } from './MoniteProvider'; +import { MoniteSettings, ComponentSettings } from './MoniteProvider'; interface MoniteContextBaseValue { locale: MoniteLocaleWithRequired; @@ -42,6 +43,7 @@ export interface MoniteContextValue queryClient: QueryClient; apiUrl: string; theme: Theme; + componentSettings: ComponentSettings; fetchToken: () => Promise<{ access_token: string; expires_in: number; @@ -73,6 +75,7 @@ interface MoniteContextProviderProps { monite: MoniteSettings; locale: Partial | undefined; theme: ThemeConfig | undefined; + componentSettings: Partial | undefined; children: ReactNode; } @@ -106,6 +109,7 @@ interface ContextProviderProps extends MoniteContextBaseValue { monite: MoniteSettings; children: ReactNode; theme: ThemeConfig | undefined; + componentSettings?: Partial; } const ContextProvider = ({ @@ -114,6 +118,7 @@ const ContextProvider = ({ i18n, dateFnsLocale, theme: userTheme, + componentSettings, children, }: ContextProviderProps) => { const { entityId, apiUrl, fetchToken } = monite; @@ -170,6 +175,7 @@ const ContextProvider = ({ environment, entityId, theme, + componentSettings: getDefaultComponentSettings(componentSettings), queryClient, sentryHub, i18n, diff --git a/packages/sdk-react/src/core/context/MoniteProvider.tsx b/packages/sdk-react/src/core/context/MoniteProvider.tsx index 75d03eb38..a7e1351bc 100644 --- a/packages/sdk-react/src/core/context/MoniteProvider.tsx +++ b/packages/sdk-react/src/core/context/MoniteProvider.tsx @@ -20,6 +20,33 @@ export interface MoniteSettings { fetchToken: () => Promise; } +export interface ComponentSettings { + approvalPolicies: { + pageSizeOptions: number[]; + }; + approvalRequests: { + pageSizeOptions: number[]; + }; + counterparts: { + pageSizeOptions: number[]; + }; + payables: { + pageSizeOptions: number[]; + }; + products: { + pageSizeOptions: number[]; + }; + receivables: { + pageSizeOptions: number[]; + }; + tags: { + pageSizeOptions: number[]; + }; + userRoles: { + pageSizeOptions: number[]; + }; +} + export interface MoniteProviderProps { children?: ReactNode; @@ -37,16 +64,27 @@ export interface MoniteProviderProps { * of all Widgets provided. */ locale?: MoniteLocale; + + /** + * Component settings + */ + componentSettings?: Partial; } export const MoniteProvider = ({ monite, theme, + componentSettings, children, locale, }: MoniteProviderProps) => { return ( - + diff --git a/packages/sdk-react/src/core/theme/monite/index.ts b/packages/sdk-react/src/core/theme/monite/index.ts index 6062c3c58..32ad2ea76 100644 --- a/packages/sdk-react/src/core/theme/monite/index.ts +++ b/packages/sdk-react/src/core/theme/monite/index.ts @@ -63,13 +63,5 @@ export const getTheme = (theme: ThemeConfig) => { lineHeight: theme.typography?.body2?.lineHeight || '20px', }, }, - - components: { - TablePagination: { - pageSizeOptions: theme.components?.TablePagination?.pageSizeOptions || [ - 15, 30, 100, - ], - }, - }, }; }; diff --git a/packages/sdk-react/src/core/theme/mui-monite/index.ts b/packages/sdk-react/src/core/theme/mui-monite/index.ts index 935a6a080..a3a1266ae 100644 --- a/packages/sdk-react/src/core/theme/mui-monite/index.ts +++ b/packages/sdk-react/src/core/theme/mui-monite/index.ts @@ -712,11 +712,6 @@ export const getTheme = (theme: ThemeConfig): ThemeOptions => { }, }, }, - MoniteTablePagination: { - defaultProps: { - pageSizeOptions: moniteTheme.components.TablePagination.pageSizeOptions, - }, - }, MuiDataGrid: { defaultProps: { columnHeaderHeight: 55, diff --git a/packages/sdk-react/src/core/theme/types.ts b/packages/sdk-react/src/core/theme/types.ts index a6df88bfd..bebb24a79 100644 --- a/packages/sdk-react/src/core/theme/types.ts +++ b/packages/sdk-react/src/core/theme/types.ts @@ -38,12 +38,6 @@ export type ThemeConfig = { body1?: TypographyStyle; body2?: TypographyStyle; }; - - components?: { - TablePagination?: { - pageSizeOptions?: number[]; - }; - }; }; export type MonitePalette = { diff --git a/packages/sdk-react/src/ui/table/TablePagination.tsx b/packages/sdk-react/src/ui/table/TablePagination.tsx index 738357733..6860bad24 100644 --- a/packages/sdk-react/src/ui/table/TablePagination.tsx +++ b/packages/sdk-react/src/ui/table/TablePagination.tsx @@ -73,12 +73,10 @@ export const TablePagination = ({ name: componentName, }); - const defaultPageSize = useTablePaginationThemeDefaultPageSize(); - const pageSize = 'pageSize' in paginationModel ? paginationModel.pageSize - : pageSizeOptions?.[0] ?? defaultPageSize; + : pageSizeOptions?.[0] ?? DEFAULT_PAGE_SIZE; const hasPageSizeSelect = pageSizeOptions && pageSizeOptions.length > 1; @@ -179,16 +177,3 @@ const StyledSelect = styled( shouldForwardProp: () => true, } )({}); - -/** - * Returns the default `pageSize` from the Theme. - * If not specified, it will return a fallback value. - */ -export const useTablePaginationThemeDefaultPageSize = () => { - const { pageSizeOptions } = useThemeProps({ - props: {} as MoniteTablePaginationRootSlotProps, - name: componentName, - }); - - return pageSizeOptions?.length ? pageSizeOptions[0] : DEFAULT_PAGE_SIZE; -}; diff --git a/packages/sdk-react/src/utils/storybook-utils.tsx b/packages/sdk-react/src/utils/storybook-utils.tsx index 1ab5757fb..e132b47f9 100644 --- a/packages/sdk-react/src/utils/storybook-utils.tsx +++ b/packages/sdk-react/src/utils/storybook-utils.tsx @@ -74,11 +74,6 @@ const defaultThemeConfig: ThemeConfig = { text: '#401d6d', }, - components: { - TablePagination: { - pageSizeOptions: [10, 20, 100], - }, - }, }; export const GlobalStorybookDecorator = (props: { @@ -121,6 +116,29 @@ export const GlobalStorybookDecorator = (props: { {props.children} From a772ec5af5c5b3f6ae87efbe647b20db81b37833 Mon Sep 17 00:00:00 2001 From: Andrei Tarasov Date: Fri, 27 Dec 2024 10:40:29 +0100 Subject: [PATCH 4/8] feat(DEV-13634): update tests and utils for the new provider config --- .../src/themes/monite.ts | 5 - .../src/ui/table/TablePagination.stories.tsx | 38 +----- .../src/ui/table/TablePagination.test.tsx | 114 ++---------------- .../sdk-react/src/utils/storybook-utils.tsx | 55 +++++---- packages/sdk-react/src/utils/test-utils.tsx | 4 + 5 files changed, 51 insertions(+), 165 deletions(-) diff --git a/examples/with-nextjs-and-clerk-auth/src/themes/monite.ts b/examples/with-nextjs-and-clerk-auth/src/themes/monite.ts index d5af24490..852754462 100644 --- a/examples/with-nextjs-and-clerk-auth/src/themes/monite.ts +++ b/examples/with-nextjs-and-clerk-auth/src/themes/monite.ts @@ -806,11 +806,6 @@ const defaultMoniteComponents: Components> = { }, }, }, - MoniteTablePagination: { - defaultProps: { - pageSizeOptions: [15, 30, 100], - }, - }, MuiDataGrid: { defaultProps: { columnHeaderHeight: 55, diff --git a/packages/sdk-react/src/ui/table/TablePagination.stories.tsx b/packages/sdk-react/src/ui/table/TablePagination.stories.tsx index 33b98800a..fefb14bfc 100644 --- a/packages/sdk-react/src/ui/table/TablePagination.stories.tsx +++ b/packages/sdk-react/src/ui/table/TablePagination.stories.tsx @@ -1,5 +1,3 @@ -import { ExtendThemeProvider } from '@/utils/ExtendThemeProvider'; -import { Alert } from '@mui/material'; import type { Meta, StoryObj } from '@storybook/react'; import { TablePagination as TablePaginationComponent } from './TablePagination'; @@ -27,17 +25,14 @@ export const TablePaginationDefault: Story = {
- - {''} could be customized through MUI - theming - ), }; -export const TablePaginationThemed: Story = { - name: 'slots customization', +export const TablePaginationCustomized: Story = { + name: 'props customization', args: { + pageSizeOptions: [55, 10, 155, 200], paginationModel: { pageSize: 10, page: 1, @@ -48,30 +43,9 @@ export const TablePaginationThemed: Story = { }, render: (args) => (
- -
- -
-
- - {''} could be customized through MUI - theming - +
+ +
), }; diff --git a/packages/sdk-react/src/ui/table/TablePagination.test.tsx b/packages/sdk-react/src/ui/table/TablePagination.test.tsx index 3bd33a5e1..adbdba6fd 100644 --- a/packages/sdk-react/src/ui/table/TablePagination.test.tsx +++ b/packages/sdk-react/src/ui/table/TablePagination.test.tsx @@ -1,4 +1,3 @@ -import { ExtendThemeProvider } from '@/utils/ExtendThemeProvider'; import { renderWithClient } from '@/utils/test-utils'; import { screen, fireEvent, act, within } from '@testing-library/react'; @@ -91,27 +90,16 @@ describe('TablePagination', () => { it('does not show page size Select if there are less than two options', async () => { renderWithClient( - - {}} - /> - + onPaginationModelChange={() => {}} + /> ); expect( @@ -140,88 +128,4 @@ describe('TablePagination', () => { }) ).not.toBeInTheDocument(); }); - - it('supports custom `pageSizeOptions` via MUI theming', async () => { - renderWithClient( - - {}} - /> - - ); - - fireEvent.mouseDown(screen.getByRole('combobox')); - - const dropdown = screen.getByRole('listbox', { name: '' }); - const { findByRole } = within(dropdown); - - expect( - await findByRole('option', { - name: '111', - }) - ).toBeInTheDocument(); - - expect( - await findByRole('option', { - name: '222', - }) - ).toBeInTheDocument(); - - expect( - await findByRole('option', { - name: '333', - }) - ).toBeInTheDocument(); - }); - - it('supports custom `slotProps` via MUI theming', async () => { - renderWithClient( - - {}} - /> - - ); - - const element = screen.getByRole('combobox'); - - expect(element.closest('.test-class-name')).toBeInTheDocument(); - }); }); diff --git a/packages/sdk-react/src/utils/storybook-utils.tsx b/packages/sdk-react/src/utils/storybook-utils.tsx index e132b47f9..c8907c282 100644 --- a/packages/sdk-react/src/utils/storybook-utils.tsx +++ b/packages/sdk-react/src/utils/storybook-utils.tsx @@ -3,6 +3,7 @@ import { ReactNode, useMemo } from 'react'; import { apiVersion } from '@/api/api-version'; import { useMoniteContext } from '@/core/context/MoniteContext'; import { MoniteProvider, MoniteSettings } from '@/core/context/MoniteProvider'; +import { ComponentSettings } from '@/core/context/MoniteProvider'; import { messages as enLocaleMessages } from '@/core/i18n/locales/en/messages'; import { ThemeConfig } from '@/core/theme/types'; import { createThemeWithDefaults } from '@/core/utils/createThemeWithDefaults'; @@ -76,6 +77,36 @@ const defaultThemeConfig: ThemeConfig = { }, }; +/** + * Default component settings for storybook stories. + * + * These settings are used to configure default functionality of the SDK components in storybook stories. + */ +const defaultPageSizeOptions = [10, 30, 100]; +const defaultComponentSettings: Partial = { + approvalRequests: { + pageSizeOptions: defaultPageSizeOptions, + }, + approvalPolicies: { + pageSizeOptions: defaultPageSizeOptions, + }, + counterparts: { + pageSizeOptions: defaultPageSizeOptions, + }, + products: { + pageSizeOptions: defaultPageSizeOptions, + }, + receivables: { + pageSizeOptions: defaultPageSizeOptions, + }, + tags: { + pageSizeOptions: defaultPageSizeOptions, + }, + userRoles: { + pageSizeOptions: defaultPageSizeOptions, + }, +}; + export const GlobalStorybookDecorator = (props: { children: ReactNode; theme?: ThemeConfig; @@ -116,29 +147,7 @@ export const GlobalStorybookDecorator = (props: { {props.children} diff --git a/packages/sdk-react/src/utils/test-utils.tsx b/packages/sdk-react/src/utils/test-utils.tsx index 11bc906fe..caab620a0 100644 --- a/packages/sdk-react/src/utils/test-utils.tsx +++ b/packages/sdk-react/src/utils/test-utils.tsx @@ -1,6 +1,7 @@ import { ReactElement, ReactNode, useEffect } from 'react'; import { createAPIClient } from '@/api/client'; +import { getDefaultComponentSettings } from '@/core/componentSettings'; import { MoniteAPIProvider, MoniteQraftContext, @@ -116,6 +117,9 @@ export const Provider = ({ sentryHub, queryClient: client, theme: createThemeWithDefaults(i18n, moniteProviderProps?.theme), + componentSettings: getDefaultComponentSettings( + moniteProviderProps?.componentSettings + ), dateFnsLocale, apiUrl: moniteSettings.apiUrl || 'https://api.sandbox.monite.com/v1', fetchToken: moniteSettings.fetchToken, From a5db162271bedc5d714aed0d0000a332b140408c Mon Sep 17 00:00:00 2001 From: Andrei Tarasov Date: Fri, 27 Dec 2024 11:52:15 +0100 Subject: [PATCH 5/8] feat(DEV-13634): update default page size value --- packages/sdk-react/src/core/componentSettings/index.ts | 2 +- packages/sdk-react/src/utils/storybook-utils.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/sdk-react/src/core/componentSettings/index.ts b/packages/sdk-react/src/core/componentSettings/index.ts index 3428abc11..30d02e77a 100644 --- a/packages/sdk-react/src/core/componentSettings/index.ts +++ b/packages/sdk-react/src/core/componentSettings/index.ts @@ -1,6 +1,6 @@ import { ComponentSettings } from '@/core/context/MoniteProvider'; -const defaultPageSizeOptions = [10, 30, 100]; +const defaultPageSizeOptions = [15, 30, 100]; export const getDefaultComponentSettings = ( componentSettings?: Partial diff --git a/packages/sdk-react/src/utils/storybook-utils.tsx b/packages/sdk-react/src/utils/storybook-utils.tsx index c8907c282..031eff6e8 100644 --- a/packages/sdk-react/src/utils/storybook-utils.tsx +++ b/packages/sdk-react/src/utils/storybook-utils.tsx @@ -82,7 +82,7 @@ const defaultThemeConfig: ThemeConfig = { * * These settings are used to configure default functionality of the SDK components in storybook stories. */ -const defaultPageSizeOptions = [10, 30, 100]; +const defaultPageSizeOptions = [15, 30, 100]; const defaultComponentSettings: Partial = { approvalRequests: { pageSizeOptions: defaultPageSizeOptions, From 9c06fcf6fa3885c5ddbe20316441d55e68160b15 Mon Sep 17 00:00:00 2001 From: Andrei Tarasov Date: Fri, 27 Dec 2024 15:01:36 +0100 Subject: [PATCH 6/8] feat(DEV-13634): move icon wrapper from theme to component settings --- packages/sdk-react/mui-styles.d.ts | 3 -- .../src/core/componentSettings/index.ts | 40 ++++++++++++++++++- .../src/core/context/MoniteContext.tsx | 3 +- .../src/core/context/MoniteProvider.tsx | 28 +------------ .../src/core/theme/mui-monite/index.ts | 5 --- .../src/ui/iconWrapper/IconWrapper.tsx | 17 ++++---- .../sdk-react/src/utils/storybook-utils.tsx | 9 ++++- 7 files changed, 58 insertions(+), 47 deletions(-) diff --git a/packages/sdk-react/mui-styles.d.ts b/packages/sdk-react/mui-styles.d.ts index 700a760df..7f5af83bd 100644 --- a/packages/sdk-react/mui-styles.d.ts +++ b/packages/sdk-react/mui-styles.d.ts @@ -9,7 +9,6 @@ import { type MonitePayableStatusChipProps, type MonitePayableTableProps, } from '@/core/theme/types'; -import { type MoniteIconWrapperProps } from '@/ui/iconWrapper/IconWrapper'; import { ComponentsOverrides, ComponentsPropsList, @@ -61,7 +60,6 @@ declare module '@mui/material/styles' { MonitePayableTable: Partial; MoniteApprovalStatusChip: Partial; MoniteReceivablesTable: Partial; - MoniteIconWrapper: Partial; } /** @@ -78,6 +76,5 @@ declare module '@mui/material/styles' { MoniteCounterpartStatusChip?: ComponentType<'MoniteCounterpartStatusChip'>; MoniteApprovalStatusChip?: ComponentType<'MoniteApprovalStatusChip'>; MoniteReceivablesTable?: ComponentType<'MoniteReceivablesTable'>; - MoniteIconWrapper?: ComponentType<'MoniteIconWrapper'>; } } diff --git a/packages/sdk-react/src/core/componentSettings/index.ts b/packages/sdk-react/src/core/componentSettings/index.ts index 30d02e77a..2cdf65664 100644 --- a/packages/sdk-react/src/core/componentSettings/index.ts +++ b/packages/sdk-react/src/core/componentSettings/index.ts @@ -1,10 +1,48 @@ -import { ComponentSettings } from '@/core/context/MoniteProvider'; +import type { MoniteIconWrapperProps } from '@/ui/iconWrapper'; + +export interface ComponentSettings { + general: { + iconWrapper: Partial; + }; + approvalPolicies: { + pageSizeOptions: number[]; + }; + approvalRequests: { + pageSizeOptions: number[]; + }; + counterparts: { + pageSizeOptions: number[]; + }; + payables: { + pageSizeOptions: number[]; + }; + products: { + pageSizeOptions: number[]; + }; + receivables: { + pageSizeOptions: number[]; + }; + tags: { + pageSizeOptions: number[]; + }; + userRoles: { + pageSizeOptions: number[]; + }; +} const defaultPageSizeOptions = [15, 30, 100]; export const getDefaultComponentSettings = ( componentSettings?: Partial ) => ({ + general: { + iconWrapper: { + defaultProps: { + showCloseIcon: true, + }, + ...componentSettings?.general?.iconWrapper, + }, + }, approvalPolicies: { pageSizeOptions: componentSettings?.approvalPolicies?.pageSizeOptions || diff --git a/packages/sdk-react/src/core/context/MoniteContext.tsx b/packages/sdk-react/src/core/context/MoniteContext.tsx index 414490feb..c73bf5219 100644 --- a/packages/sdk-react/src/core/context/MoniteContext.tsx +++ b/packages/sdk-react/src/core/context/MoniteContext.tsx @@ -8,6 +8,7 @@ import { import { createAPIClient, CreateMoniteAPIClientResult } from '@/api/client'; import { getDefaultComponentSettings } from '@/core/componentSettings'; +import type { ComponentSettings } from '@/core/componentSettings'; import { createQueryClient } from '@/core/context/createQueryClient'; import { MoniteQraftContext } from '@/core/context/MoniteAPIProvider'; import { @@ -26,7 +27,7 @@ import type { QueryClient } from '@tanstack/react-query'; import type { Locale as DateFnsLocale } from 'date-fns'; -import { MoniteSettings, ComponentSettings } from './MoniteProvider'; +import { MoniteSettings } from './MoniteProvider'; interface MoniteContextBaseValue { locale: MoniteLocaleWithRequired; diff --git a/packages/sdk-react/src/core/context/MoniteProvider.tsx b/packages/sdk-react/src/core/context/MoniteProvider.tsx index a7e1351bc..4be642cbf 100644 --- a/packages/sdk-react/src/core/context/MoniteProvider.tsx +++ b/packages/sdk-react/src/core/context/MoniteProvider.tsx @@ -2,6 +2,7 @@ import { ReactNode } from 'react'; import { components } from '@/api'; import { ContainerCssBaseline } from '@/components/ContainerCssBaseline'; +import type { ComponentSettings } from '@/core/componentSettings'; import { EmotionCacheProvider } from '@/core/context/EmotionCacheProvider'; import { MoniteAPIProvider, @@ -20,33 +21,6 @@ export interface MoniteSettings { fetchToken: () => Promise; } -export interface ComponentSettings { - approvalPolicies: { - pageSizeOptions: number[]; - }; - approvalRequests: { - pageSizeOptions: number[]; - }; - counterparts: { - pageSizeOptions: number[]; - }; - payables: { - pageSizeOptions: number[]; - }; - products: { - pageSizeOptions: number[]; - }; - receivables: { - pageSizeOptions: number[]; - }; - tags: { - pageSizeOptions: number[]; - }; - userRoles: { - pageSizeOptions: number[]; - }; -} - export interface MoniteProviderProps { children?: ReactNode; diff --git a/packages/sdk-react/src/core/theme/mui-monite/index.ts b/packages/sdk-react/src/core/theme/mui-monite/index.ts index a3a1266ae..e2044ba79 100644 --- a/packages/sdk-react/src/core/theme/mui-monite/index.ts +++ b/packages/sdk-react/src/core/theme/mui-monite/index.ts @@ -983,11 +983,6 @@ export const getTheme = (theme: ThemeConfig): ThemeOptions => { }, }, }, - MoniteIconWrapper: { - defaultProps: { - showCloseIcon: true, - }, - }, MonitePayableTable: { defaultProps: { isShowingSummaryCards: true, diff --git a/packages/sdk-react/src/ui/iconWrapper/IconWrapper.tsx b/packages/sdk-react/src/ui/iconWrapper/IconWrapper.tsx index 9ff586b34..34c931502 100644 --- a/packages/sdk-react/src/ui/iconWrapper/IconWrapper.tsx +++ b/packages/sdk-react/src/ui/iconWrapper/IconWrapper.tsx @@ -7,9 +7,10 @@ import React, { FocusEvent, } from 'react'; +import { useMoniteContext } from '@/core/context/MoniteContext'; import ArrowBackIcon from '@mui/icons-material/ArrowBack'; import CloseIcon from '@mui/icons-material/Close'; -import { SxProps, useThemeProps } from '@mui/material'; +import { SxProps } from '@mui/material'; import IconButton, { IconButtonProps } from '@mui/material/IconButton'; import { Theme } from '@mui/material/styles'; import Tooltip from '@mui/material/Tooltip'; @@ -94,20 +95,18 @@ export const IconWrapper = forwardRef< }, ref ) => { - const themeProps = useThemeProps({ - props: { icon, fallbackIcon }, - name: 'MoniteIconWrapper', - }); + const { componentSettings } = useMoniteContext(); + const providerProps = componentSettings?.general?.iconWrapper; const [displayIcon, setDisplayIcon] = useState( - themeProps.icon || themeProps.fallbackIcon || + providerProps.icon || providerProps.fallbackIcon || ); useEffect(() => { setDisplayIcon( - themeProps.icon || themeProps.fallbackIcon || + providerProps.icon || providerProps.fallbackIcon || ); - }, [themeProps.icon, themeProps.fallbackIcon]); + }, [providerProps.icon, providerProps.fallbackIcon]); const handleMouseEnter = (event: MouseEvent) => { onHover?.(event); @@ -118,7 +117,7 @@ export const IconWrapper = forwardRef< const handleMouseLeave = () => { setDisplayIcon( - themeProps.icon || themeProps.fallbackIcon || + providerProps.icon || providerProps.fallbackIcon || ); }; diff --git a/packages/sdk-react/src/utils/storybook-utils.tsx b/packages/sdk-react/src/utils/storybook-utils.tsx index 031eff6e8..6e1c836b0 100644 --- a/packages/sdk-react/src/utils/storybook-utils.tsx +++ b/packages/sdk-react/src/utils/storybook-utils.tsx @@ -1,15 +1,16 @@ import { ReactNode, useMemo } from 'react'; import { apiVersion } from '@/api/api-version'; +import { ComponentSettings } from '@/core/componentSettings'; import { useMoniteContext } from '@/core/context/MoniteContext'; import { MoniteProvider, MoniteSettings } from '@/core/context/MoniteProvider'; -import { ComponentSettings } from '@/core/context/MoniteProvider'; import { messages as enLocaleMessages } from '@/core/i18n/locales/en/messages'; import { ThemeConfig } from '@/core/theme/types'; import { createThemeWithDefaults } from '@/core/utils/createThemeWithDefaults'; import { entityIds } from '@/mocks/entities'; import { setupI18n } from '@lingui/core'; import { I18nProvider } from '@lingui/react'; +import ArrowBackIcon from '@mui/icons-material/ArrowBack'; import { ThemeProvider } from '@mui/material'; // eslint-disable-next-line import/no-extraneous-dependencies import { deepmerge } from '@mui/utils'; @@ -84,6 +85,12 @@ const defaultThemeConfig: ThemeConfig = { */ const defaultPageSizeOptions = [15, 30, 100]; const defaultComponentSettings: Partial = { + general: { + iconWrapper: { + icon: , + showCloseIcon: true, + }, + }, approvalRequests: { pageSizeOptions: defaultPageSizeOptions, }, From 408712edccf4abf8552b858cfdab6cef6cfae7b4 Mon Sep 17 00:00:00 2001 From: Andrei Tarasov Date: Mon, 6 Jan 2025 12:46:38 +0100 Subject: [PATCH 7/8] feat(DEV-13634): move MoniteReceivablesTable settings from theme to component settings --- packages/sdk-react/mui-styles.d.ts | 3 - .../ApprovalRequestsTable.tsx | 2 - .../components/receivables/Receivables.tsx | 4 +- .../ReceivablesTable.stories.tsx | 120 +++++++++--------- .../ReceivablesTable/ReceivablesTable.tsx | 35 +++-- .../src/core/componentSettings/index.ts | 31 ++++- .../src/core/context/MoniteContext.tsx | 7 +- .../src/core/utils/createThemeWithDefaults.ts | 33 +---- .../sdk-react/src/utils/storybook-utils.tsx | 50 +++----- packages/sdk-react/src/utils/test-utils.tsx | 3 +- 10 files changed, 130 insertions(+), 158 deletions(-) diff --git a/packages/sdk-react/mui-styles.d.ts b/packages/sdk-react/mui-styles.d.ts index 7f5af83bd..138a489c5 100644 --- a/packages/sdk-react/mui-styles.d.ts +++ b/packages/sdk-react/mui-styles.d.ts @@ -43,7 +43,6 @@ declare module '@mui/material/styles' { MoniteCounterpartStatusChip: 'root'; MoniteApprovalStatusChip: 'root'; MonitePayableTable: 'never'; - MoniteReceivablesTable: 'never'; } /** @@ -59,7 +58,6 @@ declare module '@mui/material/styles' { MoniteCounterpartStatusChip: Partial; MonitePayableTable: Partial; MoniteApprovalStatusChip: Partial; - MoniteReceivablesTable: Partial; } /** @@ -75,6 +73,5 @@ declare module '@mui/material/styles' { MoniteInvoiceRecurrenceIterationStatusChip?: ComponentType<'MoniteInvoiceRecurrenceIterationStatusChip'>; MoniteCounterpartStatusChip?: ComponentType<'MoniteCounterpartStatusChip'>; MoniteApprovalStatusChip?: ComponentType<'MoniteApprovalStatusChip'>; - MoniteReceivablesTable?: ComponentType<'MoniteReceivablesTable'>; } } diff --git a/packages/sdk-react/src/components/approvalRequests/ApprovalRequestsTable/ApprovalRequestsTable.tsx b/packages/sdk-react/src/components/approvalRequests/ApprovalRequestsTable/ApprovalRequestsTable.tsx index 3a644d8cb..82d607a73 100644 --- a/packages/sdk-react/src/components/approvalRequests/ApprovalRequestsTable/ApprovalRequestsTable.tsx +++ b/packages/sdk-react/src/components/approvalRequests/ApprovalRequestsTable/ApprovalRequestsTable.tsx @@ -287,8 +287,6 @@ const ApprovalRequestsTableBase = ({ ); } - console.log(componentSettings); - return ( ( const ReceivablesBase = () => { const { i18n } = useLingui(); + const { componentSettings } = useMoniteContext(); const [invoiceId, setInvoiceId] = useState(''); const [isCreateInvoiceDialogOpen, setIsCreateInvoiceDialogOpen] = useState(false); const [activeTab, setActiveTab] = useState( - ReceivablesTableTabEnum.Invoices + componentSettings.receivables.tab ?? ReceivablesTableTabEnum.Invoices ); const openInvoiceModal = (id: string) => { diff --git a/packages/sdk-react/src/components/receivables/ReceivablesTable/ReceivablesTable.stories.tsx b/packages/sdk-react/src/components/receivables/ReceivablesTable/ReceivablesTable.stories.tsx index 410a6c997..79a82ac9a 100644 --- a/packages/sdk-react/src/components/receivables/ReceivablesTable/ReceivablesTable.stories.tsx +++ b/packages/sdk-react/src/components/receivables/ReceivablesTable/ReceivablesTable.stories.tsx @@ -1,4 +1,4 @@ -import { ExtendThemeProvider } from '@/utils/ExtendThemeProvider'; +import { withGlobalStorybookDecorator } from '@/utils/storybook-utils'; import { action } from '@storybook/addon-actions'; import type { Meta, StoryObj } from '@storybook/react'; @@ -26,68 +26,66 @@ export const WithCustomTabs: Story = { args: { onRowClick: action('onRowClick'), }, - render: (args) => ( -
- ({ + componentSettings: { + receivables: { + tab: 1, + tabs: [ + { + label: 'Draft Invoices', + query: { + type: 'invoice', + sort: 'created_at', + order: 'desc', + status__in: ['draft'], }, + filters: [ + 'document_id__contains', + 'counterpart_id', + 'due_date__lte', + ], }, - }} - > - - -
- ), + { + label: 'Recurring invoices', + query: { + type: 'invoice', + status__in: ['recurring'], + }, + filters: ['document_id__contains', 'counterpart_id'], + }, + { + label: 'Other Invoices', + query: { + type: 'invoice', + sort: 'created_at', + order: 'desc', + status__in: [ + 'issued', + 'overdue', + 'partially_paid', + 'paid', + 'uncollectible', + 'canceled', + ], + }, + }, + { + label: 'Credit notes', + query: { + type: 'credit_note', + }, + }, + ], + }, + }, + })), + render: (args) => { + return ( +
+ +
+ ); + }, }; export default meta; diff --git a/packages/sdk-react/src/components/receivables/ReceivablesTable/ReceivablesTable.tsx b/packages/sdk-react/src/components/receivables/ReceivablesTable/ReceivablesTable.tsx index 2cf31d189..732b4d65e 100644 --- a/packages/sdk-react/src/components/receivables/ReceivablesTable/ReceivablesTable.tsx +++ b/packages/sdk-react/src/components/receivables/ReceivablesTable/ReceivablesTable.tsx @@ -3,20 +3,19 @@ import { useId, useState } from 'react'; import { CreditNotesTable } from '@/components'; import { InvoicesTable } from '@/components'; import { QuotesTable } from '@/components'; +import { FinanceTab } from '@/components'; import { ScopedCssBaselineContainerClassName } from '@/components/ContainerCssBaseline'; import { ReceivableFilterType, ReceivablesTabFilter, } from '@/components/receivables/ReceivablesTable/types'; +import { useMoniteContext } from '@/core/context/MoniteContext'; import { MoniteScopedProviders } from '@/core/context/MoniteScopedProviders'; import { FINANCING_LABEL, useFinancing } from '@/core/queries/useFinancing'; import { classNames } from '@/utils/css-utils'; import { t } from '@lingui/macro'; import { useLingui } from '@lingui/react'; import { Box, Tab, Tabs } from '@mui/material'; -import { useThemeProps } from '@mui/material/styles'; - -import { FinanceTab } from '../Financing/FinanceTab/FinanceTab'; interface ReceivablesTableControlledProps { /** Event handler for tab change */ @@ -33,7 +32,7 @@ interface ReceivablesTableUncontrolledProps { } /** - * Receivables Table props for MUI theming + * Receivables Table props for customisation via Monite Provider */ export interface MoniteReceivablesTableProps { /** Active-selected tab */ @@ -77,15 +76,13 @@ export type ReceivablesTableProps = * ReceivablesTable component * Displays Invoices, Quotes, Credit Notes * - * @example MUI theming + * @example Monite Provider customisation * ```ts - * // You can configure the component through MUI theming like this: - * const theme = createTheme(myTheme, { - * components: { - * MoniteReceivablesTable: { - * defaultProps: { - * tab: 0, // The default tab index to display - * tabs: [ + * // You can configure the component through Monite Provider property `componentSettings` like this: + * const componentSettings = { + * receivables: { + * tab: 0, // The default tab index to display + * tabs: [ * { * label: 'Draft Invoices', // The label of the Tab * query: { // The query parameters for the Tab @@ -131,9 +128,7 @@ export type ReceivablesTableProps = * type: 'credit_note', * }, * }, - * ], - * }, - * }, + * ], * }, * }); * ``` @@ -289,8 +284,10 @@ const ReceivablesTableBase = ({ export const useReceivablesTableProps = ( inProps?: Partial ) => { - return useThemeProps({ - props: inProps, - name: 'MoniteReceivablesTable', - }); + const { componentSettings } = useMoniteContext(); + + return { + tab: inProps?.tab ?? componentSettings?.receivables?.tab, + tabs: inProps?.tabs ?? componentSettings?.receivables?.tabs, + }; }; diff --git a/packages/sdk-react/src/core/componentSettings/index.ts b/packages/sdk-react/src/core/componentSettings/index.ts index 2cdf65664..fdc816f0a 100644 --- a/packages/sdk-react/src/core/componentSettings/index.ts +++ b/packages/sdk-react/src/core/componentSettings/index.ts @@ -1,4 +1,12 @@ +import { MoniteReceivablesTableProps } from '@/components/receivables/ReceivablesTable/ReceivablesTable'; +import { FINANCING_LABEL } from '@/core/queries/useFinancing'; import type { MoniteIconWrapperProps } from '@/ui/iconWrapper'; +import type { I18n } from '@lingui/core'; +import { t } from '@lingui/macro'; + +interface ReceivableSettings extends MoniteReceivablesTableProps { + pageSizeOptions: number[]; +} export interface ComponentSettings { general: { @@ -19,9 +27,7 @@ export interface ComponentSettings { products: { pageSizeOptions: number[]; }; - receivables: { - pageSizeOptions: number[]; - }; + receivables: Partial; tags: { pageSizeOptions: number[]; }; @@ -33,6 +39,7 @@ export interface ComponentSettings { const defaultPageSizeOptions = [15, 30, 100]; export const getDefaultComponentSettings = ( + i18n: I18n, componentSettings?: Partial ) => ({ general: { @@ -69,6 +76,24 @@ export const getDefaultComponentSettings = ( receivables: { pageSizeOptions: componentSettings?.receivables?.pageSizeOptions || defaultPageSizeOptions, + tab: componentSettings?.receivables?.tab || 0, + tabs: componentSettings?.receivables?.tabs || [ + { + label: t(i18n)`Invoices`, + query: { type: 'invoice' }, + }, + { + label: t(i18n)`Quotes`, + query: { type: 'quote' }, + }, + { + label: t(i18n)`Credit notes`, + query: { type: 'credit_note' }, + }, + { + label: FINANCING_LABEL, + }, + ], }, tags: { pageSizeOptions: diff --git a/packages/sdk-react/src/core/context/MoniteContext.tsx b/packages/sdk-react/src/core/context/MoniteContext.tsx index c73bf5219..52bcc2c75 100644 --- a/packages/sdk-react/src/core/context/MoniteContext.tsx +++ b/packages/sdk-react/src/core/context/MoniteContext.tsx @@ -160,10 +160,7 @@ const ContextProvider = ({ [entityId] ); - const theme = useMemo( - () => createThemeWithDefaults(i18n, userTheme), - [i18n, userTheme] - ); + const theme = useMemo(() => createThemeWithDefaults(userTheme), [userTheme]); useEffect(() => { queryClient.mount(); @@ -176,7 +173,7 @@ const ContextProvider = ({ environment, entityId, theme, - componentSettings: getDefaultComponentSettings(componentSettings), + componentSettings: getDefaultComponentSettings(i18n, componentSettings), queryClient, sentryHub, i18n, diff --git a/packages/sdk-react/src/core/utils/createThemeWithDefaults.ts b/packages/sdk-react/src/core/utils/createThemeWithDefaults.ts index a26a2b9a8..381177d5f 100644 --- a/packages/sdk-react/src/core/utils/createThemeWithDefaults.ts +++ b/packages/sdk-react/src/core/utils/createThemeWithDefaults.ts @@ -1,8 +1,6 @@ import { ScopedCssBaselineContainerClassName } from '@/components/ContainerCssBaseline'; import { getTheme } from '@/core/theme/mui-monite'; import { ThemeConfig } from '@/core/theme/types'; -import type { I18n } from '@lingui/core'; -import { t } from '@lingui/macro'; import { createTheme, type Theme, @@ -10,43 +8,16 @@ import { type ThemeOptions, } from '@mui/material'; -import { FINANCING_LABEL } from '../queries/useFinancing'; - /** * Create a theme with the default component's `defaultProps` */ -export const createThemeWithDefaults = ( - i18n: I18n, - theme: ThemeConfig = {} -) => { +export const createThemeWithDefaults = (theme: ThemeConfig = {}) => { const themeOptions = getTheme(theme); return createTheme( themeOptions, { - components: { - MoniteReceivablesTable: { - defaultProps: { - tabs: [ - { - label: t(i18n)`Invoices`, - query: { type: 'invoice' }, - }, - { - label: t(i18n)`Quotes`, - query: { type: 'quote' }, - }, - { - label: t(i18n)`Credit notes`, - query: { type: 'credit_note' }, - }, - { - label: FINANCING_LABEL, - }, - ], - }, - }, - }, + components: {}, } satisfies ThemeOptions, { components: { diff --git a/packages/sdk-react/src/utils/storybook-utils.tsx b/packages/sdk-react/src/utils/storybook-utils.tsx index 6e1c836b0..673418c8b 100644 --- a/packages/sdk-react/src/utils/storybook-utils.tsx +++ b/packages/sdk-react/src/utils/storybook-utils.tsx @@ -51,16 +51,23 @@ export function getRandomNumber(min = 0, max = 100) { export const withGlobalStorybookDecorator = ( cb?: () => { - monite: MoniteSettings; + monite?: MoniteSettings; + componentSettings?: Partial; } ): any => { - const { monite } = cb?.() ?? { monite: undefined }; + const { monite, componentSettings } = cb?.() ?? { + monite: undefined, + componentSettings: undefined, + }; return withThemeFromJSXProvider({ Provider: (...args: any[]) => { - const updatedArgs = monite ? { ...args[0], monite } : args[0]; - - return GlobalStorybookDecorator(updatedArgs); + return GlobalStorybookDecorator({ + ...args, + children: args[0].children, + monite, + componentSettings, + }); }, }); }; @@ -83,7 +90,6 @@ const defaultThemeConfig: ThemeConfig = { * * These settings are used to configure default functionality of the SDK components in storybook stories. */ -const defaultPageSizeOptions = [15, 30, 100]; const defaultComponentSettings: Partial = { general: { iconWrapper: { @@ -91,33 +97,13 @@ const defaultComponentSettings: Partial = { showCloseIcon: true, }, }, - approvalRequests: { - pageSizeOptions: defaultPageSizeOptions, - }, - approvalPolicies: { - pageSizeOptions: defaultPageSizeOptions, - }, - counterparts: { - pageSizeOptions: defaultPageSizeOptions, - }, - products: { - pageSizeOptions: defaultPageSizeOptions, - }, - receivables: { - pageSizeOptions: defaultPageSizeOptions, - }, - tags: { - pageSizeOptions: defaultPageSizeOptions, - }, - userRoles: { - pageSizeOptions: defaultPageSizeOptions, - }, }; export const GlobalStorybookDecorator = (props: { children: ReactNode; theme?: ThemeConfig; monite?: MoniteSettings; + componentSettings?: Partial; }) => { const apiUrl = 'https://api.sandbox.monite.com/v1'; @@ -154,7 +140,10 @@ export const GlobalStorybookDecorator = (props: { {props.children} @@ -193,10 +182,7 @@ function FallbackProviders({ return ( Date: Tue, 7 Jan 2025 18:32:22 +0100 Subject: [PATCH 8/8] feat(DEV-13634): move MonitePayableTable settings from theme to component settings --- .../src/themes/monite.ts | 15 ------------ packages/sdk-react/mui-styles.d.ts | 4 ---- .../payables/PayablesTable/PayablesTable.tsx | 21 +++++++++++------ .../payables/PayablesTable/types.ts | 2 +- .../src/core/componentSettings/index.ts | 22 +++++++++++++++--- .../src/core/theme/mui-monite/index.ts | 15 ------------ packages/sdk-react/src/core/theme/types.ts | 23 +------------------ .../sdk-react/src/utils/storybook-utils.tsx | 10 ++++++++ 8 files changed, 45 insertions(+), 67 deletions(-) diff --git a/examples/with-nextjs-and-clerk-auth/src/themes/monite.ts b/examples/with-nextjs-and-clerk-auth/src/themes/monite.ts index 852754462..184855453 100644 --- a/examples/with-nextjs-and-clerk-auth/src/themes/monite.ts +++ b/examples/with-nextjs-and-clerk-auth/src/themes/monite.ts @@ -1047,21 +1047,6 @@ const defaultMoniteComponents: Components> = { }, }, }, - MonitePayableTable: { - defaultProps: { - isShowingSummaryCards: true, - fieldOrder: [ - 'document_id', - 'counterpart_id', - 'created_at', - 'issued_at', - 'due_date', - 'status', - 'amount', - 'pay', - ], - }, - }, MuiFormHelperText: { styleOverrides: { root: { diff --git a/packages/sdk-react/mui-styles.d.ts b/packages/sdk-react/mui-styles.d.ts index 138a489c5..665730d35 100644 --- a/packages/sdk-react/mui-styles.d.ts +++ b/packages/sdk-react/mui-styles.d.ts @@ -7,7 +7,6 @@ import { type MoniteInvoiceStatusChipProps, type MonitePayableDetailsInfoProps, type MonitePayableStatusChipProps, - type MonitePayableTableProps, } from '@/core/theme/types'; import { ComponentsOverrides, @@ -42,7 +41,6 @@ declare module '@mui/material/styles' { MoniteInvoiceRecurrenceIterationStatusChip: 'root'; MoniteCounterpartStatusChip: 'root'; MoniteApprovalStatusChip: 'root'; - MonitePayableTable: 'never'; } /** @@ -56,7 +54,6 @@ declare module '@mui/material/styles' { MoniteInvoiceRecurrenceStatusChip: Partial; MoniteInvoiceRecurrenceIterationStatusChip: Partial; MoniteCounterpartStatusChip: Partial; - MonitePayableTable: Partial; MoniteApprovalStatusChip: Partial; } @@ -68,7 +65,6 @@ declare module '@mui/material/styles' { MonitePayableStatusChip?: ComponentType<'MonitePayableStatusChip'>; MoniteApprovalRequestStatusChip?: ComponentType<'MoniteApprovalRequestStatusChip'>; MonitePayableDetailsInfo?: ComponentType<'MonitePayableDetailsInfo'>; - MonitePayableTable?: ComponentType<'MonitePayableTable'>; MoniteInvoiceRecurrenceStatusChip?: ComponentType<'MoniteInvoiceRecurrenceStatusChip'>; MoniteInvoiceRecurrenceIterationStatusChip?: ComponentType<'MoniteInvoiceRecurrenceIterationStatusChip'>; MoniteCounterpartStatusChip?: ComponentType<'MoniteCounterpartStatusChip'>; diff --git a/packages/sdk-react/src/components/payables/PayablesTable/PayablesTable.tsx b/packages/sdk-react/src/components/payables/PayablesTable/PayablesTable.tsx index a4ce8994b..761442fca 100644 --- a/packages/sdk-react/src/components/payables/PayablesTable/PayablesTable.tsx +++ b/packages/sdk-react/src/components/payables/PayablesTable/PayablesTable.tsx @@ -29,7 +29,6 @@ import { hasSelectedText } from '@/utils/text-selection'; import { t } from '@lingui/macro'; import { useLingui } from '@lingui/react'; import { Box, CircularProgress, Stack, Typography } from '@mui/material'; -import { useThemeProps } from '@mui/material/styles'; import { DataGrid, GridColDef, @@ -161,7 +160,7 @@ const PayablesTableBase = ({ string | null >(null); const [pageSize, setPageSize] = useState( - componentSettings.payables.pageSizeOptions[0] + componentSettings.payables.pageSizeOptions?.[0] ?? 15 ); const [sortModel, setSortModel] = useState({ field: 'created_at', @@ -527,8 +526,16 @@ const PayablesTableBase = ({ const usePayableTableThemeProps = ( inProps: Partial -): MonitePayableTableProps => - useThemeProps({ - props: inProps, - name: 'MonitePayableTable', - }); +): MonitePayableTableProps => { + const { componentSettings } = useMoniteContext(); + + return { + isShowingSummaryCards: + inProps?.isShowingSummaryCards ?? + componentSettings?.payables?.isShowingSummaryCards, + fieldOrder: inProps?.fieldOrder ?? componentSettings?.payables?.fieldOrder, + summaryCardFilters: + inProps?.summaryCardFilters ?? + componentSettings?.payables?.summaryCardFilters, + }; +}; diff --git a/packages/sdk-react/src/components/payables/PayablesTable/types.ts b/packages/sdk-react/src/components/payables/PayablesTable/types.ts index a8b3dd109..66ed71392 100644 --- a/packages/sdk-react/src/components/payables/PayablesTable/types.ts +++ b/packages/sdk-react/src/components/payables/PayablesTable/types.ts @@ -38,7 +38,7 @@ export type FieldValueTypes = export interface MonitePayableTableProps { isShowingSummaryCards?: boolean; - fieldOrder?: Array; + fieldOrder?: FieldValueTypes[]; summaryCardFilters?: Record; } diff --git a/packages/sdk-react/src/core/componentSettings/index.ts b/packages/sdk-react/src/core/componentSettings/index.ts index fdc816f0a..ba0fcbd29 100644 --- a/packages/sdk-react/src/core/componentSettings/index.ts +++ b/packages/sdk-react/src/core/componentSettings/index.ts @@ -1,3 +1,4 @@ +import { MonitePayableTableProps } from '@/components/payables/PayablesTable/types'; import { MoniteReceivablesTableProps } from '@/components/receivables/ReceivablesTable/ReceivablesTable'; import { FINANCING_LABEL } from '@/core/queries/useFinancing'; import type { MoniteIconWrapperProps } from '@/ui/iconWrapper'; @@ -8,6 +9,10 @@ interface ReceivableSettings extends MoniteReceivablesTableProps { pageSizeOptions: number[]; } +interface PayableSettings extends MonitePayableTableProps { + pageSizeOptions: number[]; +} + export interface ComponentSettings { general: { iconWrapper: Partial; @@ -21,9 +26,7 @@ export interface ComponentSettings { counterparts: { pageSizeOptions: number[]; }; - payables: { - pageSizeOptions: number[]; - }; + payables: Partial; products: { pageSizeOptions: number[]; }; @@ -38,6 +41,15 @@ export interface ComponentSettings { const defaultPageSizeOptions = [15, 30, 100]; +const defaultPayableFieldOrder = [ + 'document_id', + 'counterpart_id', + 'due_date', + 'amount', + 'was_created_by_user_id', + 'pay', +]; + export const getDefaultComponentSettings = ( i18n: I18n, componentSettings?: Partial @@ -68,6 +80,10 @@ export const getDefaultComponentSettings = ( payables: { pageSizeOptions: componentSettings?.payables?.pageSizeOptions || defaultPageSizeOptions, + isShowingSummaryCards: + componentSettings?.payables?.isShowingSummaryCards ?? true, + fieldOrder: + componentSettings?.payables?.fieldOrder || defaultPayableFieldOrder, }, products: { pageSizeOptions: diff --git a/packages/sdk-react/src/core/theme/mui-monite/index.ts b/packages/sdk-react/src/core/theme/mui-monite/index.ts index e2044ba79..1383035cb 100644 --- a/packages/sdk-react/src/core/theme/mui-monite/index.ts +++ b/packages/sdk-react/src/core/theme/mui-monite/index.ts @@ -983,21 +983,6 @@ export const getTheme = (theme: ThemeConfig): ThemeOptions => { }, }, }, - MonitePayableTable: { - defaultProps: { - isShowingSummaryCards: true, - fieldOrder: [ - 'document_id', - 'counterpart_id', - 'created_at', - 'issued_at', - 'due_date', - 'status', - 'amount', - 'pay', - ], - }, - }, MuiFormHelperText: { styleOverrides: { root: { diff --git a/packages/sdk-react/src/core/theme/types.ts b/packages/sdk-react/src/core/theme/types.ts index bebb24a79..78bedfa04 100644 --- a/packages/sdk-react/src/core/theme/types.ts +++ b/packages/sdk-react/src/core/theme/types.ts @@ -1,4 +1,4 @@ -import { components, Services } from '@/api'; +import { components } from '@/api'; import { ChipProps } from '@mui/material'; type TypographyStyle = { @@ -145,27 +145,6 @@ export interface MoniteApprovalStatusChipProps extends BaseStatusChipProps { status: components['schemas']['ApprovalPolicyStatus']; } -export type PayablesTabFilter = NonNullable< - Services['payables']['getPayables']['types']['parameters']['query'] ->; - -//TODO: better to map it with schema.json keyof values -export type FieldValueTypes = - | 'document_id' - | 'counterpart_id' - | 'created_at' - | 'issued_at' - | 'due_date' - | 'status' - | 'amount' - | 'pay'; - -export interface MonitePayableTableProps { - isShowingSummaryCards?: boolean; - fieldOrder?: FieldValueTypes[]; - summaryCardFilters?: Record; -} - export type OptionalFields = { invoiceDate?: boolean; tags?: boolean; diff --git a/packages/sdk-react/src/utils/storybook-utils.tsx b/packages/sdk-react/src/utils/storybook-utils.tsx index 673418c8b..720151db5 100644 --- a/packages/sdk-react/src/utils/storybook-utils.tsx +++ b/packages/sdk-react/src/utils/storybook-utils.tsx @@ -97,6 +97,16 @@ const defaultComponentSettings: Partial = { showCloseIcon: true, }, }, + payables: { + fieldOrder: [ + 'amount', + 'document_id', + 'counterpart_id', + 'was_created_by_user_id', + 'due_date', + 'pay', + ], + }, }; export const GlobalStorybookDecorator = (props: {