Added stories for AdminX CurrencyField (#17882)

refs https://github.com/TryGhost/Product/issues/3745

---

This pull request adds a storybook file for the `CurrencyField`
component and changes its value prop to use cents instead of a string.
This improves the component's usability and consistency.
This commit is contained in:
Jono M 2023-08-31 07:50:18 +01:00 committed by GitHub
parent 5f5ad4d5dd
commit 84e1f11494
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 52 additions and 8 deletions

View File

@ -0,0 +1,36 @@
import {ReactNode} from 'react';
import {useArgs} from '@storybook/preview-api';
import type {Meta, StoryObj} from '@storybook/react';
import CurrencyField from './CurrencyField';
const meta = {
title: 'Global / Form / Currency field',
component: CurrencyField,
tags: ['autodocs'],
decorators: [(_story: () => ReactNode) => (<div style={{maxWidth: '400px'}}>{_story()}</div>)],
argTypes: {
hint: {
control: 'text'
},
rightPlaceholder: {
control: 'text'
}
}
} satisfies Meta<typeof CurrencyField>;
export default meta;
type Story = StoryObj<typeof CurrencyField>;
export const WithValue: Story = {
render: function Component(args) {
const [, updateArgs] = useArgs();
return <CurrencyField {...args} onChange={valueInCents => updateArgs({valueInCents})} />;
},
args: {
title: 'Amount',
hint: 'Notice how the value is the integer number of cents',
valueInCents: 500
}
};

View File

@ -2,17 +2,25 @@ import React, {useState} from 'react';
import TextField, {TextFieldProps} from './TextField';
import {currencyFromDecimal, currencyToDecimal} from '../../../utils/currency';
export type CurrencyFieldProps = Omit<TextFieldProps, 'type' | 'onChange'> & {
currency?: string
onChange?: (value: number) => void
export type CurrencyFieldProps = Omit<TextFieldProps, 'type' | 'onChange' | 'value'> & {
valueInCents?: number;
currency?: string;
onChange?: (cents: number) => void;
}
/**
* A CurrencyField is a special type of [TextField](?path=/docs/global-form-textfield--docs) with
* some parsing to input currency values. While editing you can enter any number of decimals, but
* the value in `onChange` will be rounded and multiplied to get an integer number of cents.
*
* Available options are generally the same as TextField.
*/
const CurrencyField: React.FC<CurrencyFieldProps> = ({
value,
valueInCents,
onChange,
...props
}) => {
const [localValue, setLocalValue] = useState(currencyToDecimal(parseInt(value || '0')).toString());
const [localValue, setLocalValue] = useState(currencyToDecimal(valueInCents || 0).toString());
// While the user is editing we allow more lenient input, e.g. "1.32.566" to make it easier to type and change
const stripNonNumeric = (input: string) => input.replace(/[^\d.]+/g, '');

View File

@ -105,7 +105,7 @@ const TipsOrDonations: React.FC<{ keywords: string[] }> = ({keywords}) => {
/>
)}
title='Suggested amount'
value={donationsSuggestedAmount}
valueInCents={parseInt(donationsSuggestedAmount)}
onBlur={validate}
onChange={cents => updateSetting('donations_suggested_amount', cents.toString())}
onKeyDown={() => clearError('donationsSuggestedAmount')}

View File

@ -170,7 +170,7 @@ const TierDetailModal: React.FC<TierDetailModalProps> = ({tier}) => {
placeholder='1'
rightPlaceholder={`${formState.currency}/month`}
title='Monthly price'
value={formState.monthly_price?.toString() || ''}
valueInCents={formState.monthly_price || 0}
hideTitle
onBlur={() => validators.monthly_price()}
onChange={price => updateForm(state => ({...state, monthly_price: price}))}
@ -181,7 +181,7 @@ const TierDetailModal: React.FC<TierDetailModalProps> = ({tier}) => {
placeholder='10'
rightPlaceholder={`${formState.currency}/year`}
title='Yearly price'
value={formState.yearly_price?.toString() || ''}
valueInCents={formState.yearly_price || 0}
hideTitle
onBlur={() => validators.yearly_price()}
onChange={price => updateForm(state => ({...state, yearly_price: price}))}