mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-03-18 02:21:47 -05:00
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:
parent
5f5ad4d5dd
commit
84e1f11494
4 changed files with 52 additions and 8 deletions
apps/admin-x-settings/src
admin-x-ds/global/form
components/settings/membership
|
@ -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
|
||||||
|
}
|
||||||
|
};
|
|
@ -2,17 +2,25 @@ import React, {useState} from 'react';
|
||||||
import TextField, {TextFieldProps} from './TextField';
|
import TextField, {TextFieldProps} from './TextField';
|
||||||
import {currencyFromDecimal, currencyToDecimal} from '../../../utils/currency';
|
import {currencyFromDecimal, currencyToDecimal} from '../../../utils/currency';
|
||||||
|
|
||||||
export type CurrencyFieldProps = Omit<TextFieldProps, 'type' | 'onChange'> & {
|
export type CurrencyFieldProps = Omit<TextFieldProps, 'type' | 'onChange' | 'value'> & {
|
||||||
currency?: string
|
valueInCents?: number;
|
||||||
onChange?: (value: number) => void
|
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> = ({
|
const CurrencyField: React.FC<CurrencyFieldProps> = ({
|
||||||
value,
|
valueInCents,
|
||||||
onChange,
|
onChange,
|
||||||
...props
|
...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
|
// 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, '');
|
const stripNonNumeric = (input: string) => input.replace(/[^\d.]+/g, '');
|
||||||
|
|
|
@ -105,7 +105,7 @@ const TipsOrDonations: React.FC<{ keywords: string[] }> = ({keywords}) => {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
title='Suggested amount'
|
title='Suggested amount'
|
||||||
value={donationsSuggestedAmount}
|
valueInCents={parseInt(donationsSuggestedAmount)}
|
||||||
onBlur={validate}
|
onBlur={validate}
|
||||||
onChange={cents => updateSetting('donations_suggested_amount', cents.toString())}
|
onChange={cents => updateSetting('donations_suggested_amount', cents.toString())}
|
||||||
onKeyDown={() => clearError('donationsSuggestedAmount')}
|
onKeyDown={() => clearError('donationsSuggestedAmount')}
|
||||||
|
|
|
@ -170,7 +170,7 @@ const TierDetailModal: React.FC<TierDetailModalProps> = ({tier}) => {
|
||||||
placeholder='1'
|
placeholder='1'
|
||||||
rightPlaceholder={`${formState.currency}/month`}
|
rightPlaceholder={`${formState.currency}/month`}
|
||||||
title='Monthly price'
|
title='Monthly price'
|
||||||
value={formState.monthly_price?.toString() || ''}
|
valueInCents={formState.monthly_price || 0}
|
||||||
hideTitle
|
hideTitle
|
||||||
onBlur={() => validators.monthly_price()}
|
onBlur={() => validators.monthly_price()}
|
||||||
onChange={price => updateForm(state => ({...state, monthly_price: price}))}
|
onChange={price => updateForm(state => ({...state, monthly_price: price}))}
|
||||||
|
@ -181,7 +181,7 @@ const TierDetailModal: React.FC<TierDetailModalProps> = ({tier}) => {
|
||||||
placeholder='10'
|
placeholder='10'
|
||||||
rightPlaceholder={`${formState.currency}/year`}
|
rightPlaceholder={`${formState.currency}/year`}
|
||||||
title='Yearly price'
|
title='Yearly price'
|
||||||
value={formState.yearly_price?.toString() || ''}
|
valueInCents={formState.yearly_price || 0}
|
||||||
hideTitle
|
hideTitle
|
||||||
onBlur={() => validators.yearly_price()}
|
onBlur={() => validators.yearly_price()}
|
||||||
onChange={price => updateForm(state => ({...state, yearly_price: price}))}
|
onChange={price => updateForm(state => ({...state, yearly_price: price}))}
|
||||||
|
|
Loading…
Add table
Reference in a new issue