Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PBNTR-555] Currency Kit Updates #3832

Merged
merged 11 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
22 changes: 16 additions & 6 deletions playbook/app/pb_kits/playbook/pb_currency/_currency.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type CurrencyProps = {
variant?: 'default' | 'light' | 'bold',
unit?: string,
unstyled?: boolean,
commaSeparator?: boolean,
}

const sizes: {lg: 1, md: 3, sm: 4} = {
Expand Down Expand Up @@ -53,6 +54,7 @@ const Currency = (props: CurrencyProps): React.ReactElement => {
variant = 'default',
dark = false,
unstyled = false,
commaSeparator = false,
} = props

const emphasizedClass = emphasized ? '' : '_deemphasized'
Expand All @@ -74,7 +76,7 @@ const Currency = (props: CurrencyProps): React.ReactElement => {
className
)

const getFormattedNumber = (input: number | any ) => new Intl.NumberFormat('en-US', {
const getFormattedNumber = (input: number | any) => new Intl.NumberFormat('en-US', {
notation: 'compact',
maximumFractionDigits: 1,
}).format(input)
Expand All @@ -88,12 +90,20 @@ const Currency = (props: CurrencyProps): React.ReactElement => {
return isAmount ? num.slice(0, -1) : isUnit ? num.slice(-1) : ''
}

const getMatchingDecimalAmount = decimals === "matching" ? amount : whole,
getMatchingDecimalValue = decimals === "matching" ? '' : `.${decimal}`
const getMatchingDecimalAmount = decimals === "matching" ? amount : whole
const getMatchingDecimalValue = decimals === "matching" ? '' : `.${decimal}`

const getAmount = abbreviate ? getAbbreviatedValue('amount') : getMatchingDecimalAmount,
getAbbreviation = abbreviate ? getAbbreviatedValue('unit') : null,
getDecimalValue = abbreviate ? '' : getMatchingDecimalValue
const formatAmount = (amount: string) => {
if (!commaSeparator) return amount;

const [wholePart, decimalPart] = amount.split('.');
const formattedWhole = new Intl.NumberFormat('en-US').format(parseInt(wholePart));
return decimalPart ? `${formattedWhole}.${decimalPart}` : formattedWhole;
}

const getAmount = abbreviate ? getAbbreviatedValue('amount') : formatAmount(getMatchingDecimalAmount)
const getAbbreviation = abbreviate ? getAbbreviatedValue('unit') : null
const getDecimalValue = abbreviate ? '' : getMatchingDecimalValue

return (
<div
Expand Down
49 changes: 38 additions & 11 deletions playbook/app/pb_kits/playbook/pb_currency/currency.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ class Currency < Playbook::KitBase
prop :unstyled, type: Playbook::Props::Boolean,
default: false

prop :comma_separator, type: Playbook::Props::Boolean,
default: false

def classname
generate_classname("pb_currency_kit", align, size, dark_class)
end
Expand All @@ -65,7 +68,7 @@ def caption_props
def title_props
{
size: size_value,
text: abbreviate ? abbreviated_value : whole_value,
text: abbreviate ? abbreviated_value : formatted_amount,
classname: "pb_currency_value",
dark: dark,
}
Expand Down Expand Up @@ -96,28 +99,38 @@ def variant_class
private

def whole_value
return amount if decimals == "matching"

amount.split(".").first.to_s
value = amount.split(".").first
if comma_separator
number_with_delimiter(value.gsub(",", ""))
else
value
end
end

def abbreviated_value(index = 0..-2)
value = amount.split(".").first.split(",").join("")
abbreviated_num = number_to_human(value, units: { thousand: "K", million: "M", billion: "B", trillion: "T" }).gsub(/\s+/, "").to_s
abbreviated_num[index]
def decimal_value
amount.split(".")[1] || "00"
end

def units_element
return "" if decimals == "matching" && !abbreviate && !unit

_, decimal_part = amount.split(".")
if unit.nil? && abbreviate == false
decimal_part.nil? ? ".00" : ".#{decimal_part}"
if unit.nil? && !abbreviate
if decimals == "matching"
""
else
".#{decimal_value}"
end
else
abbreviate ? "#{abbreviated_value(-1)}#{unit}" : unit
end
end

def abbreviated_value(index = 0..-2)
value = amount.split(".").first.gsub(",", "").to_i
abbreviated_num = number_to_human(value, units: { thousand: "K", million: "M", billion: "B", trillion: "T" }).gsub(/\s+/, "")
abbreviated_num[index]
end

def size_value
case size
when "lg"
Expand All @@ -132,6 +145,20 @@ def size_value
def dark_class
dark ? "dark" : nil
end

def formatted_amount
return abbreviated_value if abbreviate

if decimals == "matching"
if comma_separator
number_with_delimiter(amount.gsub(",", ""))
else
amount
end
else
whole_value
end
end
end
end
end
35 changes: 35 additions & 0 deletions playbook/app/pb_kits/playbook/pb_currency/currency.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,38 @@ test('decimals default prop returns decimals as body text', () => {
expect(currencyKit.querySelector('.pb_currency_value')).toHaveTextContent('320')
expect(currencyKit.querySelector('.unit')).toHaveTextContent('.20')
})


test('commaSeparator prop returns comma separated amount', () => {
render(
<Currency
amount="1234567890"
commaSeparator
data={{ testid: 'comma-test' }}
/>
)
expect(screen.getByTestId('comma-test')).toHaveTextContent('1,234,567,890')
})

test('commaSeparator prop returns comma separated amount with decimals', () => {
render(
<Currency
amount="1234567890.12"
commaSeparator
data={{ testid: 'comma-test-decimals' }}
/>
)
expect(screen.getByTestId('comma-test-decimals')).toHaveTextContent('1,234,567,890.12')
})

test('commaSeparator prop returns comma separated amount with decimals="matching"', () => {
render(
<Currency
amount="1234567890.12"
commaSeparator
data={{ testid: 'comma-test-decimals-matching' }}
decimals="matching"
/>
)
expect(screen.getByTestId('comma-test-decimals-matching')).toHaveTextContent('1,234,567,890.12')
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<%= pb_rails("currency", props: {
amount: '1234567.89',
comma_separator: true,
size: 'lg',
emphasized: false,
decimals: 'matching',
}) %>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from "react"

import Currency from "../_currency"

const CurrencyCommaSeparator = (props) => {
return (
<Currency
amount='1234567.89'
commaSeparator
decimals="matching"
emphasized={false}
size="lg"
{...props}
/>
)
}

export default CurrencyCommaSeparator
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
The optional `commaSeparator` can be used to auto-format the use of commas as a thousands separator.

**NOTE:** If the value passed into the `amount` prop is already comma-dilineated, it will not add additional commas.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ examples:
- currency_abbreviated: Abbreviate Larger Amounts
- currency_matching_decimals: Matching Decimals
- currency_unstyled: Unstyled

- currency_comma_separator: Comma Separator

react:
- currency_variants: Variants
- currency_size: Size
Expand All @@ -17,6 +18,7 @@ examples:
- currency_abbreviated: Abbreviate Larger Amounts
- currency_matching_decimals: Matching Decimals
- currency_unstyled: Unstyled
- currency_comma_separator: Comma Separator

swift:
- currency_size_swift: Size
Expand Down
1 change: 1 addition & 0 deletions playbook/app/pb_kits/playbook/pb_currency/docs/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export { default as CurrencyNoSymbol } from './_currency_no_symbol.jsx'
export { default as CurrencyAbbreviated } from './_currency_abbreviated.jsx'
export { default as CurrencyMatchingDecimals } from './_currency_matching_decimals.jsx'
export { default as CurrencyUnstyled } from './_currency_unstyled.jsx'
export { default as CurrencyCommaSeparator } from './_currency_comma_separator.jsx'
9 changes: 9 additions & 0 deletions playbook/spec/pb_kits/playbook/pb_currency/currency_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
it { is_expected.to define_enum_prop(:variant).with_default("default").with_values("default", "light", "bold") }
it { is_expected.to define_prop(:abbreviate).with_default(false).of_type(Playbook::Props::Boolean) }
it { is_expected.to define_enum_prop(:decimals).with_default("default").with_values("default", "matching") }
it { is_expected.to define_prop(:comma_separator).with_default(false).of_type(Playbook::Props::Boolean) }

describe "#classname" do
it "returns namespaced class name", :aggregate_failures do
Expand Down Expand Up @@ -75,4 +76,12 @@
expect(num.body_props[:text]).to eq ".20"
end
end

describe "when prop commaSeparator is set to true" do
it "returns comma separated amount" do
num = subject.new(comma_separator: true, amount: "1234567890")

expect(num.title_props[:text]).to eq "1,234,567,890"
end
end
end
Loading