diff --git a/CHANGELOG.md b/CHANGELOG.md index 48e3dd31..2a79f552 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ## [[0.0.0-alpha.1](https://github.com/multiversx/mx-sdk-dapp-core-ui/pull/16)] - 2025-01-20 - -- [Updated formatAmount component and removed dependencies](https://github.com/multiversx/mx-sdk-dapp-core-ui/pull/17) - [Updated formatAmount component](https://github.com/multiversx/mx-sdk-dapp-core-ui/pull/15) \ No newline at end of file diff --git a/package.json b/package.json index 0cd7942f..461ec3af 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,9 @@ "dependencies": { "@fortawesome/fontawesome-svg-core": ">= 6.7.2", "@fortawesome/free-solid-svg-icons": ">= 6.7.2", - "@multiversx/sdk-dapp-utils": ">= 1.0.4", + "@multiversx/sdk-dapp-utils": ">= 1.0.3", + "@multiversx/sdk-core": ">= 13.5.0", + "bignumber.js": ">= 9.1.2", "classnames": ">= 2.5.1", "qrcode": ">= 1.5.4" }, diff --git a/src/components.d.ts b/src/components.d.ts index 5721a2d0..b8e889e1 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -28,11 +28,13 @@ export namespace Components { } interface FormatAmount { "class"?: string; - "isValid": boolean; - "label"?: string; - "labelClass"?: string; - "valueDecimal": string; - "valueInteger": string; + "decimals"?: number; + "digits"?: number; + "egldLabel"?: string; + "showLabel"?: boolean; + "showLastNonZeroDecimal"?: boolean; + "token"?: string; + "value": string; } interface FungibleComponent { } @@ -291,11 +293,13 @@ declare namespace LocalJSX { } interface FormatAmount { "class"?: string; - "isValid"?: boolean; - "label"?: string; - "labelClass"?: string; - "valueDecimal"?: string; - "valueInteger"?: string; + "decimals"?: number; + "digits"?: number; + "egldLabel"?: string; + "showLabel"?: boolean; + "showLastNonZeroDecimal"?: boolean; + "token"?: string; + "value"?: string; } interface FungibleComponent { } diff --git a/src/components/format-amount/format-amount.tsx b/src/components/format-amount/format-amount.tsx index 60f2189e..c82b09f4 100644 --- a/src/components/format-amount/format-amount.tsx +++ b/src/components/format-amount/format-amount.tsx @@ -1,4 +1,7 @@ import { Component, Prop, h } from '@stencil/core'; +import BigNumber from 'bignumber.js'; +import { formatAmount } from '@multiversx/sdk-dapp-utils/out/helpers'; +import { DECIMALS, DIGITS } from '@multiversx/sdk-dapp-utils/out/constants'; @Component({ tag: 'format-amount', @@ -7,11 +10,13 @@ import { Component, Prop, h } from '@stencil/core'; }) export class FormatAmount { @Prop() class?: string; - @Prop() isValid: boolean; - @Prop() label?: string; - @Prop() labelClass?: string; - @Prop() valueDecimal: string; - @Prop() valueInteger: string; + @Prop() decimals?: number = DECIMALS; + @Prop() digits?: number = DIGITS; + @Prop() egldLabel?: string; + @Prop() showLabel?: boolean = true; + @Prop() showLastNonZeroDecimal?: boolean = false; + @Prop() token?: string; + @Prop() value: string; private renderInvalid() { return ( @@ -24,25 +29,36 @@ export class FormatAmount { } private renderValid() { + const formattedValue = formatAmount({ + input: this.value, + decimals: this.decimals, + digits: this.digits, + showLastNonZeroDecimal: this.showLastNonZeroDecimal, + addCommas: true + }); + + const valueParts = formattedValue.split('.'); + const label = ` ${this.token ?? this.egldLabel ?? ''}`.trimEnd(); + return ( - {this.valueInteger} + {valueParts[0]} - {this.valueDecimal && ( + {valueParts.length > 1 && ( - .{this.valueDecimal} + .{valueParts[1]} )} - {this.label && ( + {this.showLabel && ( - {this.label} + {label} )} @@ -50,6 +66,7 @@ export class FormatAmount { } render() { - return this.isValid ? this.renderValid() : this.renderInvalid(); + const isInteger = new BigNumber(this.value).isInteger(); + return !isInteger ? this.renderInvalid() : this.renderValid(); } } diff --git a/src/components/format-amount/readme.md b/src/components/format-amount/readme.md index 645ff7d9..b26ccf11 100644 --- a/src/components/format-amount/readme.md +++ b/src/components/format-amount/readme.md @@ -7,14 +7,16 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| -------------- | --------------- | ----------- | --------- | ----------- | -| `class` | `class` | | `string` | `undefined` | -| `isValid` | `is-valid` | | `boolean` | `undefined` | -| `label` | `label` | | `string` | `undefined` | -| `labelClass` | `label-class` | | `string` | `undefined` | -| `valueDecimal` | `value-decimal` | | `string` | `undefined` | -| `valueInteger` | `value-integer` | | `string` | `undefined` | +| Property | Attribute | Description | Type | Default | +| ------------------------ | ---------------------------- | ----------- | --------- | ----------- | +| `class` | `class` | | `string` | `undefined` | +| `decimals` | `decimals` | | `number` | `DECIMALS` | +| `digits` | `digits` | | `number` | `DIGITS` | +| `egldLabel` | `egld-label` | | `string` | `undefined` | +| `showLabel` | `show-label` | | `boolean` | `true` | +| `showLastNonZeroDecimal` | `show-last-non-zero-decimal` | | `boolean` | `false` | +| `token` | `token` | | `string` | `undefined` | +| `value` | `value` | | `string` | `undefined` | ---------------------------------------------- diff --git a/src/components/format-amount/tests/format-amount.spec.ts b/src/components/format-amount/tests/format-amount.spec.ts index 49440fac..a72b28f3 100644 --- a/src/components/format-amount/tests/format-amount.spec.ts +++ b/src/components/format-amount/tests/format-amount.spec.ts @@ -1,16 +1,17 @@ import { newSpecPage } from '@stencil/core/testing'; import { FormatAmount } from '../format-amount'; -describe('FormatAmount component', () => { +describe('Format amount component when digits = 2', () => { const renderComponent = async (props: any) => { const page = await newSpecPage({ components: [FormatAmount], html: '', - supportsShadowDom: true, + supportsShadowDom: true }); const component = page.root; - Object.keys(props).forEach((key) => { + // Set each property individually + Object.keys(props).forEach(key => { component[key] = props[key]; }); @@ -30,64 +31,81 @@ describe('FormatAmount component', () => { .length; }; - it('should render valid amount with decimals', async () => { + it('should show 2 non zero decimals', async () => { const props = { - isValid: true, - valueInteger: '99999', - valueDecimal: '99', - label: 'EGLD', + value: '9999979999800000000000000', + showLastNonZeroDecimal: false, + showLabel: true, + digits: 2, + egldLabel: 'EGLD' }; const page = await renderComponent(props); - expect(page.root.shadowRoot.querySelector('span[data-testid="formatAmountInt"]').textContent).toBe('99999'); - expect(decimalsSelector(page)).toBe('.99'); + expect(await decimalsSelector(page)).toBe('.99'); }); - it('should not render decimals when valueDecimal is empty', async () => { + it('should show 2 zero decimals', async () => { const props = { - isValid: true, - valueInteger: '90000', - valueDecimal: '', - label: 'EGLD', + value: '9000000000000000000000000', + showLastNonZeroDecimal: false, + showLabel: true, + digits: 2, + egldLabel: 'EGLD' }; const page = await renderComponent(props); - expect(decimalsSelector(page)).toBe(undefined); + expect(await decimalsSelector(page)).toBe('.00'); }); - it('should render invalid state when isValid is false', async () => { + it('should show all non zero decimals when showLastNonZeroDecimal = true', async () => { const props = { - isValid: false, - valueInteger: '', - valueDecimal: '', - label: '', + value: '100000000000000', + showLastNonZeroDecimal: true, + showLabel: false, + digits: 2, + egldLabel: 'EGLD' }; const page = await renderComponent(props); - expect(page.root.shadowRoot.querySelector('span[data-testid="formatAmountInt"]').textContent).toBe('...'); + expect(await decimalsSelector(page)).toBe('.0001'); }); - it('should render symbol when label is provided', async () => { + it('should not show decimals when value is 0', async () => { const props = { - isValid: true, - valueInteger: '90000', - valueDecimal: '00', - label: 'EGLD', + value: '100000000000000', + showLastNonZeroDecimal: false, + showLabel: true, + digits: 2, + egldLabel: 'EGLD' }; const page = await renderComponent(props); - expect(symbolSelector(page)).toBe(1); + expect(await decimalsSelector(page)).toBe(undefined); }); - it('should not render symbol when label is not provided', async () => { + it('should show symbol', async () => { const props = { - isValid: true, - valueInteger: '90000', - valueDecimal: '00', - label: '', + value: '9000000000000000000000000', + showLastNonZeroDecimal: false, + showLabel: true, + digits: 2, + egldLabel: 'EGLD' }; const page = await renderComponent(props); - expect(symbolSelector(page)).toBe(0); + expect(await symbolSelector(page)).toBe(1); + }); + + it('should not show symbol', async () => { + const props = { + value: '9000000000000000000000000', + showLastNonZeroDecimal: false, + showLabel: false, + digits: 2, + egldLabel: 'EGLD' + }; + + const page = await renderComponent(props); + expect(await symbolSelector(page)).toBe(0); }); });