diff --git a/CHANGELOG.md b/CHANGELOG.md index 655ea53b..5a74ca8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [Added the Storybook as a live server deployment](https://github.com/multiversx/mx-sdk-dapp-ui/pull/248) +- [Refactor components in transactions table](https://github.com/multiversx/mx-sdk-dapp-ui/pull/243) + ## [[0.0.35](https://github.com/multiversx/mx-sdk-dapp-ui/pull/246)] - 2025-10-10 - [Added passkey provider](https://github.com/multiversx/mx-sdk-dapp-ui/pull/242) diff --git a/package.json b/package.json index b2be7b08..e14b7ab0 100644 --- a/package.json +++ b/package.json @@ -132,4 +132,4 @@ "typescript": "^5.7.3", "vite": "^7.0.6" } -} +} \ No newline at end of file diff --git a/src/common/Icon/icon.types.ts b/src/common/Icon/icon.types.ts index ce81757d..89325ba1 100644 --- a/src/common/Icon/icon.types.ts +++ b/src/common/Icon/icon.types.ts @@ -25,7 +25,6 @@ export enum IconNameEnum { circleInfo = 'circle-info', coins = 'coins', arrowsRotate = 'arrows-rotate' - } export type IconPropsType = JSXBase.IntrinsicElements['svg'] & { diff --git a/src/components.d.ts b/src/components.d.ts index 6367766b..f566913c 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -11,12 +11,11 @@ import { CustomToastType, IComponentToast, ISimpleToast } from "./components/fun import { IConfirmScreenData, IConnectScreenData, ILedgerConnectPanelData } from "./components/functional/ledger-connect/ledger-connect.types"; import { IEventBus } from "./utils/EventBus"; import { DecodeMethodEnum } from "./components/functional/sign-transactions-panel/sign-transactions-panel.types"; -import { TransactionAccountType, TransactionIconInfoType, TransactionRowType } from "./components/controlled/transactions-table/transactions-table.type"; import { ITransactionListItem } from "./components/visual/transaction-list-item/transaction-list-item.types"; import { LocalJSX as JSX } from "@stencil/core"; import { ITransactionListItem as ITransactionListItem1 } from "./components/visual/transaction-list-item/transaction-list-item.types"; import { IToastDataState, ITransactionProgressState } from "./components/functional/toasts-list/components/transaction-toast/transaction-toast.type"; -import { TransactionValueType } from "./components/controlled/transactions-table/transactions-table.type"; +import { TransactionRowType } from "./components/controlled/transactions-table/transactions-table.type"; import { IProviderBase, ProviderTypeEnum } from "./types/provider.types"; import { IEventBus as IEventBus1, unknown as IWalletConnectPanelData } from "./components.d"; export { IAddressTableData } from "./types/address-table.types"; @@ -25,12 +24,11 @@ export { CustomToastType, IComponentToast, ISimpleToast } from "./components/fun export { IConfirmScreenData, IConnectScreenData, ILedgerConnectPanelData } from "./components/functional/ledger-connect/ledger-connect.types"; export { IEventBus } from "./utils/EventBus"; export { DecodeMethodEnum } from "./components/functional/sign-transactions-panel/sign-transactions-panel.types"; -export { TransactionAccountType, TransactionIconInfoType, TransactionRowType } from "./components/controlled/transactions-table/transactions-table.type"; export { ITransactionListItem } from "./components/visual/transaction-list-item/transaction-list-item.types"; export { LocalJSX as JSX } from "@stencil/core"; export { ITransactionListItem as ITransactionListItem1 } from "./components/visual/transaction-list-item/transaction-list-item.types"; export { IToastDataState, ITransactionProgressState } from "./components/functional/toasts-list/components/transaction-toast/transaction-toast.type"; -export { TransactionValueType } from "./components/controlled/transactions-table/transactions-table.type"; +export { TransactionRowType } from "./components/controlled/transactions-table/transactions-table.type"; export { IProviderBase, ProviderTypeEnum } from "./types/provider.types"; export { IEventBus as IEventBus1, unknown as IWalletConnectPanelData } from "./components.d"; export namespace Components { @@ -321,52 +319,9 @@ export namespace Components { */ "triggerOnClick"?: boolean; } - interface MvxTransactionAccount { - "account": TransactionAccountType; - "class"?: string; - "dataTestId"?: string; - "scope": 'receiver' | 'sender'; - /** - * @default false - */ - "showLockedAccounts": boolean; - } - interface MvxTransactionAccountName { - "address": string; - "class"?: string; - "dataTestId"?: string; - "description": string; - "name"?: string; - } - interface MvxTransactionAge { - "age": string; - "class"?: string; - "tooltip"?: string; - } - interface MvxTransactionDirectionBadge { - "class"?: string; - "direction": string; - } - interface MvxTransactionHash { - "class"?: string; - "transaction": TransactionRowType; - } - interface MvxTransactionIcon { - "class"?: string; - "iconInfo": TransactionIconInfoType; - } interface MvxTransactionListItem { "transaction": ITransactionListItem; } - interface MvxTransactionMethod { - "actionDescription": string; - "class"?: string; - "method": string; - } - interface MvxTransactionShards { - "class"?: string; - "transaction": TransactionRowType; - } interface MvxTransactionToast { "fullWidth"?: boolean; /** @@ -415,10 +370,6 @@ export namespace Components { "isStatusPending"?: boolean; "startTime"?: number; } - interface MvxTransactionValue { - "class"?: string; - "value": TransactionValueType; - } interface MvxTransactionsTable { "class"?: string; "transactions": TransactionRowType[]; @@ -988,60 +939,12 @@ declare global { prototype: HTMLMvxTooltipElement; new (): HTMLMvxTooltipElement; }; - interface HTMLMvxTransactionAccountElement extends Components.MvxTransactionAccount, HTMLStencilElement { - } - var HTMLMvxTransactionAccountElement: { - prototype: HTMLMvxTransactionAccountElement; - new (): HTMLMvxTransactionAccountElement; - }; - interface HTMLMvxTransactionAccountNameElement extends Components.MvxTransactionAccountName, HTMLStencilElement { - } - var HTMLMvxTransactionAccountNameElement: { - prototype: HTMLMvxTransactionAccountNameElement; - new (): HTMLMvxTransactionAccountNameElement; - }; - interface HTMLMvxTransactionAgeElement extends Components.MvxTransactionAge, HTMLStencilElement { - } - var HTMLMvxTransactionAgeElement: { - prototype: HTMLMvxTransactionAgeElement; - new (): HTMLMvxTransactionAgeElement; - }; - interface HTMLMvxTransactionDirectionBadgeElement extends Components.MvxTransactionDirectionBadge, HTMLStencilElement { - } - var HTMLMvxTransactionDirectionBadgeElement: { - prototype: HTMLMvxTransactionDirectionBadgeElement; - new (): HTMLMvxTransactionDirectionBadgeElement; - }; - interface HTMLMvxTransactionHashElement extends Components.MvxTransactionHash, HTMLStencilElement { - } - var HTMLMvxTransactionHashElement: { - prototype: HTMLMvxTransactionHashElement; - new (): HTMLMvxTransactionHashElement; - }; - interface HTMLMvxTransactionIconElement extends Components.MvxTransactionIcon, HTMLStencilElement { - } - var HTMLMvxTransactionIconElement: { - prototype: HTMLMvxTransactionIconElement; - new (): HTMLMvxTransactionIconElement; - }; interface HTMLMvxTransactionListItemElement extends Components.MvxTransactionListItem, HTMLStencilElement { } var HTMLMvxTransactionListItemElement: { prototype: HTMLMvxTransactionListItemElement; new (): HTMLMvxTransactionListItemElement; }; - interface HTMLMvxTransactionMethodElement extends Components.MvxTransactionMethod, HTMLStencilElement { - } - var HTMLMvxTransactionMethodElement: { - prototype: HTMLMvxTransactionMethodElement; - new (): HTMLMvxTransactionMethodElement; - }; - interface HTMLMvxTransactionShardsElement extends Components.MvxTransactionShards, HTMLStencilElement { - } - var HTMLMvxTransactionShardsElement: { - prototype: HTMLMvxTransactionShardsElement; - new (): HTMLMvxTransactionShardsElement; - }; interface HTMLMvxTransactionToastElementEventMap { "deleteToast": void; } @@ -1094,12 +997,6 @@ declare global { prototype: HTMLMvxTransactionToastProgressElement; new (): HTMLMvxTransactionToastProgressElement; }; - interface HTMLMvxTransactionValueElement extends Components.MvxTransactionValue, HTMLStencilElement { - } - var HTMLMvxTransactionValueElement: { - prototype: HTMLMvxTransactionValueElement; - new (): HTMLMvxTransactionValueElement; - }; interface HTMLMvxTransactionsTableElement extends Components.MvxTransactionsTable, HTMLStencilElement { } var HTMLMvxTransactionsTableElement: { @@ -1266,21 +1163,12 @@ declare global { "mvx-spinner-icon": HTMLMvxSpinnerIconElement; "mvx-toast-list": HTMLMvxToastListElement; "mvx-tooltip": HTMLMvxTooltipElement; - "mvx-transaction-account": HTMLMvxTransactionAccountElement; - "mvx-transaction-account-name": HTMLMvxTransactionAccountNameElement; - "mvx-transaction-age": HTMLMvxTransactionAgeElement; - "mvx-transaction-direction-badge": HTMLMvxTransactionDirectionBadgeElement; - "mvx-transaction-hash": HTMLMvxTransactionHashElement; - "mvx-transaction-icon": HTMLMvxTransactionIconElement; "mvx-transaction-list-item": HTMLMvxTransactionListItemElement; - "mvx-transaction-method": HTMLMvxTransactionMethodElement; - "mvx-transaction-shards": HTMLMvxTransactionShardsElement; "mvx-transaction-toast": HTMLMvxTransactionToastElement; "mvx-transaction-toast-content": HTMLMvxTransactionToastContentElement; "mvx-transaction-toast-details": HTMLMvxTransactionToastDetailsElement; "mvx-transaction-toast-details-body": HTMLMvxTransactionToastDetailsBodyElement; "mvx-transaction-toast-progress": HTMLMvxTransactionToastProgressElement; - "mvx-transaction-value": HTMLMvxTransactionValueElement; "mvx-transactions-table": HTMLMvxTransactionsTableElement; "mvx-trim": HTMLMvxTrimElement; "mvx-unlock-button": HTMLMvxUnlockButtonElement; @@ -1594,52 +1482,9 @@ declare namespace LocalJSX { */ "triggerOnClick"?: boolean; } - interface MvxTransactionAccount { - "account"?: TransactionAccountType; - "class"?: string; - "dataTestId"?: string; - "scope"?: 'receiver' | 'sender'; - /** - * @default false - */ - "showLockedAccounts"?: boolean; - } - interface MvxTransactionAccountName { - "address"?: string; - "class"?: string; - "dataTestId"?: string; - "description"?: string; - "name"?: string; - } - interface MvxTransactionAge { - "age"?: string; - "class"?: string; - "tooltip"?: string; - } - interface MvxTransactionDirectionBadge { - "class"?: string; - "direction"?: string; - } - interface MvxTransactionHash { - "class"?: string; - "transaction"?: TransactionRowType; - } - interface MvxTransactionIcon { - "class"?: string; - "iconInfo"?: TransactionIconInfoType; - } interface MvxTransactionListItem { "transaction"?: ITransactionListItem; } - interface MvxTransactionMethod { - "actionDescription"?: string; - "class"?: string; - "method"?: string; - } - interface MvxTransactionShards { - "class"?: string; - "transaction"?: TransactionRowType; - } interface MvxTransactionToast { "fullWidth"?: boolean; "onDeleteToast"?: (event: MvxTransactionToastCustomEvent) => void; @@ -1690,10 +1535,6 @@ declare namespace LocalJSX { "isStatusPending"?: boolean; "startTime"?: number; } - interface MvxTransactionValue { - "class"?: string; - "value"?: TransactionValueType; - } interface MvxTransactionsTable { "class"?: string; "transactions"?: TransactionRowType[]; @@ -1825,21 +1666,12 @@ declare namespace LocalJSX { "mvx-spinner-icon": MvxSpinnerIcon; "mvx-toast-list": MvxToastList; "mvx-tooltip": MvxTooltip; - "mvx-transaction-account": MvxTransactionAccount; - "mvx-transaction-account-name": MvxTransactionAccountName; - "mvx-transaction-age": MvxTransactionAge; - "mvx-transaction-direction-badge": MvxTransactionDirectionBadge; - "mvx-transaction-hash": MvxTransactionHash; - "mvx-transaction-icon": MvxTransactionIcon; "mvx-transaction-list-item": MvxTransactionListItem; - "mvx-transaction-method": MvxTransactionMethod; - "mvx-transaction-shards": MvxTransactionShards; "mvx-transaction-toast": MvxTransactionToast; "mvx-transaction-toast-content": MvxTransactionToastContent; "mvx-transaction-toast-details": MvxTransactionToastDetails; "mvx-transaction-toast-details-body": MvxTransactionToastDetailsBody; "mvx-transaction-toast-progress": MvxTransactionToastProgress; - "mvx-transaction-value": MvxTransactionValue; "mvx-transactions-table": MvxTransactionsTable; "mvx-trim": MvxTrim; "mvx-unlock-button": MvxUnlockButton; @@ -1909,21 +1741,12 @@ declare module "@stencil/core" { "mvx-spinner-icon": LocalJSX.MvxSpinnerIcon & JSXBase.HTMLAttributes; "mvx-toast-list": LocalJSX.MvxToastList & JSXBase.HTMLAttributes; "mvx-tooltip": LocalJSX.MvxTooltip & JSXBase.HTMLAttributes; - "mvx-transaction-account": LocalJSX.MvxTransactionAccount & JSXBase.HTMLAttributes; - "mvx-transaction-account-name": LocalJSX.MvxTransactionAccountName & JSXBase.HTMLAttributes; - "mvx-transaction-age": LocalJSX.MvxTransactionAge & JSXBase.HTMLAttributes; - "mvx-transaction-direction-badge": LocalJSX.MvxTransactionDirectionBadge & JSXBase.HTMLAttributes; - "mvx-transaction-hash": LocalJSX.MvxTransactionHash & JSXBase.HTMLAttributes; - "mvx-transaction-icon": LocalJSX.MvxTransactionIcon & JSXBase.HTMLAttributes; "mvx-transaction-list-item": LocalJSX.MvxTransactionListItem & JSXBase.HTMLAttributes; - "mvx-transaction-method": LocalJSX.MvxTransactionMethod & JSXBase.HTMLAttributes; - "mvx-transaction-shards": LocalJSX.MvxTransactionShards & JSXBase.HTMLAttributes; "mvx-transaction-toast": LocalJSX.MvxTransactionToast & JSXBase.HTMLAttributes; "mvx-transaction-toast-content": LocalJSX.MvxTransactionToastContent & JSXBase.HTMLAttributes; "mvx-transaction-toast-details": LocalJSX.MvxTransactionToastDetails & JSXBase.HTMLAttributes; "mvx-transaction-toast-details-body": LocalJSX.MvxTransactionToastDetailsBody & JSXBase.HTMLAttributes; "mvx-transaction-toast-progress": LocalJSX.MvxTransactionToastProgress & JSXBase.HTMLAttributes; - "mvx-transaction-value": LocalJSX.MvxTransactionValue & JSXBase.HTMLAttributes; "mvx-transactions-table": LocalJSX.MvxTransactionsTable & JSXBase.HTMLAttributes; "mvx-trim": LocalJSX.MvxTrim & JSXBase.HTMLAttributes; "mvx-unlock-button": LocalJSX.MvxUnlockButton & JSXBase.HTMLAttributes; diff --git a/src/components/controlled/transactions-table/components/TransactionAccount/TransactionAccount.tsx b/src/components/controlled/transactions-table/components/TransactionAccount/TransactionAccount.tsx new file mode 100644 index 00000000..1627e81c --- /dev/null +++ b/src/components/controlled/transactions-table/components/TransactionAccount/TransactionAccount.tsx @@ -0,0 +1,52 @@ +import { h } from '@stencil/core'; +import { Icon } from 'common/Icon'; +import { DataTestIdsEnum } from 'constants/dataTestIds.enum'; + +import type { TransactionAccountType } from '../../transactions-table.type'; +import { TransactionAccountName } from './components'; + +// prettier-ignore +const styles = { + transactionAccount: 'transaction-account mvx:flex mvx:items-center mvx:gap-2', + transactionAccountExplorerLink: 'transaction-account-explorer-link mvx:text-primary!' +} satisfies Record; + +interface TransactionAccountPropsType { + account: TransactionAccountType; + class?: string; + dataTestId?: string; + scope: 'receiver' | 'sender'; + showLockedAccounts: boolean; +} + +export function TransactionAccount({ account, dataTestId, scope, showLockedAccounts = false, class: className }: TransactionAccountPropsType) { + const explorerLinkDataTestId = + scope === 'receiver' ? DataTestIdsEnum.receiverLink : DataTestIdsEnum.senderLink; + + return ( +
+ {showLockedAccounts && account.isTokenLocked && } + {account.isContract && } + + {account.showLink ? ( + + {account.address} + + ) : ( + + )} +
+ ); +} + diff --git a/src/components/controlled/transactions-table/components/TransactionAccount/components/TransactionAccountName/TransactionAccountName.tsx b/src/components/controlled/transactions-table/components/TransactionAccount/components/TransactionAccountName/TransactionAccountName.tsx new file mode 100644 index 00000000..10171a5e --- /dev/null +++ b/src/components/controlled/transactions-table/components/TransactionAccount/components/TransactionAccountName/TransactionAccountName.tsx @@ -0,0 +1,38 @@ +import { h } from '@stencil/core'; +import classNames from 'classnames'; + +// prettier-ignore +const styles = { + transactionAccountName: 'transaction-account-name mvx:w-max mvx:truncate' +} satisfies Record; + +interface TransactionAccountNamePropsType { + address: string; + class?: string; + dataTestId?: string; + description: string; + name?: string; +} + +export function TransactionAccountName({ address, dataTestId, description, name, class: className }: TransactionAccountNamePropsType) { + if (name) { + return ( +
+ {name} +
+ ); + } + + return ( + + ); + +} diff --git a/src/components/controlled/transactions-table/components/TransactionAccount/components/TransactionAccountName/index.ts b/src/components/controlled/transactions-table/components/TransactionAccount/components/TransactionAccountName/index.ts new file mode 100644 index 00000000..0f89d2cc --- /dev/null +++ b/src/components/controlled/transactions-table/components/TransactionAccount/components/TransactionAccountName/index.ts @@ -0,0 +1 @@ +export * from './TransactionAccountName' \ No newline at end of file diff --git a/src/components/controlled/transactions-table/components/TransactionAccount/components/TransactionAccountName/tests/transaction-account-name.spec.tsx b/src/components/controlled/transactions-table/components/TransactionAccount/components/TransactionAccountName/tests/transaction-account-name.spec.tsx new file mode 100644 index 00000000..85e4a4cf --- /dev/null +++ b/src/components/controlled/transactions-table/components/TransactionAccount/components/TransactionAccountName/tests/transaction-account-name.spec.tsx @@ -0,0 +1,116 @@ +import { h } from '@stencil/core'; +import { newSpecPage } from '@stencil/core/testing'; +import { TransactionAccountName } from '../TransactionAccountName'; + +describe('TransactionAccountName tests', () => { + it('renders name when provided', async () => { + const page = await newSpecPage({ + components: [], + template: () => ( + + ), + }); + + expect(page.root).toEqualHtml(` + + `); + }); + + it('uses trim component when name is missing', async () => { + const page = await newSpecPage({ + components: [], + template: () => ( + + ) + }); + + expect(page.root).toEqualHtml(` + + `); + }); + + it('handles empty name string', async () => { + const page = await newSpecPage({ + components: [], + template: () => ( + + ) + }); + + expect(page.root).toEqualHtml(` + + `); + }); + + it('applies correct class names', async () => { + const page = await newSpecPage({ + components: [], + template: () => ( + + ) + }); + + expect(page.root).toEqualHtml(` + + `); + }); + + it('handles missing dataTestId', async () => { + const page = await newSpecPage({ + components: [], + template: () => ( + + ) + }); + + expect(page.root).toEqualHtml(` + + `); + }); + + it('uses description as title when name exists', async () => { + const page = await newSpecPage({ + components: [TransactionAccountName], + template: () => ( + + ) + }); + + expect(page.root).toEqualHtml(` + + `); + }) +}); diff --git a/src/components/controlled/transactions-table/components/TransactionAccount/components/index.ts b/src/components/controlled/transactions-table/components/TransactionAccount/components/index.ts new file mode 100644 index 00000000..0f89d2cc --- /dev/null +++ b/src/components/controlled/transactions-table/components/TransactionAccount/components/index.ts @@ -0,0 +1 @@ +export * from './TransactionAccountName' \ No newline at end of file diff --git a/src/components/controlled/transactions-table/components/TransactionAccount/index.ts b/src/components/controlled/transactions-table/components/TransactionAccount/index.ts new file mode 100644 index 00000000..4ccfa2e8 --- /dev/null +++ b/src/components/controlled/transactions-table/components/TransactionAccount/index.ts @@ -0,0 +1 @@ +export * from './TransactionAccount' \ No newline at end of file diff --git a/src/components/controlled/transactions-table/components/TransactionAccount/tests/transaction-account.spec.tsx b/src/components/controlled/transactions-table/components/TransactionAccount/tests/transaction-account.spec.tsx new file mode 100644 index 00000000..eb6efeb5 --- /dev/null +++ b/src/components/controlled/transactions-table/components/TransactionAccount/tests/transaction-account.spec.tsx @@ -0,0 +1,112 @@ +import { h } from '@stencil/core'; +import { newSpecPage } from '@stencil/core/testing'; + +import type { TransactionAccountType } from '../../../transactions-table.type'; +import { TransactionAccount } from '../TransactionAccount'; + +describe('TransactionAccount tests', () => { + const baseAccount: TransactionAccountType = { + address: '0x1234567890123456789012345678901234567890', + name: 'John Doe', + description: 'Test Account', + isContract: false, + isTokenLocked: false, + link: 'https://example.com/account/0x1234567890123456789012345678901234567890', + showLink: false, + }; + + it('should render basic account information', async () => { + const page = await newSpecPage({ + components: [], + template: () => , + }); + + expect(page.root).toEqualHtml(` + + `); + }); + + it('should render locked account icon when showLockedAccounts is true and account is locked', async () => { + const lockedAccount: TransactionAccountType = { ...baseAccount, isTokenLocked: true }; + + const page = await newSpecPage({ + components: [], + template: () => , + }); + + expect(page.root).toEqualHtml(` + + `); + }); + + it('should render contract icon when account is a contract', async () => { + const contractAccount: TransactionAccountType = { ...baseAccount, isContract: true }; + + const page = await newSpecPage({ + components: [], + template: () => , + }); + + expect(page.root).toEqualHtml(` + + `); + }); + + it('should render explorer link when showLink is true', async () => { + const linkedAccount: TransactionAccountType = { ...baseAccount, showLink: true }; + + const page = await newSpecPage({ + components: [], + template: () => , + }); + + expect(page.root).toEqualHtml(` + + `); + }); + + it('should apply custom class and data-testid', async () => { + const page = await newSpecPage({ + components: [], + template: () => ( + + ), + }); + + expect(page.root).toEqualHtml(` + + `); + }); +}); diff --git a/src/components/controlled/transactions-table/components/TransactionAge/TransactionAge.tsx b/src/components/controlled/transactions-table/components/TransactionAge/TransactionAge.tsx new file mode 100644 index 00000000..67befb52 --- /dev/null +++ b/src/components/controlled/transactions-table/components/TransactionAge/TransactionAge.tsx @@ -0,0 +1,34 @@ +import { h } from '@stencil/core'; +import { DataTestIdsEnum } from 'constants/dataTestIds.enum'; + +// prettier-ignore +const styles = { + transactionAge: 'transaction-age mvx:w-max' +} satisfies Record; + +interface TransactionAgePropsType { + age: string; + class?: string; + tooltip?: string; +} + +export function TransactionAge({ age, tooltip, class: className }: TransactionAgePropsType) { + const component = tooltip ? ( +
+ {age} +
+ ) : ( +
+ {age} +
+ ); + + return
{component}
; +} diff --git a/src/components/controlled/transactions-table/components/TransactionAge/index.ts b/src/components/controlled/transactions-table/components/TransactionAge/index.ts new file mode 100644 index 00000000..fcb2deab --- /dev/null +++ b/src/components/controlled/transactions-table/components/TransactionAge/index.ts @@ -0,0 +1 @@ +export * from './TransactionAge'; \ No newline at end of file diff --git a/src/components/controlled/transactions-table/components/TransactionAge/tests/transaction-age.spec.tsx b/src/components/controlled/transactions-table/components/TransactionAge/tests/transaction-age.spec.tsx new file mode 100644 index 00000000..3354fc1b --- /dev/null +++ b/src/components/controlled/transactions-table/components/TransactionAge/tests/transaction-age.spec.tsx @@ -0,0 +1,40 @@ +import { h } from '@stencil/core'; +import { newSpecPage } from '@stencil/core/testing'; +import { DataTestIdsEnum } from 'constants/dataTestIds.enum'; +import { TransactionAge } from '../TransactionAge'; + + +describe('TransactionAge tests', () => { + it('renders with age prop', async () => { + const page = await newSpecPage({ + components: [], + template: () => + }); + + const ageSpan = page.root.querySelector(`[data-testid="${DataTestIdsEnum.transactionAge}"]`); + expect(ageSpan).not.toBeNull(); + expect(ageSpan.textContent).toBe('2 days ago'); + }); + + it('renders without tooltip when not provided', async () => { + const page = await newSpecPage({ + components: [], + template: () => + }); + + const ageSpan = page.root.querySelector(`[data-testid="${DataTestIdsEnum.transactionAge}"]`); + expect(ageSpan).not.toBeNull(); + expect(ageSpan.getAttribute('title')).toBeNull(); + }); + + it('renders with tooltip when provided', async () => { + const page = await newSpecPage({ + components: [], + template: () => + }); + + const ageSpan = page.root.querySelector(`[data-testid="${DataTestIdsEnum.transactionAge}"]`); + expect(ageSpan).not.toBeNull(); + expect(ageSpan.getAttribute('title')).toBe('2023-05-17 10:30:00 UTC'); + }); +}); diff --git a/src/components/controlled/transactions-table/components/TransactionHash/TransactionHash.tsx b/src/components/controlled/transactions-table/components/TransactionHash/TransactionHash.tsx new file mode 100644 index 00000000..fe2d0bc8 --- /dev/null +++ b/src/components/controlled/transactions-table/components/TransactionHash/TransactionHash.tsx @@ -0,0 +1,43 @@ +import { h } from '@stencil/core'; +import { DataTestIdsEnum } from 'constants/dataTestIds.enum'; + +import type { TransactionRowType } from '../../transactions-table.type'; +import { TransactionIcon } from '../TransactionIcon'; + +// prettier-ignore +const styles = { + transactionHash: 'transaction-hash mvx:flex mvx:gap-1 mvx:items-center mvx:justify-center', + transactionHashExplorerLink: 'transaction-hash-explorer-link mvx:text-primary!', + transactionHashIcon: 'transaction-hash-icon mvx:flex mvx:items-center mvx:justify-center', +} satisfies Record; + +interface TransactionHashPropsType { + class?: string; + transaction: TransactionRowType; +} + +export function TransactionHash({ transaction, class: className }: TransactionHashPropsType) { + if (!transaction) { + return null; + } + + return ( +
+ + + + + +
+ ); + +} diff --git a/src/components/controlled/transactions-table/components/TransactionHash/index.ts b/src/components/controlled/transactions-table/components/TransactionHash/index.ts new file mode 100644 index 00000000..3b8611a9 --- /dev/null +++ b/src/components/controlled/transactions-table/components/TransactionHash/index.ts @@ -0,0 +1 @@ +export * from './TransactionHash' \ No newline at end of file diff --git a/src/components/controlled/transactions-table/components/TransactionHash/tests/transaction-hash.spec.tsx b/src/components/controlled/transactions-table/components/TransactionHash/tests/transaction-hash.spec.tsx new file mode 100644 index 00000000..3e72b346 --- /dev/null +++ b/src/components/controlled/transactions-table/components/TransactionHash/tests/transaction-hash.spec.tsx @@ -0,0 +1,143 @@ +import { h } from '@stencil/core'; +import { newSpecPage } from '@stencil/core/testing'; +import { DataTestIdsEnum } from 'constants/dataTestIds.enum'; + +import type { TransactionAccountType, TransactionRowType } from '../../../transactions-table.type'; +import { TransactionHash } from '../TransactionHash'; + +const account: TransactionAccountType = { + address: 'erd...', + name: 'test', + description: 'test', + isContract: false, + isTokenLocked: false, + link: '/test', + showLink: false, + shard: '0', + shardLink: '/shard/0', +}; + +describe('TransactionHash tests', () => { + it('renders with transaction data', async () => { + const transaction: TransactionRowType = { + age: { + timeAgo: '1h', + tooltip: '1 hour ago', + }, + direction: 'in', + iconInfo: { icon: 'circle-info', tooltip: 'Test' }, + link: 'https://example.com/tx/123', + method: { + name: 'Smart Contract', + actionDescription: 'Contract call', + }, + receiver: account, + sender: account, + txHash: '0x123456789abcdef', + value: { + egldLabel: 'xEGLD', + valueDecimal: '0', + valueInteger: '100', + }, + }; + + const page = await newSpecPage({ + components: [], + template: () => , + }); + + expect(page.root).toEqualHtml(` +
+ + + + +
+ `); + }); + + it('updates when transaction prop changes', async () => { + const initialTransactionData: TransactionRowType = { + age: { + timeAgo: '1h', + tooltip: '1 hour ago', + }, + direction: 'in', + iconInfo: { icon: 'circle-Info', tooltip: 'Initial' }, + link: 'https://example.com/tx/initial', + method: { + name: 'Smart Contract', + actionDescription: 'Initial call', + }, + receiver: account, + sender: account, + txHash: '0xInitialHash', + value: { + egldLabel: 'xEGLD', + valueDecimal: '0', + valueInteger: '100', + }, + }; + + const page = await newSpecPage({ + components: [], + template: () => , + }); + + expect(page.root).toEqualHtml(` +
+ +
+ `); + }); + + it('renders with updated transaction data', async () => { + const updatedTransactionData: TransactionRowType = { + age: { + timeAgo: '2h', + tooltip: '2 hours ago', + }, + direction: 'out', + iconInfo: { icon: 'circle-check', tooltip: 'Updated' }, + link: 'https://example.com/tx/updated', + method: { + name: 'Transfer', + actionDescription: 'Token transfer', + }, + receiver: account, + sender: account, + txHash: '0xUpdatedHash', + value: { + egldLabel: 'xEGLD', + valueDecimal: '1', + valueInteger: '200', + }, + }; + + const page = await newSpecPage({ + components: [], + template: () => , + }); + + expect(page.root).toEqualHtml(` +
+ + + + +
+ `); + }); + + it('renders null when transaction is not provided', async () => { + const page = await newSpecPage({ + components: [TransactionHash], + template: () => , + }); + + expect(page.root).toEqualHtml(` + + + `); + }); +}); diff --git a/src/components/controlled/transactions-table/components/TransactionIcon/TransactionIcon.tsx b/src/components/controlled/transactions-table/components/TransactionIcon/TransactionIcon.tsx new file mode 100644 index 00000000..9a82d123 --- /dev/null +++ b/src/components/controlled/transactions-table/components/TransactionIcon/TransactionIcon.tsx @@ -0,0 +1,36 @@ +import { h } from '@stencil/core'; + +import type { TransactionIconInfoType } from '../../transactions-table.type'; +import { Icon } from 'common/Icon'; +import { getValidIcon } from './transactionIcon.helpers'; + +// prettier-ignore +const styles = { + transactionIconError: 'transaction-icon-error mvx:text-error', + transactionIconPending: 'transaction-icon-pending mvx:text-pending' +} satisfies Record; + +interface TransactionIconPropsType { + iconInfo: TransactionIconInfoType; + class?: string; +} + +export function TransactionIcon({ iconInfo, class: className }: TransactionIconPropsType) { + if (!iconInfo) { + return null; + } + + const iconName = getValidIcon(iconInfo.icon); + + return ( + + ); + +} diff --git a/src/components/controlled/transactions-table/components/TransactionIcon/index.ts b/src/components/controlled/transactions-table/components/TransactionIcon/index.ts new file mode 100644 index 00000000..c6aafb2c --- /dev/null +++ b/src/components/controlled/transactions-table/components/TransactionIcon/index.ts @@ -0,0 +1 @@ +export * from './TransactionIcon' \ No newline at end of file diff --git a/src/components/controlled/transactions-table/components/TransactionIcon/transactionIcon.helpers.ts b/src/components/controlled/transactions-table/components/TransactionIcon/transactionIcon.helpers.ts new file mode 100644 index 00000000..5a0d60c7 --- /dev/null +++ b/src/components/controlled/transactions-table/components/TransactionIcon/transactionIcon.helpers.ts @@ -0,0 +1,15 @@ +import { IconNameEnum } from "common/Icon/icon.types"; + +const iconMap: Record = Object.values(IconNameEnum).reduce((acc, icon) => { + acc[icon] = true; + return acc; +}, {} as Record); + +function isValidIcon(value: string): value is IconNameEnum { + return value in iconMap; +} + +export function getValidIcon(icon: string): IconNameEnum { + return isValidIcon(icon) ? icon : null; +} + diff --git a/src/components/controlled/transactions-table/components/TransactionMethod/TransactionMethod.tsx b/src/components/controlled/transactions-table/components/TransactionMethod/TransactionMethod.tsx new file mode 100644 index 00000000..35caf702 --- /dev/null +++ b/src/components/controlled/transactions-table/components/TransactionMethod/TransactionMethod.tsx @@ -0,0 +1,32 @@ +import { h } from '@stencil/core'; +import { DataTestIdsEnum } from 'constants/dataTestIds.enum'; + +// prettier-ignore +const styles = { + transactionMethodBadge: 'transaction-method-badge mvx:inline-block mvx:py-1 mvx:px-1.5 mvx:font-normal mvx:text-center mvx:whitespace-pre-wrap mvx:text-xs mvx:leading-none mvx:break-all mvx:align-baseline mvx:rounded-sm mvx:transition-colors mvx:duration-200 mvx:ease-in-out mvx:motion-reduce:transition-none mvx:text-transaction-method mvx:border-1 mvx:border-transaction-method mvx:bg-transparent mvx:font-light', + transactionMethodBadgeEmpty: 'transaction-method-badge-empty mvx:hidden', + transactionMethodText: 'transaction-method-text mvx:truncate mvx:capitalize' + +} satisfies Record; + +interface TransactionMethodPropsType { + class?: string; + actionDescription: string; + method: string; +} + +export function TransactionMethod({ method, actionDescription, class: className }: TransactionMethodPropsType) { + return ( + +
{method}
+
+ ); +} diff --git a/src/components/controlled/transactions-table/components/TransactionMethod/index.ts b/src/components/controlled/transactions-table/components/TransactionMethod/index.ts new file mode 100644 index 00000000..2f5606bb --- /dev/null +++ b/src/components/controlled/transactions-table/components/TransactionMethod/index.ts @@ -0,0 +1 @@ +export * from './TransactionMethod' \ No newline at end of file diff --git a/src/components/controlled/transactions-table/components/TransactionMethod/tests/transaction-method.spec.tsx b/src/components/controlled/transactions-table/components/TransactionMethod/tests/transaction-method.spec.tsx new file mode 100644 index 00000000..c8c4488d --- /dev/null +++ b/src/components/controlled/transactions-table/components/TransactionMethod/tests/transaction-method.spec.tsx @@ -0,0 +1,117 @@ +import { h } from '@stencil/core'; +import { newSpecPage } from '@stencil/core/testing'; +import { TransactionMethod } from '../TransactionMethod'; + + + +describe('TransactionMethod tests', () => { + const createPage = async (props: { method?: string; actionDescription?: string }) => { + const page = await newSpecPage({ + components: [], + template: () => + }); + + return page; + }; + + describe('rendering', () => { + it('renders with default props', async () => { + const page = await newSpecPage({ + components: [], + template: () => + }); + + expect(page.root).toBeTruthy(); + }); + + it('has correct data-testid', async () => { + const page = await newSpecPage({ + components: [], + template: () => + }); + + expect(page.root).toEqualHtml(` + +
testMethod
+
+ `); + }); + }); + + describe('method display', () => { + it('displays the transaction method', async () => { + const page = await createPage({ method: 'testMethod' }); + const methodElement = page.root.querySelector('.transaction-method-text'); + expect(methodElement.textContent).toBe('testMethod'); + }); + + it('handles empty method', async () => { + const page = await createPage({ method: '' }); + const methodElement = page.root.querySelector('.transaction-method-text'); + expect(methodElement.textContent).toBe(''); + }); + + it('handles undefined method', async () => { + const page = await createPage({ method: undefined }); + const methodElement = page.root.querySelector('.transaction-method-text'); + expect(methodElement.textContent).toBe(''); + }); + }); + + describe('action description', () => { + it('sets the action description as title', async () => { + const page = await createPage({ actionDescription: 'Test Description' }); + expect(page.root).toEqualHtml(` + +
+
+ `); + }); + + it('handles empty action description', async () => { + const page = await createPage({ actionDescription: '' }); + expect(page.root).toEqualHtml(` + +
+
+ `); + }); + + it('handles undefined action description', async () => { + const page = await createPage({ actionDescription: undefined }); + expect(page.root).toEqualHtml(` + +
+
+ `); + }); + }); + + describe('styling', () => { + it('applies correct CSS classes to outer span', async () => { + const page = await newSpecPage({ + components: [], + template: () => + }); + + expect(page.root).toEqualHtml(` + +
testMethod
+
+ `); + }); + + it('applies correct CSS classes to inner div', async () => { + const page = await newSpecPage({ + components: [], + template: () => + }); + + expect(page.root).toEqualHtml(` + +
testMethod
+
+ `); + }); + }); +}); diff --git a/src/components/controlled/transactions-table/components/TransactionShards/TransactionShards.tsx b/src/components/controlled/transactions-table/components/TransactionShards/TransactionShards.tsx new file mode 100644 index 00000000..3276f1b1 --- /dev/null +++ b/src/components/controlled/transactions-table/components/TransactionShards/TransactionShards.tsx @@ -0,0 +1,41 @@ +import { h } from '@stencil/core'; +import { DataTestIdsEnum } from 'constants/dataTestIds.enum'; + +import type { TransactionRowType } from '../../transactions-table.type'; + +// prettier-ignore +const styles = { + transactionShards: 'transaction-shards mvx:items-center mvx:flex mvx:gap-2 mvx:w-max mvx:fill-label', + transactionShardsArrowIcon: 'transaction-shards-arrow-icon mvx:w-4 mvx:h-4', + explorerLink: 'explorer-link mvx:text-primary!' +} satisfies Record; + +interface TransactionShardsPropsType { + class?: string; + transaction: TransactionRowType; +} + +export function TransactionShards({ transaction, class: className }: TransactionShardsPropsType) { + return ( +
+ + {transaction.sender.shard} + + + + + + {transaction.receiver.shard} + +
+ ); +} + diff --git a/src/components/controlled/transactions-table/components/TransactionShards/index.ts b/src/components/controlled/transactions-table/components/TransactionShards/index.ts new file mode 100644 index 00000000..18ca9b68 --- /dev/null +++ b/src/components/controlled/transactions-table/components/TransactionShards/index.ts @@ -0,0 +1 @@ +export * from './TransactionShards' \ No newline at end of file diff --git a/src/components/controlled/transactions-table/components/TransactionShards/tests/transaction-shards.spec.tsx b/src/components/controlled/transactions-table/components/TransactionShards/tests/transaction-shards.spec.tsx new file mode 100644 index 00000000..7a248e98 --- /dev/null +++ b/src/components/controlled/transactions-table/components/TransactionShards/tests/transaction-shards.spec.tsx @@ -0,0 +1,101 @@ +import { h } from '@stencil/core'; +import { newSpecPage } from '@stencil/core/testing'; +import { DataTestIdsEnum } from 'constants/dataTestIds.enum'; + +import type { TransactionRowType } from '../../../transactions-table.type'; +import { TransactionShards } from '../TransactionShards'; + +describe('TransactionShards tests', () => { + const createMockTransaction = (senderShard: string, receiverShard: string): TransactionRowType => ({ + age: { timeAgo: '1 min ago', tooltip: '1 minute ago' }, + method: { name: 'transfer' }, + iconInfo: { tooltip: 'Transfer' }, + link: '/tx/123', + receiver: { + address: 'erd1receiver...', + description: 'Receiver', + isContract: false, + isTokenLocked: false, + link: '/address/erd1receiver...', + name: 'Receiver', + shard: receiverShard, + shardLink: `/blocks?shard=${receiverShard}`, + showLink: true, + }, + sender: { + address: 'erd1sender...', + description: 'Sender', + isContract: false, + isTokenLocked: false, + link: '/address/erd1sender...', + name: 'Sender', + shard: senderShard, + shardLink: `/blocks?shard=${senderShard}`, + showLink: true, + }, + txHash: 'hash123', + value: { + egldLabel: 'xEGLD', + valueDecimal: '0', + valueInteger: '100', + }, + direction: 'in', + }); + + it('renders with default props', async () => { + const transaction = createMockTransaction('0', '1'); + + const page = await newSpecPage({ + components: [], + template: () => , + }); + + expect(page.root).toEqualHtml(` +
+ + 0 + + + + 1 + +
+ `); + }); + + it('renders with custom class', async () => { + const transaction = createMockTransaction('0', '1'); + + const page = await newSpecPage({ + components: [], + template: () => , + }); + + expect(page.root).toEqualHtml(` +
+ + 0 + + + + 1 + +
+ `); + }); + + it('renders with different shard values', async () => { + const transaction = createMockTransaction('2', '3'); + + const page = await newSpecPage({ + components: [], + template: () => , + }); + + const senderShard = page.root.querySelector(`[data-testid="${DataTestIdsEnum.senderShard}"]`); + const receiverShard = page.root.querySelector(`[data-testid="${DataTestIdsEnum.receiverShard}"]`); + + expect(senderShard.textContent).toBe('2'); + expect(receiverShard.textContent).toBe('3'); + }); +}); diff --git a/src/components/controlled/transactions-table/components/TransactionValue/TransactionValue.tsx b/src/components/controlled/transactions-table/components/TransactionValue/TransactionValue.tsx new file mode 100644 index 00000000..fb5dcc3a --- /dev/null +++ b/src/components/controlled/transactions-table/components/TransactionValue/TransactionValue.tsx @@ -0,0 +1,77 @@ +import { h } from '@stencil/core'; +import { Icon } from 'common/Icon'; +import type { TransactionValueType } from 'components/controlled/transactions-table/transactions-table.type'; +import { DataTestIdsEnum } from 'constants/dataTestIds.enum'; + +import styles from './transactionValue.styles'; +import classNames from 'classnames'; + +interface TransactionValuePropsType { + class?: string; + value: TransactionValueType; +} + +export function TransactionValue({ value, class: className }: TransactionValuePropsType) { + return ( +
+ {value.badge && ( +
+ {value.badge} +
+ )} + + {value.showFormattedAmount && ( +
+ {value.egldLabel && } + + +
+ )} + + {value.link && ( + +
+ {value.svgUrl && ( + {value.name + )} + + {value.linkText && ( + + {value.linkText} + + )} +
+
+ )} + + {value.titleText && ( + }> + {value.titleText} + + )} +
+ ); +} + diff --git a/src/components/controlled/transactions-table/components/TransactionValue/index.ts b/src/components/controlled/transactions-table/components/TransactionValue/index.ts new file mode 100644 index 00000000..31fba0ce --- /dev/null +++ b/src/components/controlled/transactions-table/components/TransactionValue/index.ts @@ -0,0 +1 @@ +export * from './TransactionValue'; \ No newline at end of file diff --git a/src/components/controlled/transactions-table/components/TransactionValue/tests/transaction-value.spec.tsx b/src/components/controlled/transactions-table/components/TransactionValue/tests/transaction-value.spec.tsx new file mode 100644 index 00000000..471cacd5 --- /dev/null +++ b/src/components/controlled/transactions-table/components/TransactionValue/tests/transaction-value.spec.tsx @@ -0,0 +1,195 @@ +import { h } from '@stencil/core'; +import { newSpecPage } from '@stencil/core/testing'; +import type { TransactionValueType } from 'components/controlled/transactions-table/transactions-table.type'; +import { TransactionValue } from '../TransactionValue'; + +describe('TransactionValue tests', () => { + it('renders with minimal props', async () => { + const value: TransactionValueType = { + egldLabel: '', + link: '', + linkText: '', + name: '', + ticker: '', + valueDecimal: '', + valueInteger: '', + }; + + const page = await newSpecPage({ + components: [], + template: () => , + }); + + expect(page.root).toEqualHtml(` +
+ `); + }); + + it('renders with badge', async () => { + const value: TransactionValueType = { + badge: 'NFT', + egldLabel: '', + link: '', + linkText: '', + name: '', + ticker: '', + valueDecimal: '', + valueInteger: '', + }; + + const page = await newSpecPage({ + components: [], + template: () => , + }); + + expect(page.root).toEqualHtml(` +
+
+ NFT +
+
+ `); + }); + + it('renders with formatted amount', async () => { + const value: TransactionValueType = { + showFormattedAmount: true, + egldLabel: 'xEGLD', + valueDecimal: '123', + valueInteger: '123', + link: '', + linkText: '', + name: '', + ticker: '', + }; + + const page = await newSpecPage({ + components: [], + template: () => , + }); + + expect(page.root).toEqualHtml(` +
+
+ + +
+
+ `); + }); + + it('renders with explorer link', async () => { + const value: TransactionValueType = { + egldLabel: '', + link: 'https://example.com', + linkText: 'Example Link', + name: 'Example', + ticker: 'EX', + valueDecimal: '', + valueInteger: '', + }; + + const page = await newSpecPage({ + components: [], + template: () => , + }); + + expect(page.root).toEqualHtml(` +
+ +
+ Example Link +
+
+
+ `); + }); + + it('renders with SVG icon', async () => { + const value: TransactionValueType = { + egldLabel: '', + link: 'https://example.com', + linkText: 'Example Link', + svgUrl: 'https://example.com/icon.svg', + name: 'Example Icon', + ticker: 'EX', + valueDecimal: '', + valueInteger: '', + }; + + const page = await newSpecPage({ + components: [], + template: () => , + }); + + expect(page.root).toEqualHtml(` +
+ +
+ Example Icon + Example Link +
+
+
+ `); + }); + + it('renders with truncated text', async () => { + const value: TransactionValueType = { + egldLabel: '', + link: 'https://example.com', + linkText: 'Example Link', + ticker: 'EXM', + collection: 'EXM', + name: 'Example', + valueDecimal: '', + valueInteger: '', + }; + + const page = await newSpecPage({ + components: [], + template: () => , + }); + + expect(page.root).toEqualHtml(` +
+ +
+ Example Link +
+
+
+ `); + }); + + it('renders with titleText', async () => { + const value: TransactionValueType = { + egldLabel: '', + link: 'https://example.com', + linkText: 'Example Link', + name: 'Example', + ticker: 'EX', + valueDecimal: '', + valueInteger: '', + titleText: 'Title Text', + }; + + const page = await newSpecPage({ + components: [], + template: () => , + }); + + expect(page.root).toEqualHtml(` +
+ +
+ Example Link +
+
+ + Title Text + +
+ `); + }); +}); diff --git a/src/components/controlled/transactions-table/components/transaction-value/transaction-value.styles.ts b/src/components/controlled/transactions-table/components/TransactionValue/transactionValue.styles.ts similarity index 100% rename from src/components/controlled/transactions-table/components/transaction-value/transaction-value.styles.ts rename to src/components/controlled/transactions-table/components/TransactionValue/transactionValue.styles.ts diff --git a/src/components/controlled/transactions-table/components/index.ts b/src/components/controlled/transactions-table/components/index.ts new file mode 100644 index 00000000..6ff8a6c0 --- /dev/null +++ b/src/components/controlled/transactions-table/components/index.ts @@ -0,0 +1,7 @@ +export * from './TransactionAge'; +export * from './TransactionHash'; +export * from './TransactionIcon'; +export * from './TransactionMethod'; +export * from './TransactionValue'; +export * from './TransactionShards'; +export * from './TransactionAccount'; \ No newline at end of file diff --git a/src/components/controlled/transactions-table/components/transaction-account/components/transaction-account-name/tests/transaction-account-name.spec.ts b/src/components/controlled/transactions-table/components/transaction-account/components/transaction-account-name/tests/transaction-account-name.spec.ts deleted file mode 100644 index 5d5ad35a..00000000 --- a/src/components/controlled/transactions-table/components/transaction-account/components/transaction-account-name/tests/transaction-account-name.spec.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { newSpecPage } from '@stencil/core/testing'; - -import { TransactionAccountName } from '../transaction-account-name'; - -describe('transaction-account-name', () => { - it('renders name when provided', async () => { - const { root } = await newSpecPage({ - components: [TransactionAccountName], - html: ` - - `, - }); - - const element = root?.querySelector('div'); - expect(element).not.toBeNull(); - expect(element?.textContent).toBe('Alice'); - expect(element?.getAttribute('title')).toBe("Alice's Wallet"); - expect(element?.getAttribute('data-testid')).toBe('account-name'); - expect(element?.className).toContain('text-truncate'); - }); - - it('uses trim component when name is missing', async () => { - const { root } = await newSpecPage({ - components: [TransactionAccountName], - html: ` - - `, - }); - - const trimElement = root?.querySelector('mvx-trim'); - expect(trimElement).not.toBeNull(); - expect(trimElement?.getAttribute('text')).toBe('erd1q...'); - expect(trimElement?.getAttribute('datatestid')).toBe('account-trim'); - }); - - it('handles empty name string', async () => { - const { root } = await newSpecPage({ - components: [TransactionAccountName], - html: ` - - `, - }); - - const trimElement = root?.querySelector('mvx-trim'); - expect(trimElement).not.toBeNull(); - }); - - it('applies correct class names', async () => { - const { root } = await newSpecPage({ - components: [TransactionAccountName], - html: ` - - `, - }); - - const element = root?.querySelector('div'); - expect(element?.className).toContain('custom-class'); - expect(element?.className).toContain('text-truncate'); - expect(element?.className).toContain('transaction-account-name'); - }); - - it('handles missing dataTestId', async () => { - const { root } = await newSpecPage({ - components: [TransactionAccountName], - html: ` - - `, - }); - - const element = root?.querySelector('div'); - expect(element?.hasAttribute('data-testid')).toBe(false); - }); - - it('uses description as title when name exists', async () => { - const { root } = await newSpecPage({ - components: [TransactionAccountName], - html: ` - - `, - }); - - const element = root?.querySelector('div'); - expect(element?.getAttribute('title')).toBe("Dave's Savings"); - }); -}); diff --git a/src/components/controlled/transactions-table/components/transaction-account/components/transaction-account-name/transaction-account-name.scss b/src/components/controlled/transactions-table/components/transaction-account/components/transaction-account-name/transaction-account-name.scss deleted file mode 100644 index ff1190ee..00000000 --- a/src/components/controlled/transactions-table/components/transaction-account/components/transaction-account-name/transaction-account-name.scss +++ /dev/null @@ -1 +0,0 @@ -// This is needed to trigger the Stecil Tailwind compilation for inline Tailwind classes. \ No newline at end of file diff --git a/src/components/controlled/transactions-table/components/transaction-account/components/transaction-account-name/transaction-account-name.tsx b/src/components/controlled/transactions-table/components/transaction-account/components/transaction-account-name/transaction-account-name.tsx deleted file mode 100644 index 928a6c13..00000000 --- a/src/components/controlled/transactions-table/components/transaction-account/components/transaction-account-name/transaction-account-name.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { Component, h, Prop } from '@stencil/core'; -import classNames from 'classnames'; - -// prettier-ignore -const styles = { - transactionAccountName: 'transaction-account-name mvx:w-max' -} satisfies Record; -@Component({ - tag: 'mvx-transaction-account-name', - styleUrl: 'transaction-account-name.scss', -}) -export class TransactionAccountName { - @Prop() address: string; - @Prop() class?: string; - @Prop() dataTestId?: string; - @Prop() description: string; - @Prop() name?: string; - - render() { - if (this.name) { - return ( -
- {this.name} -
- ); - } - - return ( - - ); - } -} diff --git a/src/components/controlled/transactions-table/components/transaction-account/tests/transaction-account.spec.tsx b/src/components/controlled/transactions-table/components/transaction-account/tests/transaction-account.spec.tsx deleted file mode 100644 index e247d4cb..00000000 --- a/src/components/controlled/transactions-table/components/transaction-account/tests/transaction-account.spec.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { h } from '@stencil/core'; -import { newSpecPage } from '@stencil/core/testing'; - -import type { TransactionAccountType } from '../../../transactions-table.type'; -import { TransactionAccount } from '../transaction-account'; - -describe('TransactionAccount Component', () => { - const baseAccount: TransactionAccountType = { - address: '0x1234567890123456789012345678901234567890', - name: 'John Doe', - description: 'Test Account', - isContract: false, - isTokenLocked: false, - link: 'https://example.com/account/0x1234567890123456789012345678901234567890', - showLink: false, - }; - - it('should render basic account information', async () => { - const page = await newSpecPage({ - components: [TransactionAccount], - template: () => , - }); - - const transactionAccountName = page.root.querySelector('mvx-transaction-account-name'); - expect(transactionAccountName).not.toBeNull(); - expect(transactionAccountName.getAttribute('name')).toBe('John Doe'); - expect(transactionAccountName.getAttribute('description')).toBe('Test Account'); - }); - - it('should render locked account icon when showLockedAccounts is true and account is locked', async () => { - const lockedAccount: TransactionAccountType = { ...baseAccount, isTokenLocked: true }; - - const page = await newSpecPage({ - components: [TransactionAccount], - template: () => , - }); - - const lockedIcon = page.root.querySelector('svg'); - expect(lockedIcon).not.toBeNull(); - }); - - it('should render contract icon when account is a contract', async () => { - const contractAccount: TransactionAccountType = { ...baseAccount, isContract: true }; - - const page = await newSpecPage({ - components: [TransactionAccount], - template: () => , - }); - - const contractIcon = page.root.querySelector('svg'); - expect(contractIcon).not.toBeNull(); - }); - - it('should render explorer link when showLink is true', async () => { - const linkedAccount: TransactionAccountType = { ...baseAccount, showLink: true }; - - const page = await newSpecPage({ - components: [TransactionAccount], - template: () => , - }); - - const explorerLink = page.root.querySelector('mvx-explorer-link'); - expect(explorerLink).not.toBeNull(); - expect(explorerLink.getAttribute('link')).toBe(linkedAccount.link); - expect(explorerLink.getAttribute('data-testid')).toBe('receiverLink'); - }); - - it('should apply custom class and data-testid', async () => { - const page = await newSpecPage({ - components: [TransactionAccount], - template: () => ( - - ), - }); - - const div = page.root.querySelector('div'); - expect(div.className).toBe('transaction-account mvx:flex mvx:items-center mvx:gap-2 custom-class'); - expect(div.getAttribute('data-testid')).toBe('test-id'); - }); -}); diff --git a/src/components/controlled/transactions-table/components/transaction-account/transaction-account.scss b/src/components/controlled/transactions-table/components/transaction-account/transaction-account.scss deleted file mode 100644 index 21b0cbc1..00000000 --- a/src/components/controlled/transactions-table/components/transaction-account/transaction-account.scss +++ /dev/null @@ -1 +0,0 @@ -// This is needed to trigger the Stecil Tailwind compilation for inline Tailwind classes. diff --git a/src/components/controlled/transactions-table/components/transaction-account/transaction-account.tsx b/src/components/controlled/transactions-table/components/transaction-account/transaction-account.tsx deleted file mode 100644 index 47a99ba2..00000000 --- a/src/components/controlled/transactions-table/components/transaction-account/transaction-account.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { Component, h, Prop } from '@stencil/core'; -import { Icon } from 'common/Icon'; -import { DataTestIdsEnum } from 'constants/dataTestIds.enum'; - -import type { TransactionAccountType } from '../../transactions-table.type'; - -// prettier-ignore -const styles = { - transactionAccount: 'transaction-account mvx:flex mvx:items-center mvx:gap-2', - transactionAccountExplorerLink: 'transaction-account-explorer-link mvx:text-primary!' -} satisfies Record; - -@Component({ - tag: 'mvx-transaction-account', - styleUrl: 'transaction-account.scss', -}) -export class TransactionAccount { - @Prop() account: TransactionAccountType; - @Prop() class?: string; - @Prop() dataTestId?: string; - @Prop() scope: 'receiver' | 'sender'; - @Prop() showLockedAccounts: boolean = false; - - render() { - const explorerLinkDataTestId = - this.scope === 'receiver' ? DataTestIdsEnum.receiverLink : DataTestIdsEnum.senderLink; - - return ( -
- {this.showLockedAccounts && this.account.isTokenLocked && } - {this.account.isContract && } - - {this.account.showLink ? ( - - {this.account.address} - - ) : ( - - )} -
- ); - } -} diff --git a/src/components/controlled/transactions-table/components/transaction-age/tests/transaction-age.spec.ts b/src/components/controlled/transactions-table/components/transaction-age/tests/transaction-age.spec.ts deleted file mode 100644 index 69fb6817..00000000 --- a/src/components/controlled/transactions-table/components/transaction-age/tests/transaction-age.spec.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { newSpecPage } from '@stencil/core/testing'; -import { DataTestIdsEnum } from 'constants/dataTestIds.enum'; - -import { TransactionAge } from '../transaction-age'; - -describe('TransactionAge', () => { - it('renders with age prop', async () => { - const page = await newSpecPage({ - components: [TransactionAge], - html: '', - }); - - const ageSpan = page.root.querySelector(`[data-testid="${DataTestIdsEnum.transactionAge}"]`); - expect(ageSpan).not.toBeNull(); - expect(ageSpan.textContent).toBe('2 days ago'); - }); - - it('renders without tooltip when not provided', async () => { - const page = await newSpecPage({ - components: [TransactionAge], - html: '', - }); - - const ageSpan = page.root.querySelector(`[data-testid="${DataTestIdsEnum.transactionAge}"]`); - expect(ageSpan).not.toBeNull(); - expect(ageSpan.getAttribute('title')).toBeNull(); - }); - - it('renders with tooltip when provided', async () => { - const page = await newSpecPage({ - components: [TransactionAge], - html: '', - }); - - const ageSpan = page.root.querySelector(`[data-testid="${DataTestIdsEnum.transactionAge}"]`); - expect(ageSpan).not.toBeNull(); - expect(ageSpan.getAttribute('title')).toBe('2023-05-17 10:30:00 UTC'); - }); - - it('updates when age prop changes', async () => { - const page = await newSpecPage({ - components: [TransactionAge], - html: '', - }); - - let ageSpan = page.root.querySelector(`[data-testid="${DataTestIdsEnum.transactionAge}"]`); - expect(ageSpan.textContent).toBe('5 minutes ago'); - - page.root.age = '10 minutes ago'; - await page.waitForChanges(); - - ageSpan = page.root.querySelector(`[data-testid="${DataTestIdsEnum.transactionAge}"]`); - expect(ageSpan.textContent).toBe('10 minutes ago'); - }); - - it('updates when tooltip prop changes', async () => { - const page = await newSpecPage({ - components: [TransactionAge], - html: '', - }); - - let ageSpan = page.root.querySelector(`[data-testid="${DataTestIdsEnum.transactionAge}"]`); - expect(ageSpan.getAttribute('title')).toBe('2023-05-17 09:30:00 UTC'); - - page.root.tooltip = '2023-05-17 10:30:00 UTC'; - await page.waitForChanges(); - - ageSpan = page.root.querySelector(`[data-testid="${DataTestIdsEnum.transactionAge}"]`); - expect(ageSpan.getAttribute('title')).toBe('2023-05-17 10:30:00 UTC'); - }); -}); diff --git a/src/components/controlled/transactions-table/components/transaction-age/transaction-age.scss b/src/components/controlled/transactions-table/components/transaction-age/transaction-age.scss deleted file mode 100644 index ff1190ee..00000000 --- a/src/components/controlled/transactions-table/components/transaction-age/transaction-age.scss +++ /dev/null @@ -1 +0,0 @@ -// This is needed to trigger the Stecil Tailwind compilation for inline Tailwind classes. \ No newline at end of file diff --git a/src/components/controlled/transactions-table/components/transaction-age/transaction-age.tsx b/src/components/controlled/transactions-table/components/transaction-age/transaction-age.tsx deleted file mode 100644 index 6c6c352a..00000000 --- a/src/components/controlled/transactions-table/components/transaction-age/transaction-age.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { Component, h, Prop } from '@stencil/core'; -import { DataTestIdsEnum } from 'constants/dataTestIds.enum'; - -// prettier-ignore -const styles = { - transactionAge: 'transaction-age mvx:w-max' -} satisfies Record; - -@Component({ - tag: 'mvx-transaction-age', - styleUrl: 'transaction-age.scss', -}) -export class TransactionAge { - @Prop() age: string; - @Prop() class?: string; - @Prop() tooltip?: string; - - render() { - const component = this.tooltip ? ( -
- {this.age} -
- ) : ( -
- {this.age} -
- ); - - return
{component}
; - } -} diff --git a/src/components/controlled/transactions-table/components/transaction-direction-badge/tests/transaction-direction-badge.spec.ts b/src/components/controlled/transactions-table/components/transaction-direction-badge/tests/transaction-direction-badge.spec.ts deleted file mode 100644 index 5477c0e4..00000000 --- a/src/components/controlled/transactions-table/components/transaction-direction-badge/tests/transaction-direction-badge.spec.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { newSpecPage } from '@stencil/core/testing'; - -import { TransactionDirectionBadge } from '../transaction-direction-badge'; - -describe('TransactionDirectionBadge', () => { - it('renders with "in" direction', async () => { - const page = await newSpecPage({ - components: [TransactionDirectionBadge], - html: '', - }); - expect(page.root).toEqualHtml(` - -
- - IN - -
-
- `); - }); - - it('renders with "out" direction', async () => { - const page = await newSpecPage({ - components: [TransactionDirectionBadge], - html: '', - }); - expect(page.root).toEqualHtml(` - -
- - OUT - -
-
- `); - }); - - it('renders with custom direction', async () => { - const page = await newSpecPage({ - components: [TransactionDirectionBadge], - html: '', - }); - expect(page.root).toEqualHtml(` - -
- - CUSTOM - -
-
- `); - }); -}); diff --git a/src/components/controlled/transactions-table/components/transaction-direction-badge/transaction-direction-badge.scss b/src/components/controlled/transactions-table/components/transaction-direction-badge/transaction-direction-badge.scss deleted file mode 100644 index ff1190ee..00000000 --- a/src/components/controlled/transactions-table/components/transaction-direction-badge/transaction-direction-badge.scss +++ /dev/null @@ -1 +0,0 @@ -// This is needed to trigger the Stecil Tailwind compilation for inline Tailwind classes. \ No newline at end of file diff --git a/src/components/controlled/transactions-table/components/transaction-direction-badge/transaction-direction-badge.tsx b/src/components/controlled/transactions-table/components/transaction-direction-badge/transaction-direction-badge.tsx deleted file mode 100644 index 3d578c3a..00000000 --- a/src/components/controlled/transactions-table/components/transaction-direction-badge/transaction-direction-badge.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { Component, h, Prop } from '@stencil/core'; - -// prettier-ignore -const styles = { - transactionDirectionBadge: 'transaction-direction-badge mvx:flex' -} satisfies Record; - -@Component({ - tag: 'mvx-transaction-direction-badge', - styleUrl: 'transaction-direction-badge.scss', -}) -export class TransactionDirectionBadge { - @Prop() class?: string; - @Prop() direction: string; - - render() { - return ( -
- - {this.direction.toUpperCase()} - -
- ); - } -} diff --git a/src/components/controlled/transactions-table/components/transaction-hash/tests/transaction-hash.spec.tsx b/src/components/controlled/transactions-table/components/transaction-hash/tests/transaction-hash.spec.tsx deleted file mode 100644 index 301a0e71..00000000 --- a/src/components/controlled/transactions-table/components/transaction-hash/tests/transaction-hash.spec.tsx +++ /dev/null @@ -1,142 +0,0 @@ -import { h } from '@stencil/core'; -import { newSpecPage } from '@stencil/core/testing'; -import { DataTestIdsEnum } from 'constants/dataTestIds.enum'; - -import type { TransactionAccountType, TransactionRowType } from '../../../transactions-table.type'; -import { TransactionHash } from '../transaction-hash'; - -const account: TransactionAccountType = { - address: 'erd...', - name: 'test', - description: 'test', - isContract: false, - isTokenLocked: false, - link: '/test', - showLink: false, - shard: '0', - shardLink: '/shard/0', -}; - -describe('TransactionHash', () => { - it('renders with transaction data', async () => { - const transaction: TransactionRowType = { - age: { - timeAgo: '1h', - tooltip: '1 hour ago', - }, - direction: 'in', - iconInfo: { icon: 'circle-info', tooltip: 'Test' }, - link: 'https://example.com/tx/123', - method: { - name: 'Smart Contract', - actionDescription: 'Contract call', - }, - receiver: account, - sender: account, - txHash: '0x123456789abcdef', - value: { - egldLabel: 'xEGLD', - valueDecimal: '0', - valueInteger: '100', - }, - }; - - const page = await newSpecPage({ - components: [TransactionHash], - template: () => , - }); - - expect(page.root).toEqualHtml(` - -
- - -
-
- `); - }); - - it('updates when transaction prop changes', async () => { - const initialTransactionData: TransactionRowType = { - age: { - timeAgo: '1h', - tooltip: '1 hour ago', - }, - direction: 'in', - iconInfo: { icon: 'circle-Info', tooltip: 'Initial' }, - link: 'https://example.com/tx/initial', - method: { - name: 'Smart Contract', - actionDescription: 'Initial call', - }, - receiver: account, - sender: account, - txHash: '0xInitialHash', - value: { - egldLabel: 'xEGLD', - valueDecimal: '0', - valueInteger: '100', - }, - }; - - const page = await newSpecPage({ - components: [TransactionHash], - template: () => , - }); - - expect(page.root).toEqualHtml(` - -
- - -
-
- `); - - const updatedTransactionData: TransactionRowType = { - age: { - timeAgo: '2h', - tooltip: '2 hours ago', - }, - direction: 'out', - iconInfo: { icon: 'circle-check', tooltip: 'Updated' }, - link: 'https://example.com/tx/updated', - method: { - name: 'Transfer', - actionDescription: 'Token transfer', - }, - receiver: account, - sender: account, - txHash: '0xUpdatedHash', - value: { - egldLabel: 'xEGLD', - valueDecimal: '1', - valueInteger: '200', - }, - }; - - page.root.transaction = updatedTransactionData; - await page.waitForChanges(); - - expect(page.root).toEqualHtml(` - -
- - -
-
- `); - }); - - it('renders null when transaction is not provided', async () => { - const page = await newSpecPage({ - components: [TransactionHash], - template: () => , - }); - - expect(page.root).toEqualHtml(` - - - `); - }); -}); diff --git a/src/components/controlled/transactions-table/components/transaction-hash/transaction-hash.scss b/src/components/controlled/transactions-table/components/transaction-hash/transaction-hash.scss deleted file mode 100644 index ff1190ee..00000000 --- a/src/components/controlled/transactions-table/components/transaction-hash/transaction-hash.scss +++ /dev/null @@ -1 +0,0 @@ -// This is needed to trigger the Stecil Tailwind compilation for inline Tailwind classes. \ No newline at end of file diff --git a/src/components/controlled/transactions-table/components/transaction-hash/transaction-hash.tsx b/src/components/controlled/transactions-table/components/transaction-hash/transaction-hash.tsx deleted file mode 100644 index bd8e05b7..00000000 --- a/src/components/controlled/transactions-table/components/transaction-hash/transaction-hash.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { Component, h, Prop } from '@stencil/core'; -import { DataTestIdsEnum } from 'constants/dataTestIds.enum'; - -import type { TransactionRowType } from '../../transactions-table.type'; - -// prettier-ignore -const styles = { - transactionHash: 'transaction-hash mvx:flex mvx:gap-1 mvx:items-center mvx:justify-center', - transactionHashExplorerLink: 'transaction-hash-explorer-link mvx:text-primary!', - transactionHashIcon: 'transaction-hash-icon mvx:flex mvx:items-center mvx:justify-center', -} satisfies Record; - -@Component({ - tag: 'mvx-transaction-hash', - styleUrl: 'transaction-hash.scss', -}) -export class TransactionHash { - @Prop() class?: string; - @Prop() transaction: TransactionRowType; - - render() { - if (!this.transaction) { - return null; - } - - return ( -
- - - - - -
- ); - } -} diff --git a/src/components/controlled/transactions-table/components/transaction-icon/transaction-icon.scss b/src/components/controlled/transactions-table/components/transaction-icon/transaction-icon.scss deleted file mode 100644 index ff1190ee..00000000 --- a/src/components/controlled/transactions-table/components/transaction-icon/transaction-icon.scss +++ /dev/null @@ -1 +0,0 @@ -// This is needed to trigger the Stecil Tailwind compilation for inline Tailwind classes. \ No newline at end of file diff --git a/src/components/controlled/transactions-table/components/transaction-icon/transaction-icon.tsx b/src/components/controlled/transactions-table/components/transaction-icon/transaction-icon.tsx deleted file mode 100644 index 8e335271..00000000 --- a/src/components/controlled/transactions-table/components/transaction-icon/transaction-icon.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { Component, h, Prop } from '@stencil/core'; - -import type { TransactionIconInfoType } from '../../transactions-table.type'; -import { Icon } from 'common/Icon'; -import { IconNameEnum } from 'common/Icon/icon.types'; - -// prettier-ignore -const styles = { - transactionIconError: 'transaction-icon-error mvx:text-error', - transactionIconPending: 'transaction-icon-pending mvx:text-pending' -} satisfies Record; - -@Component({ - tag: 'mvx-transaction-icon', -}) -export class TransactionIcon { - @Prop() class?: string; - @Prop() iconInfo: TransactionIconInfoType; - - render() { - if (!this.iconInfo) { - return null; - } - - return ( - - ); - } -} diff --git a/src/components/controlled/transactions-table/components/transaction-method/tests/transaction-method.spec.ts b/src/components/controlled/transactions-table/components/transaction-method/tests/transaction-method.spec.ts deleted file mode 100644 index 9df0aaf2..00000000 --- a/src/components/controlled/transactions-table/components/transaction-method/tests/transaction-method.spec.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { newSpecPage } from '@stencil/core/testing'; -import { DataTestIdsEnum } from 'constants/dataTestIds.enum'; - -import { TransactionMethod } from '../transaction-method'; - -describe('transaction-method', () => { - const createPage = async (props: { method?: string; actionDescription?: string }) => { - const page = await newSpecPage({ - components: [TransactionMethod], - html: '', - }); - - const component = page.rootInstance as TransactionMethod; - component.method = props.method; - component.actionDescription = props.actionDescription; - await page.waitForChanges(); - return page; - }; - - describe('rendering', () => { - it('renders with default props', async () => { - const page = await newSpecPage({ - components: [TransactionMethod], - html: '', - }); - - expect(page.root).toBeTruthy(); - }); - - it('has correct data-testid', async () => { - const page = await newSpecPage({ - components: [TransactionMethod], - html: '', - }); - - const spanElement = page.root.querySelector(`[data-testid="${DataTestIdsEnum.method}"]`); - expect(spanElement).toBeTruthy(); - }); - }); - - describe('method display', () => { - it('displays the transaction method', async () => { - const page = await createPage({ method: 'testMethod' }); - const methodElement = page.root.querySelector('.transaction-method-text'); - expect(methodElement.textContent).toBe('testMethod'); - }); - - it('handles empty method', async () => { - const page = await createPage({ method: '' }); - const methodElement = page.root.querySelector('.transaction-method-text'); - expect(methodElement.textContent).toBe(''); - }); - - it('handles undefined method', async () => { - const page = await createPage({ method: undefined }); - const methodElement = page.root.querySelector('.transaction-method-text'); - expect(methodElement.textContent).toBe(''); - }); - }); - - describe('action description', () => { - it('sets the action description as title', async () => { - const page = await createPage({ actionDescription: 'Test Description' }); - const spanElement = page.root.querySelector(`[data-testid="${DataTestIdsEnum.method}"]`); - expect(spanElement.getAttribute('title')).toBe('Test Description'); - }); - - it('handles empty action description', async () => { - const page = await createPage({ actionDescription: '' }); - const spanElement = page.root.querySelector(`[data-testid="${DataTestIdsEnum.method}"]`); - expect(spanElement.getAttribute('title')).toBe(''); - }); - - it('handles undefined action description', async () => { - const page = await createPage({ actionDescription: undefined }); - const spanElement = page.root.querySelector(`[data-testid="${DataTestIdsEnum.method}"]`); - expect(spanElement.getAttribute('title')).toBeNull(); - }); - }); - - describe('styling', () => { - it('applies correct CSS classes to outer span', async () => { - const page = await newSpecPage({ - components: [TransactionMethod], - html: '', - }); - - const outerSpan = page.root.querySelector('span'); - expect(outerSpan).toHaveClass('transaction-method-badge'); - }); - - it('applies correct CSS classes to inner div', async () => { - const page = await newSpecPage({ - components: [TransactionMethod], - html: '', - }); - - const innerDiv = page.root.querySelector('span > div'); - expect(innerDiv).toHaveClass('transaction-method-text'); - }); - }); -}); diff --git a/src/components/controlled/transactions-table/components/transaction-method/transaction-method.scss b/src/components/controlled/transactions-table/components/transaction-method/transaction-method.scss deleted file mode 100644 index 4525d97d..00000000 --- a/src/components/controlled/transactions-table/components/transaction-method/transaction-method.scss +++ /dev/null @@ -1,2 +0,0 @@ -// This is needed to trigger the Stecil Tailwind compilation for inline Tailwind classes. - diff --git a/src/components/controlled/transactions-table/components/transaction-method/transaction-method.tsx b/src/components/controlled/transactions-table/components/transaction-method/transaction-method.tsx deleted file mode 100644 index a61dff9b..00000000 --- a/src/components/controlled/transactions-table/components/transaction-method/transaction-method.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { Component, h, Prop } from '@stencil/core'; -import { DataTestIdsEnum } from 'constants/dataTestIds.enum'; - -// prettier-ignore -const styles = { - transactionMethodBadge: 'transaction-method-badge mvx:inline-block mvx:py-1 mvx:px-1.5 mvx:font-normal mvx:text-center mvx:whitespace-pre-wrap mvx:text-xs mvx:leading-none mvx:break-all mvx:align-baseline mvx:rounded-sm mvx:transition-colors mvx:duration-200 mvx:ease-in-out mvx:motion-reduce:transition-none mvx:text-transaction-method mvx:border-1 mvx:border-transaction-method mvx:bg-transparent mvx:font-light', - transactionMethodBadgeEmpty: 'transaction-method-badge-empty mvx:hidden', - transactionMethodText: 'transaction-method-text mvx:truncate mvx:capitalize' - -} satisfies Record; - -@Component({ - tag: 'mvx-transaction-method', - styleUrl: 'transaction-method.scss', -}) -export class TransactionMethod { - @Prop() class?: string; - @Prop() actionDescription: string; - @Prop() method: string; - - render() { - return ( - -
{this.method}
-
- ); - } -} diff --git a/src/components/controlled/transactions-table/components/transaction-shards/tests/transaction-shards.spec.tsx b/src/components/controlled/transactions-table/components/transaction-shards/tests/transaction-shards.spec.tsx deleted file mode 100644 index 8fd2c8a2..00000000 --- a/src/components/controlled/transactions-table/components/transaction-shards/tests/transaction-shards.spec.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import { h } from '@stencil/core'; -import { newSpecPage } from '@stencil/core/testing'; -import { DataTestIdsEnum } from 'constants/dataTestIds.enum'; - -import type { TransactionRowType } from '../../../transactions-table.type'; -import { TransactionShards } from '../transaction-shards'; - -describe('TransactionShards', () => { - const createMockTransaction = (senderShard: string, receiverShard: string): TransactionRowType => ({ - age: { timeAgo: '1 min ago', tooltip: '1 minute ago' }, - method: { name: 'transfer' }, - iconInfo: { tooltip: 'Transfer' }, - link: '/tx/123', - receiver: { - address: 'erd1receiver...', - description: 'Receiver', - isContract: false, - isTokenLocked: false, - link: '/address/erd1receiver...', - name: 'Receiver', - shard: receiverShard, - shardLink: `/blocks?shard=${receiverShard}`, - showLink: true, - }, - sender: { - address: 'erd1sender...', - description: 'Sender', - isContract: false, - isTokenLocked: false, - link: '/address/erd1sender...', - name: 'Sender', - shard: senderShard, - shardLink: `/blocks?shard=${senderShard}`, - showLink: true, - }, - txHash: 'hash123', - value: { - egldLabel: 'xEGLD', - valueDecimal: '0', - valueInteger: '100', - }, - direction: 'in', - }); - - it('renders with default props', async () => { - const transaction = createMockTransaction('0', '1'); - - const page = await newSpecPage({ - components: [TransactionShards], - template: () => , - }); - - expect(page.root).toEqualHtml(` - -
- - 0 - - - - 1 - -
-
- `); - }); - - it('renders with custom class', async () => { - const transaction = createMockTransaction('0', '1'); - - const page = await newSpecPage({ - components: [TransactionShards], - template: () => , - }); - - expect(page.root).toEqualHtml(` - -
- - 0 - - - - 1 - -
-
- `); - }); - - it('renders with different shard values', async () => { - const transaction = createMockTransaction('2', '3'); - - const page = await newSpecPage({ - components: [TransactionShards], - template: () => , - }); - - const senderShard = page.root.querySelector(`[data-testid="${DataTestIdsEnum.senderShard}"]`); - const receiverShard = page.root.querySelector(`[data-testid="${DataTestIdsEnum.receiverShard}"]`); - - expect(senderShard.textContent).toBe('2'); - expect(receiverShard.textContent).toBe('3'); - }); -}); diff --git a/src/components/controlled/transactions-table/components/transaction-shards/transaction-shards.scss b/src/components/controlled/transactions-table/components/transaction-shards/transaction-shards.scss deleted file mode 100644 index ff1190ee..00000000 --- a/src/components/controlled/transactions-table/components/transaction-shards/transaction-shards.scss +++ /dev/null @@ -1 +0,0 @@ -// This is needed to trigger the Stecil Tailwind compilation for inline Tailwind classes. \ No newline at end of file diff --git a/src/components/controlled/transactions-table/components/transaction-shards/transaction-shards.tsx b/src/components/controlled/transactions-table/components/transaction-shards/transaction-shards.tsx deleted file mode 100644 index bb76e8de..00000000 --- a/src/components/controlled/transactions-table/components/transaction-shards/transaction-shards.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { Component, h, Prop } from '@stencil/core'; -import { DataTestIdsEnum } from 'constants/dataTestIds.enum'; - -import type { TransactionRowType } from '../../transactions-table.type'; - -// prettier-ignore -const styles = { - transactionShards: 'transaction-shards mvx:items-center mvx:flex mvx:gap-2 mvx:w-max mvx:fill-label', - transactionShardsArrowIcon: 'transaction-shards-arrow-icon mvx:w-4 mvx:h-4', - explorerLink: 'explorer-link mvx:text-primary!' -} satisfies Record; - -@Component({ - tag: 'mvx-transaction-shards', - styleUrl: 'transaction-shards.scss', -}) -export class TransactionShards { - @Prop() class?: string; - @Prop() transaction: TransactionRowType; - - render() { - return ( -
- - {this.transaction.sender.shard} - - - - - - {this.transaction.receiver.shard} - -
- ); - } -} diff --git a/src/components/controlled/transactions-table/components/transaction-value/tests/transaction-value.spec.tsx b/src/components/controlled/transactions-table/components/transaction-value/tests/transaction-value.spec.tsx deleted file mode 100644 index 514ce048..00000000 --- a/src/components/controlled/transactions-table/components/transaction-value/tests/transaction-value.spec.tsx +++ /dev/null @@ -1,210 +0,0 @@ -import { h } from '@stencil/core'; -import { newSpecPage } from '@stencil/core/testing'; -import type { TransactionValueType } from 'components/controlled/transactions-table/transactions-table.type'; - -import { TransactionValue } from '../transaction-value'; - -describe('TransactionValue', () => { - it('renders with minimal props', async () => { - const value: TransactionValueType = { - egldLabel: '', - link: '', - linkText: '', - name: '', - ticker: '', - valueDecimal: '', - valueInteger: '', - }; - - const page = await newSpecPage({ - components: [TransactionValue], - template: () => , - }); - - expect(page.root).toEqualHtml(` - -
-
- `); - }); - - it('renders with badge', async () => { - const value: TransactionValueType = { - badge: 'NFT', - egldLabel: '', - link: '', - linkText: '', - name: '', - ticker: '', - valueDecimal: '', - valueInteger: '', - }; - - const page = await newSpecPage({ - components: [TransactionValue], - template: () => , - }); - - expect(page.root).toEqualHtml(` - -
-
- NFT -
-
-
- `); - }); - - it('renders with formatted amount', async () => { - const value: TransactionValueType = { - showFormattedAmount: true, - egldLabel: 'xEGLD', - valueDecimal: '123', - valueInteger: '123', - link: '', - linkText: '', - name: '', - ticker: '', - }; - - const page = await newSpecPage({ - components: [TransactionValue], - template: () => , - }); - - expect(page.root).toEqualHtml(` - -
-
- - -
-
-
- `); - }); - - it('renders with explorer link', async () => { - const value: TransactionValueType = { - egldLabel: '', - link: 'https://example.com', - linkText: 'Example Link', - name: 'Example', - ticker: 'EX', - valueDecimal: '', - valueInteger: '', - }; - - const page = await newSpecPage({ - components: [TransactionValue], - template: () => , - }); - - expect(page.root).toEqualHtml(` - -
- -
- Example Link -
-
-
-
- `); - }); - - it('renders with SVG icon', async () => { - const value: TransactionValueType = { - egldLabel: '', - link: 'https://example.com', - linkText: 'Example Link', - svgUrl: 'https://example.com/icon.svg', - name: 'Example Icon', - ticker: 'EX', - valueDecimal: '', - valueInteger: '', - }; - - const page = await newSpecPage({ - components: [TransactionValue], - template: () => , - }); - - expect(page.root).toEqualHtml(` - -
- -
- Example Icon - Example Link -
-
-
-
- `); - }); - - it('renders with truncated text', async () => { - const value: TransactionValueType = { - egldLabel: '', - link: 'https://example.com', - linkText: 'Example Link', - ticker: 'EXM', - collection: 'EXM', - name: 'Example', - valueDecimal: '', - valueInteger: '', - }; - - const page = await newSpecPage({ - components: [TransactionValue], - template: () => , - }); - - expect(page.root).toEqualHtml(` - -
- -
- Example Link -
-
-
-
- `); - }); - - it('renders with titleText', async () => { - const value: TransactionValueType = { - egldLabel: '', - link: 'https://example.com', - linkText: 'Example Link', - name: 'Example', - ticker: 'EX', - valueDecimal: '', - valueInteger: '', - titleText: 'Title Text', - }; - - const page = await newSpecPage({ - components: [TransactionValue], - template: () => , - }); - - expect(page.root).toEqualHtml(` - -
- -
- Example Link -
-
- - Title Text - -
-
- `); - }); -}); diff --git a/src/components/controlled/transactions-table/components/transaction-value/transaction-value.scss b/src/components/controlled/transactions-table/components/transaction-value/transaction-value.scss deleted file mode 100644 index 21b0cbc1..00000000 --- a/src/components/controlled/transactions-table/components/transaction-value/transaction-value.scss +++ /dev/null @@ -1 +0,0 @@ -// This is needed to trigger the Stecil Tailwind compilation for inline Tailwind classes. diff --git a/src/components/controlled/transactions-table/components/transaction-value/transaction-value.tsx b/src/components/controlled/transactions-table/components/transaction-value/transaction-value.tsx deleted file mode 100644 index f80a80d6..00000000 --- a/src/components/controlled/transactions-table/components/transaction-value/transaction-value.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import { Component, h, Prop } from '@stencil/core'; -import { Icon } from 'common/Icon'; -import type { TransactionValueType } from 'components/controlled/transactions-table/transactions-table.type'; -import { DataTestIdsEnum } from 'constants/dataTestIds.enum'; - -import styles from './transaction-value.styles'; -import classNames from 'classnames'; - -@Component({ - tag: 'mvx-transaction-value', - styleUrl: 'transaction-value.scss', -}) -export class TransactionValue { - @Prop() class?: string; - @Prop() value: TransactionValueType; - - render() { - return ( -
- {this.value.badge && ( -
- {this.value.badge} -
- )} - - {this.value.showFormattedAmount && ( -
- {this.value.egldLabel && } - - -
- )} - - {this.value.link && ( - -
- {this.value.svgUrl && ( - {this.value.name - )} - - {this.value.linkText && ( - - {this.value.linkText} - - )} -
-
- )} - - {this.value.titleText && ( - }> - {this.value.titleText} - - )} -
- ); - } -} diff --git a/src/components/controlled/transactions-table/tests/transactions-table.spec.tsx b/src/components/controlled/transactions-table/tests/transactions-table.spec.tsx index 0021f875..6f2e33a9 100644 --- a/src/components/controlled/transactions-table/tests/transactions-table.spec.tsx +++ b/src/components/controlled/transactions-table/tests/transactions-table.spec.tsx @@ -126,20 +126,13 @@ describe('TransactionsTable', () => { const rows = page.root.querySelectorAll('tbody tr'); expect(rows.length).toBe(2); - rows.forEach((row, index) => { - expect(row.querySelector('mvx-transaction-hash')).toBeTruthy(); - expect(row.querySelector('mvx-transaction-age')).toBeTruthy(); - expect(row.querySelector('mvx-transaction-shards')).toBeTruthy(); - expect(row.querySelector('mvx-transaction-account[scope="sender"]')).toBeTruthy(); - expect(row.querySelector('mvx-transaction-account[scope="receiver"]')).toBeTruthy(); - expect(row.querySelector('mvx-transaction-method')).toBeTruthy(); - expect(row.querySelector('mvx-transaction-value')).toBeTruthy(); + const cells = rows[0].querySelectorAll('td'); + expect(cells.length).toBe(7); - // Check some specific values - expect(row.querySelector('mvx-transaction-age').getAttribute('age')).toBe(mockTransactions[index].age.timeAgo); - expect(row.querySelector('mvx-transaction-method').getAttribute('method')).toBe( - mockTransactions[index].method.name, - ); - }); + // Check some specific values + const ageCell = cells[1]; + expect(ageCell.textContent).toContain('5 minutes ago'); + const methodCell = cells[5]; + expect(methodCell.textContent).toContain('transfer'); }); }); diff --git a/src/components/controlled/transactions-table/transactions-table.tsx b/src/components/controlled/transactions-table/transactions-table.tsx index 7b72b6ec..04cd0ca9 100644 --- a/src/components/controlled/transactions-table/transactions-table.tsx +++ b/src/components/controlled/transactions-table/transactions-table.tsx @@ -3,6 +3,7 @@ import { Component, h, Prop } from '@stencil/core'; import { DataTestIdsEnum } from '../../../constants/dataTestIds.enum'; import type { TransactionRowType } from './transactions-table.type'; import styles from './transactions-table.styles' +import { TransactionAccount, TransactionAge, TransactionHash, TransactionMethod, TransactionShards, TransactionValue } from './components'; const COLUMNS = ['Txn Hash', 'Age', 'Shard', 'From', 'To', 'Method', 'Value']; @@ -30,45 +31,45 @@ export class TransactionsTable { {this.transactions.map(transaction => ( - + - + /> - + - + /> - + /> - + /> - + ))}