From a1d6e602116ca52287c22106069315ccd0fa7a6f Mon Sep 17 00:00:00 2001 From: Yuri Victor Munayev Date: Sat, 29 Oct 2022 15:42:26 -0400 Subject: [PATCH 1/4] feat: add currency column component using intl formatter --- .../docs/components/CurrencyColumn.story.mdx | 19 +++ .../docs/stories/CurrencyColumn.story.js | 125 ++++++++++++++++++ .../__test__/currencyColumn.spec.js | 21 +++ .../CurrencyColumn/helpers/formatCurrency.ts | 19 +++ .../src/components/CurrencyColumn/index.tsx | 70 ++++++++++ .../src/components/CurrencyColumn/styled.ts | 8 ++ .../src/components/CurrencyColumn/types.ts | 16 +++ 7 files changed, 278 insertions(+) create mode 100644 packages/listview/docs/components/CurrencyColumn.story.mdx create mode 100644 packages/listview/docs/stories/CurrencyColumn.story.js create mode 100644 packages/listview/src/components/CurrencyColumn/__test__/currencyColumn.spec.js create mode 100644 packages/listview/src/components/CurrencyColumn/helpers/formatCurrency.ts create mode 100644 packages/listview/src/components/CurrencyColumn/index.tsx create mode 100644 packages/listview/src/components/CurrencyColumn/styled.ts create mode 100644 packages/listview/src/components/CurrencyColumn/types.ts diff --git a/packages/listview/docs/components/CurrencyColumn.story.mdx b/packages/listview/docs/components/CurrencyColumn.story.mdx new file mode 100644 index 00000000..960d9c7c --- /dev/null +++ b/packages/listview/docs/components/CurrencyColumn.story.mdx @@ -0,0 +1,19 @@ +import { Meta, Story, Preview, Props } from '@storybook/addon-docs/blocks'; +import CurrencyColumn from '../../src/components/CurrencyColumn'; +import * as stories from '../stories/CurrencyColumn.story.js'; + + + +# Overview + +`CurrencyColumn` is a column that renders the number passed as value. + +### This is an example with the CurrencyColumn. + + + {stories.currencyColumn()} + + +# Component props + + diff --git a/packages/listview/docs/stories/CurrencyColumn.story.js b/packages/listview/docs/stories/CurrencyColumn.story.js new file mode 100644 index 00000000..46c81ca4 --- /dev/null +++ b/packages/listview/docs/stories/CurrencyColumn.story.js @@ -0,0 +1,125 @@ +import React from 'react'; +import styled from 'styled-components'; +import { Table, Column, Application } from 'react-rainbow-components'; +import CurrencyColumn from '../../src/components/CurrencyColumn'; +import ColoredStatusColumn from '../../src/components/ColoredStatusColumn'; + +const initialData = [ + { + name: 'Carls Smith', + status: 'canceled', + company: 'Google', + amout: 0.1, + createdAt: '09/06/2020 09:00 AM', + }, + { + name: 'John Snow', + status: 'delivered', + company: 'Google', + amout: 0.25, + createdAt: '09/06/2020 09:00 AM', + }, + { + name: 'Anna Adams', + status: 'pending', + company: 'Google', + amout: 3045, + createdAt: '09/06/2020 09:00 AM', + }, + { + name: 'William Adams', + status: 'arrived', + company: 'Google', + amout: 0, + createdAt: '09/06/2020 09:00 AM', + }, + { + name: 'Joe Smith', + status: 'arrived', + company: 'Google', + amout: 100.85, + createdAt: '09/06/2020 09:00 AM', + }, + { + name: 'John Doe', + status: 'arrived', + company: 'Google', + amout: 1, + createdAt: '09/06/2020 09:00 AM', + }, + { + name: 'Jane Adams', + status: 'arrived', + company: 'Google', + amout: 120000.65, + createdAt: '09/06/2020 09:00 AM', + }, +]; + +const Container = styled.div` + padding: 2rem; +`; + +const colors = { + canceled: { backgroundColor: '#f2707a', color: 'rgba(255, 255, 255)' }, + delivered: '#009900', + pending: { backgroundColor: '#EBC665', color: '#fff' }, + arrived: { backgroundColor: '#4dc9cb', color: '#fff' }, +}; + +export const currencyColumn = () => { + return ( + + + + + + + + +
+
+
+ ); +}; + +export const currencyWithIntlOptionColumn = () => { + return ( + + + + + + + + +
+
+
+ ); +}; + +export default { + title: 'Modules/Listview/Stories/CurrencyColumn', + parameters: { + viewOnGithub: { + fileName: __filename, + }, + }, +}; diff --git a/packages/listview/src/components/CurrencyColumn/__test__/currencyColumn.spec.js b/packages/listview/src/components/CurrencyColumn/__test__/currencyColumn.spec.js new file mode 100644 index 00000000..fc9e2c8f --- /dev/null +++ b/packages/listview/src/components/CurrencyColumn/__test__/currencyColumn.spec.js @@ -0,0 +1,21 @@ +import React from 'react'; +import { mount } from 'enzyme'; +import CurrencyColumn from '../index'; + +describe('', () => { + it('should render a CurrencyColumn with the value passed', () => { + const wrapper = mount(); + const output = wrapper.find('span'); + expect(output.exists()).toBe(true); + expect(output.text()).toBe('$1.00'); + }); + + it('should render a CurrencyColumn with the value passed and intl options', () => { + const wrapper = mount( + , + ); + const output = wrapper.find('span'); + expect(output.exists()).toBe(true); + expect(output.text()).toBe('5,025.00 euros'); + }); +}); diff --git a/packages/listview/src/components/CurrencyColumn/helpers/formatCurrency.ts b/packages/listview/src/components/CurrencyColumn/helpers/formatCurrency.ts new file mode 100644 index 00000000..c1723d6c --- /dev/null +++ b/packages/listview/src/components/CurrencyColumn/helpers/formatCurrency.ts @@ -0,0 +1,19 @@ +interface Options { + currency?: string; + currencyDisplay?: 'symbol' | 'narrowSymbol' | 'code' | 'name'; + currencySign?: 'standard' | 'accounting'; + minimumIntegerDigits?: number; + minimumFractionDigits?: number; + maximumFractionDigits?: number; + minimumSignificantDigits?: number; + maximumSignificantDigits?: number; +} + +const formatCurrency = (value: number, locale: string, options: Options): string => { + return new Intl.NumberFormat(locale, { + style: 'currency', + ...options, + }).format(value); +}; + +export default formatCurrency; diff --git a/packages/listview/src/components/CurrencyColumn/index.tsx b/packages/listview/src/components/CurrencyColumn/index.tsx new file mode 100644 index 00000000..11be89e4 --- /dev/null +++ b/packages/listview/src/components/CurrencyColumn/index.tsx @@ -0,0 +1,70 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import useLocale from 'react-rainbow-components/libs/hooks/useLocale'; +import formatCurrency from './helpers/formatCurrency'; +import { StyledCellContainer } from './styled'; +import { CurrencyColumnProps } from './types'; + +const CurrencyColumn: React.FC = (props: CurrencyColumnProps) => { + const { value, locale: localeProp, className, style, ...rest } = props; + const locale = useLocale(localeProp); + const content = formatCurrency(value ?? 0, locale, rest); + + return ( + + {content} + + ); +}; + +CurrencyColumn.propTypes = { + /** A number that comes from the data and is displayed in the table cell */ + value: PropTypes.number, + /** The CurrencyColumn locale. Defaults to browser's language. */ + locale: PropTypes.string, + /** The currency to use in currency formatting. Possible values are the ISO 4217 currency codes. The default is "USD" */ + currency: PropTypes.string, + /** How to display the currency in currency formatting. The default is "symbol". */ + currencyDisplay: PropTypes.oneOf(['symbol', 'narrowSymbol', 'code', 'name']), + /** In many locales, accounting format means to wrap the number with parentheses instead of appending a minus sign. + * You can enable this formatting by setting the currencySign option to "accounting". The default value is "standard". */ + currencySign: PropTypes.oneOf(['standard', 'accounting']), + /** The minimum number of integer digits to use. + * A value with a smaller number of integer digits than this number will be left-padded with zeros (to the specified + * length) when formatted. Possible values are from 1 to 21; The default is 1. */ + minimumIntegerDigits: PropTypes.number, + /** The minimum number of fraction digits to use. Possible values are from 0 to 20; + * the default for currency formatting is the number of minor unit digits provided by the ISO 4217 currency code list + * (2 if the list doesn't provide that information). */ + minimumFractionDigits: PropTypes.number, + /** The maximum number of fraction digits to use. Possible values are from 0 to 20; + * the default for currency formatting is the larger of minimumFractionDigits and + * the number of minor unit digits provided by the ISO 4217 currency code list + * (2 if the list doesn't provide that information); */ + maximumFractionDigits: PropTypes.number, + /** The minimum number of significant digits to use. Possible values are from 1 to 21; The default is 1. */ + minimumSignificantDigits: PropTypes.number, + /** The maximum number of significant digits to use. Possible values are from 1 to 21; The default is 21. */ + maximumSignificantDigits: PropTypes.number, + /** A CSS class for the outer element, in addition to the component's base classes. */ + className: PropTypes.string, + /** An object with custom style applied to the outer element. */ + style: PropTypes.object, +}; + +CurrencyColumn.defaultProps = { + value: undefined, + locale: undefined, + currency: 'USD', + currencyDisplay: undefined, + currencySign: undefined, + minimumIntegerDigits: undefined, + minimumFractionDigits: undefined, + maximumFractionDigits: undefined, + minimumSignificantDigits: undefined, + maximumSignificantDigits: undefined, + className: undefined, + style: undefined, +}; + +export default CurrencyColumn; diff --git a/packages/listview/src/components/CurrencyColumn/styled.ts b/packages/listview/src/components/CurrencyColumn/styled.ts new file mode 100644 index 00000000..3363e601 --- /dev/null +++ b/packages/listview/src/components/CurrencyColumn/styled.ts @@ -0,0 +1,8 @@ +/* eslint-disable import/prefer-default-export */ +import styled from 'styled-components'; + +export const StyledCellContainer = styled.div` + padding: 0 5px; + overflow: hidden; + text-overflow: ellipsis; +`; diff --git a/packages/listview/src/components/CurrencyColumn/types.ts b/packages/listview/src/components/CurrencyColumn/types.ts new file mode 100644 index 00000000..b8a4ff57 --- /dev/null +++ b/packages/listview/src/components/CurrencyColumn/types.ts @@ -0,0 +1,16 @@ +import { CSSProperties } from 'react'; + +export interface CurrencyColumnProps { + value?: number; + locale?: string; + currency?: string; + currencyDisplay?: 'symbol' | 'narrowSymbol' | 'code' | 'name'; + currencySign?: 'standard' | 'accounting'; + minimumIntegerDigits?: number; + minimumFractionDigits?: number; + maximumFractionDigits?: number; + minimumSignificantDigits?: number; + maximumSignificantDigits?: number; + className?: string; + style?: CSSProperties; +} From aa7c86a2cf1e63cd2193b40f2cbbd14ee11affab Mon Sep 17 00:00:00 2001 From: Yuri Victor Munayev Date: Sat, 5 Nov 2022 16:49:58 -0400 Subject: [PATCH 2/4] fix: change title to container --- packages/listview/src/components/CurrencyColumn/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/listview/src/components/CurrencyColumn/index.tsx b/packages/listview/src/components/CurrencyColumn/index.tsx index 11be89e4..57cca3e5 100644 --- a/packages/listview/src/components/CurrencyColumn/index.tsx +++ b/packages/listview/src/components/CurrencyColumn/index.tsx @@ -11,8 +11,8 @@ const CurrencyColumn: React.FC = (props: CurrencyColumnProp const content = formatCurrency(value ?? 0, locale, rest); return ( - - {content} + + {content} ); }; From d73e0be9e35bc6b04827ee25a83783a2d1a43896 Mon Sep 17 00:00:00 2001 From: Yuri Victor Munayev Date: Sat, 5 Nov 2022 17:37:04 -0400 Subject: [PATCH 3/4] fix: useLocale import from react-rainbow-component --- package.json | 2 +- .../src/components/CurrencyColumn/index.tsx | 2 +- yarn.lock | 14 ++++++++++---- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 9b435be7..e427cf2d 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,7 @@ "react-dom": "^17.0.0", "react-intl": "^4.4.0", "react-query": "^3.34.0", - "react-rainbow-components": "1.31.0-canary.300d49e", + "react-rainbow-components": "1.31.0-canary.6ccebb7", "react-redux": "^7.2.0", "react-router-dom": "^5.0.0", "redux": "^4.0.5", diff --git a/packages/listview/src/components/CurrencyColumn/index.tsx b/packages/listview/src/components/CurrencyColumn/index.tsx index 57cca3e5..0adf796d 100644 --- a/packages/listview/src/components/CurrencyColumn/index.tsx +++ b/packages/listview/src/components/CurrencyColumn/index.tsx @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import useLocale from 'react-rainbow-components/libs/hooks/useLocale'; +import { useLocale } from 'react-rainbow-components'; import formatCurrency from './helpers/formatCurrency'; import { StyledCellContainer } from './styled'; import { CurrencyColumnProps } from './types'; diff --git a/yarn.lock b/yarn.lock index e9579897..0b57cb6a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4325,6 +4325,11 @@ resolved "https://registry.yarnpkg.com/@rainbow-modules/icons/-/icons-0.44.0.tgz#900ed90dcdf87e845a90eb3f9010d359b9d2a122" integrity sha512-JUhsEYi6x+Lqq0wO2Tn7Dnga+zXc4NmIRV4H/aeq96rWnIdeOeQh5LsFtznNR5a5qvSQ9BgDOkaatQvj7msm2A== +"@rainbow-modules/validation@^0.53.0": + version "0.53.0" + resolved "https://registry.yarnpkg.com/@rainbow-modules/validation/-/validation-0.53.0.tgz#2c81b3e5bb61bc2daa4506a6d33ef239b6ae50e9" + integrity sha512-NfnQv6jDk8xIeLyS2lAFK/sZ7VPfLPpCJnxjkj+Ib0XVqsdcc01CYcSdJUax2gR2B6TAoarU+E6KeEpA7aSyow== + "@samverschueren/stream-to-observable@^0.3.0": version "0.3.1" resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.1.tgz#a21117b19ee9be70c379ec1877537ef2e1c63301" @@ -18608,12 +18613,13 @@ react-query@^3.34.0: broadcast-channel "^3.4.1" match-sorter "^6.0.2" -react-rainbow-components@1.31.0-canary.300d49e: - version "1.31.0-canary.300d49e" - resolved "https://registry.yarnpkg.com/react-rainbow-components/-/react-rainbow-components-1.31.0-canary.300d49e.tgz#c0dcb98cf69944748a79a094d19fe36944631dd4" - integrity sha512-66mdV02noS8rmPYxe5KGsenpuD7BxMqvNTXfMhitoN+VhVt3BBef4C5nGKmAmynogOlWiibM6L4COi8FDESSJg== +react-rainbow-components@1.31.0-canary.6ccebb7: + version "1.31.0-canary.6ccebb7" + resolved "https://registry.yarnpkg.com/react-rainbow-components/-/react-rainbow-components-1.31.0-canary.6ccebb7.tgz#ad85a9264f5d86864bb71e730496e8181d6dafca" + integrity sha512-L82R9j0G35p3oa1Ji66UZ55xfcHAaFTLOaghja7gIaQz6jeximwcY9AebI/s0CM+OuhdrZV2mc9mpBV4lWFGzw== dependencies: "@rainbow-modules/hooks" "^0.12.0" + "@rainbow-modules/validation" "^0.53.0" autosize "^4.0.2" chart.js "2.9.4" clipboard-copy "^2.0.0" From 41ef790d110ef136de66fc0d938bc1a266d5957d Mon Sep 17 00:00:00 2001 From: Yuri Victor Munayev Date: Sun, 6 Nov 2022 11:50:54 -0500 Subject: [PATCH 4/4] feat: add cellAlignment prop --- .../CurrencyColumn/__test__/currencyColumn.spec.js | 11 +++++++++-- .../listview/src/components/CurrencyColumn/index.tsx | 12 ++++++++++-- .../listview/src/components/CurrencyColumn/styled.ts | 3 ++- .../listview/src/components/CurrencyColumn/types.ts | 1 + 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/packages/listview/src/components/CurrencyColumn/__test__/currencyColumn.spec.js b/packages/listview/src/components/CurrencyColumn/__test__/currencyColumn.spec.js index fc9e2c8f..29625a73 100644 --- a/packages/listview/src/components/CurrencyColumn/__test__/currencyColumn.spec.js +++ b/packages/listview/src/components/CurrencyColumn/__test__/currencyColumn.spec.js @@ -1,11 +1,12 @@ import React from 'react'; import { mount } from 'enzyme'; import CurrencyColumn from '../index'; +import { StyledCellContainer } from '../styled'; describe('', () => { it('should render a CurrencyColumn with the value passed', () => { const wrapper = mount(); - const output = wrapper.find('span'); + const output = wrapper.find(StyledCellContainer); expect(output.exists()).toBe(true); expect(output.text()).toBe('$1.00'); }); @@ -14,8 +15,14 @@ describe('', () => { const wrapper = mount( , ); - const output = wrapper.find('span'); + const output = wrapper.find(StyledCellContainer); expect(output.exists()).toBe(true); expect(output.text()).toBe('5,025.00 euros'); }); + it('should render a center text whne cellAlignment is center', () => { + const wrapper = mount(); + const output = wrapper.find(StyledCellContainer); + expect(output.exists()).toBe(true); + expect(output.prop('cellAlignment')).toBe('center'); + }); }); diff --git a/packages/listview/src/components/CurrencyColumn/index.tsx b/packages/listview/src/components/CurrencyColumn/index.tsx index 0adf796d..1242fe62 100644 --- a/packages/listview/src/components/CurrencyColumn/index.tsx +++ b/packages/listview/src/components/CurrencyColumn/index.tsx @@ -6,12 +6,17 @@ import { StyledCellContainer } from './styled'; import { CurrencyColumnProps } from './types'; const CurrencyColumn: React.FC = (props: CurrencyColumnProps) => { - const { value, locale: localeProp, className, style, ...rest } = props; + const { value, locale: localeProp, className, style, cellAlignment, ...rest } = props; const locale = useLocale(localeProp); const content = formatCurrency(value ?? 0, locale, rest); return ( - + {content} ); @@ -50,6 +55,8 @@ CurrencyColumn.propTypes = { className: PropTypes.string, /** An object with custom style applied to the outer element. */ style: PropTypes.object, + /** Determines the alignment of the text in each column cell. */ + cellAlignment: PropTypes.oneOf(['left', 'right', 'center']), }; CurrencyColumn.defaultProps = { @@ -65,6 +72,7 @@ CurrencyColumn.defaultProps = { maximumSignificantDigits: undefined, className: undefined, style: undefined, + cellAlignment: 'right', }; export default CurrencyColumn; diff --git a/packages/listview/src/components/CurrencyColumn/styled.ts b/packages/listview/src/components/CurrencyColumn/styled.ts index 3363e601..3cb574c6 100644 --- a/packages/listview/src/components/CurrencyColumn/styled.ts +++ b/packages/listview/src/components/CurrencyColumn/styled.ts @@ -1,8 +1,9 @@ /* eslint-disable import/prefer-default-export */ import styled from 'styled-components'; -export const StyledCellContainer = styled.div` +export const StyledCellContainer = styled.div<{ cellAlignment?: 'left' | 'right' | 'center' }>` padding: 0 5px; overflow: hidden; text-overflow: ellipsis; + text-align: ${(props) => props.cellAlignment}; `; diff --git a/packages/listview/src/components/CurrencyColumn/types.ts b/packages/listview/src/components/CurrencyColumn/types.ts index b8a4ff57..5386fd51 100644 --- a/packages/listview/src/components/CurrencyColumn/types.ts +++ b/packages/listview/src/components/CurrencyColumn/types.ts @@ -13,4 +13,5 @@ export interface CurrencyColumnProps { maximumSignificantDigits?: number; className?: string; style?: CSSProperties; + cellAlignment?: 'left' | 'right' | 'center'; }