diff --git a/.gitignore b/.gitignore
index 2c4105f7..2db2c100 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,7 +43,6 @@ next-env.d.ts
*storybook.log
# Storybook
-.storybook
/storybook-static/
# Playwright
diff --git a/.storybook/main.ts b/.storybook/main.ts
new file mode 100644
index 00000000..c4ed6878
--- /dev/null
+++ b/.storybook/main.ts
@@ -0,0 +1,57 @@
+import type { StorybookConfig } from '@storybook/nextjs'
+
+const config: StorybookConfig = {
+ stories: [
+ '../src/components/**/*.mdx',
+ '../src/components/**/*.stories.@(js|jsx|mjs|ts|tsx)'
+ ],
+ staticDirs: ['../public'],
+ addons: [
+ '@storybook/addon-onboarding',
+ '@storybook/addon-links',
+ '@storybook/addon-essentials',
+ '@chromatic-com/storybook',
+ '@storybook/addon-interactions',
+ '@storybook/addon-styling-webpack',
+
+ {
+ name: '@storybook/addon-styling-webpack',
+ options: {
+ rules: [
+ {
+ test: /\.css$/,
+ sideEffects: true,
+ use: [
+ require.resolve('style-loader'),
+ {
+ loader: require.resolve('css-loader'),
+ options: {
+ importLoaders: 1
+ }
+ },
+ {
+ loader: require.resolve('postcss-loader'),
+ options: {
+ implementation: require.resolve('postcss')
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+ ],
+
+ framework: {
+ name: '@storybook/nextjs',
+ options: {}
+ },
+ typescript: {
+ reactDocgen: 'react-docgen-typescript'
+ },
+ docs: {
+ autodocs: 'tag'
+ },
+ build: {}
+}
+export default config
diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx
new file mode 100644
index 00000000..d7963faa
--- /dev/null
+++ b/.storybook/preview.tsx
@@ -0,0 +1,34 @@
+import type { Preview } from '@storybook/react'
+
+import '../src/app/globals.css'
+
+import React from 'react'
+import { ThemeProvider } from '../src/lib/theme/theme-provider'
+import { IntlProvider } from 'react-intl'
+
+const preview: Preview = {
+ parameters: {
+ backgrounds: {
+ values: [{ name: 'Light', value: '#f4f4f5' }],
+ default: 'Light'
+ },
+ controls: {
+ matchers: {
+ color: /(background|color)$/i,
+ date: /Date$/i
+ }
+ }
+ }
+}
+
+export const decorators = [
+ (Story) => (
+
+
+
+
+
+ )
+]
+
+export default preview
diff --git a/locales/extracted/en.json b/locales/extracted/en.json
index ad1f9360..3a8209de 100644
--- a/locales/extracted/en.json
+++ b/locales/extracted/en.json
@@ -43,6 +43,7 @@
"common.noOptions": "No options found.",
"common.portfolio": "Portfolio",
"common.previousPage": "Previous page",
+ "common.records": "records",
"common.remove": "Remove",
"common.requiredFields": "(*) required fields.",
"common.resources": "Resources",
@@ -158,7 +159,7 @@
"ledgers.account.sheet.edit.title": "Edit {accountName}",
"ledgers.account.sheet.tabs.details": "Account Details",
"ledgers.accounts.createFirst": "Create first account",
- "ledgers.accounts.subtitle": "{count} {count, plural, =0 {accounts found} one {acount found} other {accounts found}}",
+ "ledgers.accounts.subtitle": "{count} {count, plural, =0 {accounts found} one {account found} other {accounts found}}",
"ledgers.accounts.title": "Accounts",
"ledgers.assets.createButton": "Create your first Asset",
"ledgers.assets.emptyResource": "You haven't added any Asset within this Ledger yet.",
@@ -199,12 +200,14 @@
"ledgers.products.sheet.title": "New Product",
"ledgers.products.subtitle": "Clustering or allocation of customers at different levels.",
"ledgers.products.title": "Products",
+ "ledgers.sheet.tabs.details": "Ledger Details",
"ledgers.sheetCreate.description": "Fill in the data of the Ledger you wish to create.",
"ledgers.sheetCreate.title": "New Ledger",
"ledgers.subtitle": "Visualize and edit the Ledgers of your Organization.",
+ "ledgers.tab.accounts": "Accounts",
"ledgers.tab.assets": "Assets",
"ledgers.tab.overview": "Overview",
- "ledgers.tab.portfolios-and-accounts": "Portfolios and Accounts",
+ "ledgers.tab.portfolios": "Portfolios",
"ledgers.tab.products": "Products",
"ledgers.title": "Ledgers",
"ledgers.toast.accountCreated": "{accountName} account successfully created",
@@ -249,6 +252,7 @@
"products.delete.description": "You are about to permanently delete this product. This action cannot be undone. Do you wish to continue?",
"settings.tab.organizations": "Organizations",
"settings.tab.otherSettings": "Other Settings",
+ "settings.tab.portfolios": "Portfolios",
"settings.tab.products": "Products",
"settings.tabs.organizations": "Organizations",
"settings.tabs.others": "Others Settings",
diff --git a/locales/extracted/pt.json b/locales/extracted/pt.json
index ff403cbb..07b01f0d 100644
--- a/locales/extracted/pt.json
+++ b/locales/extracted/pt.json
@@ -168,7 +168,6 @@
"ledgers.portfolio.sheet.edit.description": "Visualize e edite os campos do portfólio.",
"ledgers.portfolio.sheet.edit.title": "Editar {portfolioName}",
"ledgers.portfolio.sheet.title": "Novo Portfólio",
- "ledgers.tab.portfolios-and-accounts": "Portfólios e Contas",
"portfolio.create": "Criar primeiro portfólio",
"entity.portfolio.description": "Insira o identificador único da entidade associado a este portfólio",
"entity.portfolio.entityId": "ID da Entidade",
@@ -279,5 +278,10 @@
"ledgers.assets.sheet.tabs.details": "Detalhes do Ativo",
"ledgers.portfolio.sheet.tabs.details": "Detalhes do Portfólio",
"ledgers.products.sheet.tabs.details": "Detalhes do Produto",
- "notFound.backToHome": "Voltar para Home"
+ "notFound.backToHome": "Voltar para Home",
+ "ledgers.sheet.tabs.details": "Detalhes do Ledger",
+ "common.records": "registros",
+ "ledgers.tab.accounts": "Contas",
+ "ledgers.tab.portfolios": "Portfólios",
+ "settings.tab.portfolios": "Portfólios"
}
diff --git a/package.json b/package.json
index 6d4f9cbd..a7f75b4e 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,7 @@
"build": "next build",
"start": "next start -p 8081",
"lint": "next lint --fix",
- "storybook": "storybook dev -p 6006",
+ "storybook": "storybook dev -p 6007",
"build-storybook": "storybook build",
"extract:i18n": "tsx ./scripts/i18n-extract.ts",
"compile:i18n": "formatjs compile-folder \"./locales/extracted\" --format simple \"./locales/compiled\"",
diff --git a/src/app/(auth-routes)/signin/page.tsx b/src/app/(auth-routes)/signin/page.tsx
index 9cfbeb34..044c458e 100644
--- a/src/app/(auth-routes)/signin/page.tsx
+++ b/src/app/(auth-routes)/signin/page.tsx
@@ -16,6 +16,7 @@ import { ArrowRight } from 'lucide-react'
import React from 'react'
import LoadingScreen from '@/components/loading-screen'
import MidazLogo from '@/images/midaz-login-screen.png'
+import BackgroundImage from '@/images/login-wallpaper.jpg'
import {
Tooltip,
TooltipContent,
@@ -172,7 +173,13 @@ const SignInPage = () => {
-
+
+
diff --git a/src/app/(routes)/ledgers/[id]/accounts-and-portfolios/accounts-portfolios-tab-content.tsx b/src/app/(routes)/ledgers/[id]/accounts-and-portfolios/accounts-portfolios-tab-content.tsx
deleted file mode 100644
index 8917e8c2..00000000
--- a/src/app/(routes)/ledgers/[id]/accounts-and-portfolios/accounts-portfolios-tab-content.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import { AccountsContent } from './accounts-content'
-import { PortfoliosContent } from './portfolios-content'
-
-export const AccountsPortfoliosTabContent = () => {
- return (
-
- )
-}
diff --git a/src/app/(routes)/ledgers/[id]/accounts-and-portfolios/portfolios-content.tsx b/src/app/(routes)/ledgers/[id]/accounts-and-portfolios/portfolios-content.tsx
deleted file mode 100644
index 96fc9cb3..00000000
--- a/src/app/(routes)/ledgers/[id]/accounts-and-portfolios/portfolios-content.tsx
+++ /dev/null
@@ -1,334 +0,0 @@
-import { Button } from '@/components/ui/button'
-import { MoreVertical, Plus, ChevronDown, ChevronUp } from 'lucide-react'
-import { PortfolioSheet } from './portfolios-sheet'
-import { useParams } from 'next/navigation'
-import { EntityBox } from '@/components/entity-box'
-import { useCreateUpdateSheet } from '@/components/sheet/use-create-update-sheet'
-import { PortfolioResponseDto } from '@/core/application/dto/portfolios-dto'
-import { useDeletePortfolio, useListPortfolios } from '@/client/portfolios'
-import { useOrganization } from '@/context/organization-provider/organization-provider-client'
-import { useIntl } from 'react-intl'
-import { isNil } from 'lodash'
-import {
- getCoreRowModel,
- getFilteredRowModel,
- useReactTable
-} from '@tanstack/react-table'
-import React, { useState } from 'react'
-import { useConfirmDialog } from '@/components/confirmation-dialog/use-confirm-dialog'
-import {
- DropdownMenu,
- DropdownMenuContent,
- DropdownMenuItem,
- DropdownMenuSeparator,
- DropdownMenuTrigger
-} from '@/components/ui/dropdown-menu'
-import {
- Table,
- TableBody,
- TableCell,
- TableContainer,
- TableHead,
- TableHeader,
- TableRow
-} from '@/components/ui/table'
-import { truncateString } from '@/helpers'
-import ConfirmationDialog from '@/components/confirmation-dialog'
-import { Skeleton } from '@/components/ui/skeleton'
-import { useAllPortfoliosAccounts } from '@/client/accounts'
-import {
- Tooltip,
- TooltipContent,
- TooltipProvider,
- TooltipTrigger
-} from '@/components/ui/tooltip'
-import useCustomToast from '@/hooks/use-custom-toast'
-import { Arrow } from '@radix-ui/react-tooltip'
-
-export const PortfoliosContent = () => {
- const intl = useIntl()
- const { id: ledgerId } = useParams<{ id: string }>()
- const { currentOrganization } = useOrganization()
- const [columnFilters, setColumnFilters] = React.useState
([])
- const [isTableExpanded, setIsTableExpanded] = useState(false)
- const { showInfo } = useCustomToast()
-
- const {
- data: portfoliosData,
- refetch,
- isLoading
- } = useAllPortfoliosAccounts({
- organizationId: currentOrganization.id!,
- ledgerId: ledgerId
- })
-
- const { mutate: deletePortfolio, isPending: deletePending } =
- useDeletePortfolio({
- organizationId: currentOrganization.id!,
- ledgerId,
- onSuccess: () => {
- handleDialogClose()
- refetch()
- }
- })
-
- const { handleDialogOpen, dialogProps, handleDialogClose } = useConfirmDialog(
- {
- onConfirm: (id: string) => deletePortfolio({ id })
- }
- )
-
- const { handleCreate, handleEdit, sheetProps } =
- useCreateUpdateSheet()
-
- const table = useReactTable({
- data: portfoliosData?.items!,
- columns: [
- {
- accessorKey: 'name'
- }
- ],
- getCoreRowModel: getCoreRowModel(),
- getFilteredRowModel: getFilteredRowModel(),
- onColumnFiltersChange: setColumnFilters,
- state: {
- columnFilters
- }
- })
-
- if (isLoading) {
- return
- }
- const handleCopyToClipboard = (value: string, message: string) => {
- navigator.clipboard.writeText(value)
- showInfo(message)
- }
-
- return (
- <>
-
-
-
-
-
-
-
-
- {!isNil(portfoliosData?.items) &&
- portfoliosData?.items.length > 0 && (
-
- )}
-
-
-
- {!isNil(portfoliosData?.items) &&
- portfoliosData?.items.length > 0 &&
- isTableExpanded && (
-
-
-
-
-
- {intl.formatMessage({
- id: 'common.id',
- defaultMessage: 'ID'
- })}
-
-
- {intl.formatMessage({
- id: 'common.name',
- defaultMessage: 'Name'
- })}
-
-
- {intl.formatMessage({
- id: 'common.metadata',
- defaultMessage: 'Metadata'
- })}
-
-
- {intl.formatMessage({
- id: 'common.accounts',
- defaultMessage: 'Accounts'
- })}
-
-
- {intl.formatMessage({
- id: 'common.actions',
- defaultMessage: 'Actions'
- })}
-
-
-
-
- {table.getRowModel().rows.map((portfolio) => {
- const displayId =
- portfolio.original.id && portfolio.original.id.length > 8
- ? `${truncateString(portfolio.original.id, 8)}`
- : portfolio.original.id
-
- return (
-
-
-
-
-
- handleCopyToClipboard(
- portfolio.original.id,
- intl.formatMessage({
- id: 'ledgers.toast.copyId',
- defaultMessage:
- 'The id has been copied to your clipboard.'
- })
- )
- }
- >
-
- {displayId}
-
-
-
-
- {portfolio.original.id}
-
-
- {intl.formatMessage({
- id: 'ledgers.columnsTable.tooltipCopyText',
- defaultMessage: 'Click to copy'
- })}
-
-
-
-
-
-
- {portfolio.original.name}
-
- {intl.formatMessage(
- {
- id: 'common.table.accounts',
- defaultMessage:
- '{number, plural, =0 {No accounts} one {# account} other {# accounts}}'
- },
- {
- number: portfolio.original.accounts?.length || 0
- }
- )}
-
-
- {intl.formatMessage(
- {
- id: 'common.table.metadata',
- defaultMessage:
- '{number, plural, =0 {-} one {# record} other {# records}}'
- },
- {
- number: Object.entries(
- portfolio.original.metadata || []
- ).length
- }
- )}
-
-
-
-
-
-
-
-
-
- handleEdit({
- ...portfolio.original,
- entityId: portfolio.original.id,
- status: {
- ...portfolio.original.status,
- description:
- portfolio.original.status.description ??
- ''
- }
- } as PortfolioResponseDto)
- }
- >
- {intl.formatMessage({
- id: `common.edit`,
- defaultMessage: 'Edit'
- })}
-
-
- {
- handleDialogOpen(portfolio?.original?.id!)
- }}
- >
- {intl.formatMessage({
- id: `common.delete`,
- defaultMessage: 'Delete'
- })}
-
-
-
-
-
- )
- })}
-
-
-
- )}
- >
- )
-}
diff --git a/src/app/(routes)/ledgers/[id]/accounts-and-portfolios/accounts-data-table.tsx b/src/app/(routes)/ledgers/[id]/accounts/accounts-data-table.tsx
similarity index 67%
rename from src/app/(routes)/ledgers/[id]/accounts-and-portfolios/accounts-data-table.tsx
rename to src/app/(routes)/ledgers/[id]/accounts/accounts-data-table.tsx
index 6e44835c..65171473 100644
--- a/src/app/(routes)/ledgers/[id]/accounts-and-portfolios/accounts-data-table.tsx
+++ b/src/app/(routes)/ledgers/[id]/accounts/accounts-data-table.tsx
@@ -41,7 +41,6 @@ type AccountsTableProps = {
}
onDelete: (id: string, account: AccountType) => void
refetch: () => void
- isTableExpanded: boolean
handleEdit: (account: AccountType) => void
}
@@ -118,11 +117,13 @@ const AccountRow: React.FC = ({
)
)}
- {account.original.portfolioName}
+
+ {account.original.portfolio?.name ?? }
+
-
@@ -155,7 +156,6 @@ export const AccountsDataTable: React.FC = ({
accounts,
table,
onDelete,
- isTableExpanded,
handleEdit
}) => {
const intl = useIntl()
@@ -167,66 +167,64 @@ export const AccountsDataTable: React.FC = ({
}
return (
- <>
- {!isNil(accounts?.items) &&
- accounts?.items.length > 0 &&
- isTableExpanded && (
-
-
-
-
-
- {intl.formatMessage({
- id: 'common.id',
- defaultMessage: 'ID'
- })}
-
-
- {intl.formatMessage({
- id: 'entity.account.name',
- defaultMessage: 'Account Name'
- })}
-
-
- {intl.formatMessage({
- id: 'entity.account.currency',
- defaultMessage: 'Assets'
- })}
-
-
- {intl.formatMessage({
- id: 'common.metadata',
- defaultMessage: 'Metadata'
- })}
-
-
- {intl.formatMessage({
- id: 'common.portfolio',
- defaultMessage: 'Portfolio'
- })}
-
-
- {intl.formatMessage({
- id: 'common.actions',
- defaultMessage: 'Actions'
- })}
-
-
-
-
- {table.getRowModel().rows.map((account) => (
-
- ))}
-
-
-
- )}
- >
+
+ {!isNil(accounts?.items) && accounts?.items.length > 0 && (
+
+
+
+
+
+ {intl.formatMessage({
+ id: 'common.id',
+ defaultMessage: 'ID'
+ })}
+
+
+ {intl.formatMessage({
+ id: 'entity.account.name',
+ defaultMessage: 'Account Name'
+ })}
+
+
+ {intl.formatMessage({
+ id: 'entity.account.currency',
+ defaultMessage: 'Assets'
+ })}
+
+
+ {intl.formatMessage({
+ id: 'common.metadata',
+ defaultMessage: 'Metadata'
+ })}
+
+
+ {intl.formatMessage({
+ id: 'common.portfolio',
+ defaultMessage: 'Portfolio'
+ })}
+
+
+ {intl.formatMessage({
+ id: 'common.actions',
+ defaultMessage: 'Actions'
+ })}
+
+
+
+
+ {table.getRowModel().rows.map((account) => (
+
+ ))}
+
+
+
+ )}
+
)
}
diff --git a/src/app/(routes)/ledgers/[id]/accounts-and-portfolios/accounts-sheet.tsx b/src/app/(routes)/ledgers/[id]/accounts/accounts-sheet.tsx
similarity index 77%
rename from src/app/(routes)/ledgers/[id]/accounts-and-portfolios/accounts-sheet.tsx
rename to src/app/(routes)/ledgers/[id]/accounts/accounts-sheet.tsx
index 9e7160c1..8cfa1cb7 100644
--- a/src/app/(routes)/ledgers/[id]/accounts-and-portfolios/accounts-sheet.tsx
+++ b/src/app/(routes)/ledgers/[id]/accounts/accounts-sheet.tsx
@@ -20,7 +20,7 @@ import { MetadataField } from '@/components/form/metadata-field'
import { useListProducts } from '@/client/products'
import { useCreateAccount, useUpdateAccount } from '@/client/accounts'
import { useListPortfolios } from '@/client/portfolios'
-import { isNil } from 'lodash'
+import { isNil, omitBy } from 'lodash'
import { useListAssets } from '@/client/assets'
import useCustomToast from '@/hooks/use-custom-toast'
import { accountSchema } from '@/schema/account'
@@ -34,12 +34,13 @@ export type AccountSheetProps = DialogProps & {
ledgerId: string
mode: 'create' | 'edit'
data?: AccountType | null
- onSucess?: () => void
+ onSuccess?: () => void
}
-const defaultValues = {
+const initialValues = {
name: '',
entityId: '',
+ portfolioId: '',
productId: '',
assetCode: '',
alias: '',
@@ -52,7 +53,7 @@ type FormData = z.infer
export const AccountSheet = ({
mode,
data,
- onSucess,
+ onSuccess,
onOpenChange,
...others
}: AccountSheetProps) => {
@@ -104,21 +105,14 @@ export const AccountSheet = ({
const form = useForm>({
resolver: zodResolver(accountSchema),
- defaultValues: Object.assign(
- {},
- defaultValues,
- mode === 'create' ? { entityId: '' } : {}
- )
+ defaultValues: initialValues
})
- const selectedPortfolioId = form.watch('portfolioId')
-
const { mutate: createAccount, isPending: createPending } = useCreateAccount({
organizationId: currentOrganization.id!,
ledgerId,
- portfolioId: selectedPortfolioId,
onSuccess: (data) => {
- onSucess?.()
+ onSuccess?.()
onOpenChange?.(false)
showSuccess(
intl.formatMessage(
@@ -144,9 +138,8 @@ export const AccountSheet = ({
organizationId: currentOrganization.id!,
ledgerId,
accountId: data?.id!,
- portfolioId: data?.portfolioId!,
onSuccess: (data) => {
- onSucess?.()
+ onSuccess?.()
onOpenChange?.(false)
showSuccess(
intl.formatMessage(
@@ -171,19 +164,21 @@ export const AccountSheet = ({
const { showSuccess, showError } = useCustomToast()
const handleSubmit = (data: FormData) => {
+ const cleanedData = omitBy(data, (value) => value === '' || isNil(value))
+
if (mode === 'create') {
createAccount({
- ...data,
- portfolioId: data.portfolioId
+ ...cleanedData,
+ portfolioId: cleanedData.portfolioId
})
} else if (mode === 'edit') {
- const { portfolioId, assetCode, ...updateData } = data
+ const { type, portfolioId, assetCode, ...updateData } = cleanedData
updateAccount({
...updateData
})
}
- form.reset(defaultValues)
+ form.reset(initialValues)
}
React.useEffect(() => {
@@ -198,7 +193,7 @@ export const AccountSheet = ({
}, [data])
return (
- <>
+
e.preventDefault()}>
{mode === 'create' && (
@@ -290,78 +285,76 @@ export const AccountSheet = ({
})}
/>
-
-
- {intl.formatMessage({
- id: 'account.sheet.type.deposit',
- defaultMessage: 'Deposit'
- })}
-
-
-
- {intl.formatMessage({
- id: 'account.sheet.type.savings',
- defaultMessage: 'Savings'
- })}
-
-
-
- {intl.formatMessage({
- id: 'account.sheet.type.loans',
- defaultMessage: 'Loans'
- })}
-
-
-
- {intl.formatMessage({
- id: 'account.sheet.type.marketplace',
- defaultMessage: 'Marketplace'
- })}
-
-
-
- {intl.formatMessage({
- id: 'account.sheet.type.creditCard',
- defaultMessage: 'CreditCard'
- })}
-
-
-
- {intl.formatMessage({
- id: 'account.sheet.type.external',
- defaultMessage: 'External'
- })}
-
-
-
{mode === 'create' && (
-
- )}
- {mode === 'create' && (
- <>
+
+
+
+ {intl.formatMessage({
+ id: 'account.sheet.type.deposit',
+ defaultMessage: 'Deposit'
+ })}
+
+
+
+ {intl.formatMessage({
+ id: 'account.sheet.type.savings',
+ defaultMessage: 'Savings'
+ })}
+
+
+
+ {intl.formatMessage({
+ id: 'account.sheet.type.loans',
+ defaultMessage: 'Loans'
+ })}
+
+
+
+ {intl.formatMessage({
+ id: 'account.sheet.type.marketplace',
+ defaultMessage: 'Marketplace'
+ })}
+
+
+
+ {intl.formatMessage({
+ id: 'account.sheet.type.creditCard',
+ defaultMessage: 'CreditCard'
+ })}
+
+
+
+ {intl.formatMessage({
+ id: 'account.sheet.type.external',
+ defaultMessage: 'External'
+ })}
+
+
+
+
))}
- >
+
)}
@@ -458,6 +450,6 @@ export const AccountSheet = ({
- >
+
)
}
diff --git a/src/app/(routes)/ledgers/[id]/accounts-and-portfolios/accounts-content.tsx b/src/app/(routes)/ledgers/[id]/accounts/accounts-tab-content.tsx
similarity index 64%
rename from src/app/(routes)/ledgers/[id]/accounts-and-portfolios/accounts-content.tsx
rename to src/app/(routes)/ledgers/[id]/accounts/accounts-tab-content.tsx
index f7cc2008..e74e63ca 100644
--- a/src/app/(routes)/ledgers/[id]/accounts-and-portfolios/accounts-content.tsx
+++ b/src/app/(routes)/ledgers/[id]/accounts/accounts-tab-content.tsx
@@ -1,13 +1,11 @@
-import React, { useState, useMemo, useCallback } from 'react'
+import React, { useMemo } from 'react'
import { Button } from '@/components/ui/button'
-import { ChevronDown, ChevronUp, Plus } from 'lucide-react'
+import { Plus } from 'lucide-react'
import { useParams } from 'next/navigation'
import { EntityBox } from '@/components/entity-box'
import { useCreateUpdateSheet } from '@/components/sheet/use-create-update-sheet'
-import { useListPortfolios } from '@/client/portfolios'
import { useOrganization } from '@/context/organization-provider/organization-provider-client'
import { useIntl } from 'react-intl'
-import { isNil } from 'lodash'
import {
getCoreRowModel,
getFilteredRowModel,
@@ -15,47 +13,41 @@ import {
} from '@tanstack/react-table'
import { useConfirmDialog } from '@/components/confirmation-dialog/use-confirm-dialog'
import ConfirmationDialog from '@/components/confirmation-dialog'
-import { useAllPortfoliosAccounts, useDeleteAccount } from '@/client/accounts'
+import { useAccountsWithPortfolios, useDeleteAccount } from '@/client/accounts'
import { Skeleton } from '@/components/ui/skeleton'
import useCustomToast from '@/hooks/use-custom-toast'
import { AccountType } from '@/types/accounts-type'
import { AccountSheet } from './accounts-sheet'
import { AccountsDataTable } from './accounts-data-table'
-export const AccountsContent = () => {
+export const AccountsTabContent = () => {
const intl = useIntl()
const { id: ledgerId } = useParams<{ id: string }>()
const { currentOrganization } = useOrganization()
const [columnFilters, setColumnFilters] = React.useState([])
- const [isTableExpanded, setIsTableExpanded] = useState(false)
-
- const { data, refetch, isLoading } = useListPortfolios({
- organizationId: currentOrganization.id!,
- ledgerId: ledgerId
- })
const {
data: accountsData,
refetch: refetchAccounts,
isLoading: isAccountsLoading
- } = useAllPortfoliosAccounts({
+ } = useAccountsWithPortfolios({
organizationId: currentOrganization.id!,
ledgerId: ledgerId
})
- const accountsList = useMemo(
- () => ({
- items:
- accountsData?.items.flatMap((portfolio) =>
- portfolio.accounts.map((account) => ({
- ...account,
- portfolioName: portfolio.name,
- portfolioId: portfolio.id
- }))
- ) || []
- }),
- [accountsData]
- )
+ const accountsList: AccountType[] = useMemo(() => {
+ return (
+ accountsData?.items.map((account: any) => ({
+ ...account,
+ assetCode: account.assetCode,
+ parentAccountId: account.parentAccountId,
+ productId: account.productId,
+ metadata: account.metadata,
+ portfolioId: account.portfolio?.id,
+ portfolioName: account.portfolio?.name
+ })) || []
+ )
+ }, [accountsData])
const { showSuccess, showError } = useCustomToast()
@@ -73,7 +65,6 @@ export const AccountsContent = () => {
organizationId: currentOrganization.id!,
ledgerId,
accountId: selectedAccount?.id || '',
- portfolioId: selectedAccount?.portfolioId || '',
onSuccess: () => {
handleDialogClose()
refetchAccounts()
@@ -83,7 +74,7 @@ export const AccountsContent = () => {
id: 'ledgers.toast.accountDeleted',
defaultMessage: '{accountName} account successfully deleted'
},
- { accountName: (selectedAccount as AccountType)?.name! }
+ { accountName: selectedAccount?.name! }
)
)
},
@@ -104,18 +95,58 @@ export const AccountsContent = () => {
} = useCreateUpdateSheet()
const handleEdit = (account: AccountType) => {
- handleEditOriginal(account as unknown as AccountType)
+ handleEditOriginal(account)
}
const table = useReactTable({
- data: accountsList?.items!,
+ data: accountsList,
columns: [
- { accessorKey: 'id' },
- { accessorKey: 'name' },
- { accessorKey: 'assets' },
- { accessorKey: 'metadata' },
- { accessorKey: 'portfolio' },
- { accessorKey: 'actions' }
+ { accessorKey: 'id', header: 'ID' },
+ {
+ accessorKey: 'name',
+ header: intl.formatMessage({
+ id: 'entity.account.name',
+ defaultMessage: 'Account Name'
+ })
+ },
+ {
+ accessorKey: 'assetCode',
+ header: intl.formatMessage({
+ id: 'entity.account.currency',
+ defaultMessage: 'Assets'
+ }),
+ cell: (info) => info.getValue() || '-'
+ },
+ {
+ accessorKey: 'metadata',
+ header: intl.formatMessage({
+ id: 'common.metadata',
+ defaultMessage: 'Metadata'
+ }),
+ cell: (info) => {
+ const metadata = info.getValue() || {}
+ const count = Object.keys(metadata).length
+ return count > 0
+ ? `${count} ${intl.formatMessage({ id: 'common.records', defaultMessage: 'records' })}`
+ : '-'
+ }
+ },
+ {
+ accessorKey: 'portfolio.name',
+ header: intl.formatMessage({
+ id: 'common.portfolio',
+ defaultMessage: 'Portfolio'
+ }),
+ cell: (info) => info.getValue() || '-'
+ },
+ {
+ accessorKey: 'actions',
+ header: intl.formatMessage({
+ id: 'common.actions',
+ defaultMessage: 'Actions'
+ }),
+ cell: () => null
+ }
],
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
@@ -125,12 +156,12 @@ export const AccountsContent = () => {
}
})
- if (isLoading) {
+ if (isAccountsLoading) {
return
}
return (
- <>
+
{
@@ -157,15 +188,15 @@ export const AccountsContent = () => {
defaultMessage: 'Accounts'
})}
subtitle={
- accountsList?.items?.length !== undefined
+ accountsList.length !== undefined
? intl.formatMessage(
{
id: 'ledgers.accounts.subtitle',
defaultMessage:
- '{count} {count, plural, =0 {accounts found} one {acount found} other {accounts found}}'
+ '{count} {count, plural, =0 {accounts found} one {account found} other {accounts found}}'
},
{
- count: accountsList.items.length
+ count: accountsList.length
}
)
: undefined
@@ -175,9 +206,9 @@ export const AccountsContent = () => {
- {accountsList && accountsList.items.length > 0 ? (
+ {accountsList && accountsList.length > 0 ? (
) : (
<>
@@ -189,28 +220,19 @@ export const AccountsContent = () => {
>
)}
- {!isNil(accountsList?.items) && accountsList?.items?.length > 0 && (
- setIsTableExpanded(!isTableExpanded)}
- >
- {isTableExpanded ? : }
-
- )}
{accountsList && (
)}
- >
+
)
}
diff --git a/src/app/(routes)/ledgers/[id]/ledger-details-view.tsx b/src/app/(routes)/ledgers/[id]/ledger-details-view.tsx
index 07a0b486..222cdfc1 100644
--- a/src/app/(routes)/ledgers/[id]/ledger-details-view.tsx
+++ b/src/app/(routes)/ledgers/[id]/ledger-details-view.tsx
@@ -9,7 +9,6 @@ import { cn } from '@/lib/utils'
import { useFormState } from '@/context/form-details-context'
import { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/ui/tabs'
import { useIntl } from 'react-intl'
-import { AccountsPortfoliosTabContent } from './accounts-and-portfolios/accounts-portfolios-tab-content'
import { ProductsTabContent } from './products/products-tab-content'
import { useTabs } from '@/hooks/use-tabs'
import { getBreadcrumbPaths } from '@/components/breadcrumb/get-breadcrumb-paths'
@@ -19,12 +18,15 @@ import { useUpdateLedger } from '@/client/ledgers'
import { LedgerDetailsSkeleton } from './ledger-details-skeleton'
import { OverviewTabContent } from './overview/overview-tab-content'
import { AssetsTabContent } from './assets/assets-tab-content'
+import { PortfoliosTabContent } from './portfolios/portfolios-tab-content'
+import { AccountsTabContent } from './accounts/accounts-tab-content'
const TAB_VALUES = {
OVERVIEW: 'overview',
ASSETS: 'assets',
- PORTFOLIOS_AND_ACCOUNTS: 'portfolios-and-accounts',
- PRODUCTS: 'products'
+ PRODUCTS: 'products',
+ PORTFOLIOS: 'portfolios',
+ ACCOUNTS: 'accounts'
}
const DEFAULT_TAB_VALUE = TAB_VALUES.OVERVIEW
@@ -94,17 +96,24 @@ const LedgerDetailsView = ({ data }: LedgerDetailsViewProps) => {
},
{
name: intl.formatMessage({
- id: `ledgers.tab.portfolios-and-accounts`,
- defaultMessage: 'Portfolios and Accounts'
+ id: `settings.tab.products`,
+ defaultMessage: 'Products'
}),
- active: () => activeTab === TAB_VALUES.PORTFOLIOS_AND_ACCOUNTS
+ active: () => activeTab === TAB_VALUES.PRODUCTS
},
{
name: intl.formatMessage({
- id: `settings.tab.products`,
- defaultMessage: 'Products'
+ id: `settings.tab.portfolios`,
+ defaultMessage: 'Portfolios'
}),
- active: () => activeTab === TAB_VALUES.PRODUCTS
+ active: () => activeTab === TAB_VALUES.PORTFOLIOS
+ },
+ {
+ name: intl.formatMessage({
+ id: `ledgers.tab.accounts`,
+ defaultMessage: 'Accounts'
+ }),
+ active: () => activeTab === TAB_VALUES.ACCOUNTS
}
])
@@ -160,17 +169,24 @@ const LedgerDetailsView = ({ data }: LedgerDetailsViewProps) => {
})}
-
+
+ {intl.formatMessage({
+ id: 'ledgers.tab.products',
+ defaultMessage: 'Products'
+ })}
+
+
+
{intl.formatMessage({
- id: 'ledgers.tab.portfolios-and-accounts',
- defaultMessage: 'Portfolios and Accounts'
+ id: 'ledgers.tab.portfolios',
+ defaultMessage: 'Portfolios'
})}
-
+
{intl.formatMessage({
- id: 'ledgers.tab.products',
- defaultMessage: 'Products'
+ id: 'ledgers.tab.accounts',
+ defaultMessage: 'Accounts'
})}
@@ -183,13 +199,17 @@ const LedgerDetailsView = ({ data }: LedgerDetailsViewProps) => {
-
-
-
-
+
+
+
+
+
+
+
+
{
+ const intl = useIntl()
+ const { id: ledgerId } = useParams<{ id: string }>()
+ const { currentOrganization } = useOrganization()
+ const [columnFilters, setColumnFilters] = React.useState([])
+ const { showInfo } = useCustomToast()
+
+ const {
+ data: portfoliosData,
+ refetch,
+ isLoading
+ } = usePortfoliosWithAccounts({
+ organizationId: currentOrganization.id!,
+ ledgerId: ledgerId
+ })
+
+ const { mutate: deletePortfolio, isPending: deletePending } =
+ useDeletePortfolio({
+ organizationId: currentOrganization.id!,
+ ledgerId,
+ onSuccess: () => {
+ handleDialogClose()
+ refetch()
+ }
+ })
+
+ const { handleDialogOpen, dialogProps, handleDialogClose } = useConfirmDialog(
+ {
+ onConfirm: (id: string) => deletePortfolio({ id })
+ }
+ )
+
+ const { handleCreate, handleEdit, sheetProps } =
+ useCreateUpdateSheet()
+
+ const table = useReactTable({
+ data: portfoliosData?.items!,
+ columns: [
+ {
+ accessorKey: 'name'
+ }
+ ],
+ getCoreRowModel: getCoreRowModel(),
+ getFilteredRowModel: getFilteredRowModel(),
+ onColumnFiltersChange: setColumnFilters,
+ state: {
+ columnFilters
+ }
+ })
+
+ if (isLoading) {
+ return
+ }
+ const handleCopyToClipboard = (value: string, message: string) => {
+ navigator.clipboard.writeText(value)
+ showInfo(message)
+ }
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+ {portfoliosData?.items?.length ? (
+
+ ) : (
+
+ {intl.formatMessage({
+ id: `portfolio.create`,
+ defaultMessage: 'Create first portfolio'
+ })}
+
+
+ )}
+
+
+
+
+ {!isNil(portfoliosData?.items) && portfoliosData?.items.length > 0 && (
+
+
+
+
+
+ {intl.formatMessage({
+ id: 'common.id',
+ defaultMessage: 'ID'
+ })}
+
+
+ {intl.formatMessage({
+ id: 'common.name',
+ defaultMessage: 'Name'
+ })}
+
+
+ {intl.formatMessage({
+ id: 'common.metadata',
+ defaultMessage: 'Metadata'
+ })}
+
+
+ {intl.formatMessage({
+ id: 'common.accounts',
+ defaultMessage: 'Accounts'
+ })}
+
+
+ {intl.formatMessage({
+ id: 'common.actions',
+ defaultMessage: 'Actions'
+ })}
+
+
+
+
+ {table.getRowModel().rows.map((portfolio) => {
+ const metadataCount = Object.entries(
+ portfolio.original.metadata || []
+ ).length
+ const displayId =
+ portfolio.original.id && portfolio.original.id.length > 8
+ ? `${truncateString(portfolio.original.id, 8)}`
+ : portfolio.original.id
+
+ return (
+
+
+
+
+
+ handleCopyToClipboard(
+ portfolio.original.id,
+ intl.formatMessage({
+ id: 'ledgers.toast.copyId',
+ defaultMessage:
+ 'The id has been copied to your clipboard.'
+ })
+ )
+ }
+ >
+
+ {displayId}
+
+
+
+
+ {portfolio.original.id}
+
+
+ {intl.formatMessage({
+ id: 'ledgers.columnsTable.tooltipCopyText',
+ defaultMessage: 'Click to copy'
+ })}
+
+
+
+
+
+
+ {portfolio.original.name}
+
+ {metadataCount === 0 ? (
+
+ ) : (
+ intl.formatMessage(
+ {
+ id: 'common.table.metadata',
+ defaultMessage:
+ '{number, plural, =0 {-} one {# record} other {# records}}'
+ },
+ {
+ number: metadataCount
+ }
+ )
+ )}
+
+
+ {intl.formatMessage(
+ {
+ id: 'common.table.accounts',
+ defaultMessage:
+ '{number, plural, =0 {No accounts} one {# account} other {# accounts}}'
+ },
+ {
+ number: portfolio.original.accounts?.length || 0
+ }
+ )}
+
+
+
+
+
+
+ {}} />
+
+
+
+
+ handleEdit({
+ ...portfolio.original,
+ entityId: portfolio.original.id,
+ status: {
+ ...portfolio.original.status,
+ description:
+ portfolio.original.status.description ?? ''
+ }
+ } as PortfolioResponseDto)
+ }
+ >
+ {intl.formatMessage({
+ id: `common.edit`,
+ defaultMessage: 'Edit'
+ })}
+
+
+ {
+ handleDialogOpen(portfolio?.original?.id!)
+ }}
+ >
+ {intl.formatMessage({
+ id: `common.delete`,
+ defaultMessage: 'Delete'
+ })}
+
+
+
+
+
+ )
+ })}
+
+
+
+ )}
+ >
+ )
+}
diff --git a/src/app/(routes)/ledgers/ledgers-sheet.tsx b/src/app/(routes)/ledgers/ledgers-sheet.tsx
index fea264fc..d463595e 100644
--- a/src/app/(routes)/ledgers/ledgers-sheet.tsx
+++ b/src/app/(routes)/ledgers/ledgers-sheet.tsx
@@ -1,7 +1,6 @@
import { InputField } from '@/components/form'
import { MetadataField } from '@/components/form/metadata-field'
import { Form } from '@/components/ui/form'
-import { Label } from '@/components/ui/label'
import {
Sheet,
SheetContent,
@@ -10,7 +9,6 @@ import {
SheetHeader,
SheetTitle
} from '@/components/ui/sheet'
-import { Switch } from '@/components/ui/switch'
import { ledger } from '@/schema/ledger'
import { zodResolver } from '@hookform/resolvers/zod'
import { DialogProps } from '@radix-ui/react-dialog'
@@ -25,6 +23,7 @@ import { LedgerResponseDto } from '@/core/application/dto/ledger-response-dto'
import { useOrganization } from '@/context/organization-provider/organization-provider-client'
import useCustomToast from '@/hooks/use-custom-toast'
import { ILedgerType } from '@/types/ledgers-type'
+import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
export type LedgersSheetProps = DialogProps & {
mode: 'create' | 'edit'
@@ -87,10 +86,6 @@ export const LedgersSheet = ({
defaultValues: Object.assign({}, defaultValues, ledger)
})
- const [metadataEnabled, setMetadataEnabled] = React.useState(
- Object.entries(ledger?.metadata || {}).length > 0
- )
-
const handleSubmit = (data: FormData) => {
if (mode === 'create') {
createLedger(data)
@@ -107,10 +102,7 @@ export const LedgersSheet = ({
React.useEffect(() => {
if (!isNil(data)) {
- setMetadataEnabled(Object.entries(data.metadata).length > 0)
form.reset(data, { keepDefaultValues: true })
- } else {
- setMetadataEnabled(false)
}
}, [data])
@@ -137,47 +129,48 @@ export const LedgersSheet = ({