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..29625a73 --- /dev/null +++ b/packages/listview/src/components/CurrencyColumn/__test__/currencyColumn.spec.js @@ -0,0 +1,28 @@ +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(StyledCellContainer); + 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(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/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..1242fe62 --- /dev/null +++ b/packages/listview/src/components/CurrencyColumn/index.tsx @@ -0,0 +1,78 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { useLocale } from 'react-rainbow-components'; +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, cellAlignment, ...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, + /** Determines the alignment of the text in each column cell. */ + cellAlignment: PropTypes.oneOf(['left', 'right', 'center']), +}; + +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, + cellAlignment: 'right', +}; + +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..3cb574c6 --- /dev/null +++ b/packages/listview/src/components/CurrencyColumn/styled.ts @@ -0,0 +1,9 @@ +/* eslint-disable import/prefer-default-export */ +import styled from 'styled-components'; + +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 new file mode 100644 index 00000000..5386fd51 --- /dev/null +++ b/packages/listview/src/components/CurrencyColumn/types.ts @@ -0,0 +1,17 @@ +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; + cellAlignment?: 'left' | 'right' | 'center'; +}