Skip to content

Commit 0d48c37

Browse files
committed
feat: Enhance ControlledCurrencyInput and FormIntegrationExamples stories
- Updated ControlledCurrencyInput stories to include currency symbol and code as props for better flexibility. - Refactored validation schemas to use string types for price inputs, ensuring consistent handling of numeric values. - Improved FormIntegrationExamples by adding missing imports and refining form handling logic for better readability. - Enhanced error handling and validation messages across various form components, ensuring a more robust user experience.
1 parent 67fe131 commit 0d48c37

3 files changed

Lines changed: 232 additions & 137 deletions

File tree

apps/docs/src/medusa-forms/ControlledCurrencyInput.stories.tsx

Lines changed: 146 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
import { zodResolver } from '@hookform/resolvers/zod';
12
import { ControlledCurrencyInput } from '@lambdacurry/medusa-forms/controlled/ControlledCurrencyInput';
23
import type { Meta, StoryObj } from '@storybook/react-vite';
34
import { FormProvider, useForm } from 'react-hook-form';
4-
import { zodResolver } from '@hookform/resolvers/zod';
55
import { z } from 'zod';
66

77
const meta = {
@@ -11,30 +11,49 @@ const meta = {
1111
layout: 'centered',
1212
},
1313
tags: ['autodocs'],
14+
args: {
15+
symbol: '$',
16+
code: 'usd',
17+
},
1418
} satisfies Meta<typeof ControlledCurrencyInput>;
1519

1620
export default meta;
1721
type Story = StoryObj<typeof meta>;
1822

23+
interface CurrencyFormData {
24+
price: string;
25+
}
26+
1927
// Base wrapper component for stories
20-
const CurrencyInputWithHookForm = ({
21-
currency = 'USD',
28+
const CurrencyInputWithHookForm = ({
29+
currency = 'USD',
30+
symbol = '$',
31+
code = 'usd',
2232
schema,
2333
defaultValues = { price: '' },
24-
...props
34+
...props
35+
}: {
36+
currency?: string;
37+
symbol?: string;
38+
code?: string;
39+
schema?: z.ZodSchema<any>;
40+
defaultValues?: CurrencyFormData;
41+
[key: string]: any;
2542
}) => {
26-
const form = useForm({
43+
const form = useForm<CurrencyFormData>({
2744
resolver: schema ? zodResolver(schema) : undefined,
2845
defaultValues,
2946
});
3047

3148
return (
3249
<FormProvider {...form}>
3350
<div className="w-[400px]">
34-
<ControlledCurrencyInput
35-
name="price"
36-
label="Price"
51+
<ControlledCurrencyInput
52+
name="price"
53+
label="Price"
3754
currency={currency}
55+
symbol={symbol}
56+
code={code}
3857
{...props}
3958
/>
4059
</div>
@@ -44,74 +63,129 @@ const CurrencyInputWithHookForm = ({
4463

4564
// 1. Different Currency Symbols
4665
export const USDCurrency: Story = {
47-
render: () => <CurrencyInputWithHookForm currency="USD" />,
66+
args: {
67+
name: 'price',
68+
symbol: '$',
69+
code: 'usd',
70+
},
71+
render: (args) => <CurrencyInputWithHookForm currency="USD" symbol={args.symbol} code={args.code} />,
4872
};
4973

5074
export const EURCurrency: Story = {
51-
render: () => <CurrencyInputWithHookForm currency="EUR" />,
75+
args: {
76+
name: 'price',
77+
symbol: '€',
78+
code: 'eur',
79+
},
80+
render: (args) => <CurrencyInputWithHookForm currency="EUR" symbol={args.symbol} code={args.code} />,
5281
};
5382

5483
export const GBPCurrency: Story = {
55-
render: () => <CurrencyInputWithHookForm currency="GBP" />,
84+
args: {
85+
name: 'price',
86+
symbol: '£',
87+
code: 'gbp',
88+
},
89+
render: (args) => <CurrencyInputWithHookForm currency="GBP" symbol={args.symbol} code={args.code} />,
5690
};
5791

5892
// 2. Validation with Min/Max Values
5993
const minValidationSchema = z.object({
60-
price: z.number().min(10, 'Minimum price is $10'),
94+
price: z.string().refine((val) => {
95+
const num = Number.parseFloat(val);
96+
return !Number.isNaN(num) && num >= 10;
97+
}, 'Minimum price is $10'),
6198
});
6299

63100
export const MinimumValueValidation: Story = {
64-
render: () => (
65-
<CurrencyInputWithHookForm
101+
args: {
102+
name: 'price',
103+
symbol: '$',
104+
code: 'usd',
105+
},
106+
render: (args) => (
107+
<CurrencyInputWithHookForm
66108
currency="USD"
109+
symbol={args.symbol}
110+
code={args.code}
67111
schema={minValidationSchema}
68-
defaultValues={{ price: 5 }}
112+
defaultValues={{ price: '5' }}
69113
label="Price (Min $10)"
70114
/>
71115
),
72116
};
73117

74118
const maxValidationSchema = z.object({
75-
price: z.number().max(1000, 'Maximum price is $1000'),
119+
price: z.string().refine((val) => {
120+
const num = Number.parseFloat(val);
121+
return !Number.isNaN(num) && num <= 1000;
122+
}, 'Maximum price is $1000'),
76123
});
77124

78125
export const MaximumValueValidation: Story = {
79-
render: () => (
80-
<CurrencyInputWithHookForm
126+
args: {
127+
name: 'price',
128+
symbol: '$',
129+
code: 'usd',
130+
},
131+
render: (args) => (
132+
<CurrencyInputWithHookForm
81133
currency="USD"
134+
symbol={args.symbol}
135+
code={args.code}
82136
schema={maxValidationSchema}
83-
defaultValues={{ price: 1500 }}
137+
defaultValues={{ price: '1500' }}
84138
label="Price (Max $1000)"
85139
/>
86140
),
87141
};
88142

89143
const rangeValidationSchema = z.object({
90-
price: z.number()
91-
.min(50, 'Price must be at least $50')
92-
.max(500, 'Price cannot exceed $500'),
144+
price: z.string().refine((val) => {
145+
const num = Number.parseFloat(val);
146+
return !Number.isNaN(num) && num >= 50 && num <= 500;
147+
}, 'Price must be between $50 and $500'),
93148
});
94149

95150
export const RangeValidation: Story = {
96-
render: () => (
97-
<CurrencyInputWithHookForm
151+
args: {
152+
name: 'price',
153+
symbol: '$',
154+
code: 'usd',
155+
},
156+
render: (args) => (
157+
<CurrencyInputWithHookForm
98158
currency="USD"
159+
symbol={args.symbol}
160+
code={args.code}
99161
schema={rangeValidationSchema}
100-
defaultValues={{ price: 25 }}
162+
defaultValues={{ price: '25' }}
101163
label="Price ($50 - $500)"
102164
/>
103165
),
104166
};
105167

106168
// 3. Error Handling and Validation Messages
107169
const requiredSchema = z.object({
108-
price: z.number().min(0.01, 'Price is required'),
170+
price: z
171+
.string()
172+
.min(1, 'Price is required')
173+
.refine((val) => {
174+
const num = Number.parseFloat(val);
175+
return !Number.isNaN(num) && num > 0;
176+
}, 'Price must be greater than 0'),
109177
});
110178

111179
export const RequiredFieldValidation: Story = {
112-
render: () => (
113-
<CurrencyInputWithHookForm
180+
args: {
181+
symbol: '$',
182+
code: 'usd',
183+
},
184+
render: (args) => (
185+
<CurrencyInputWithHookForm
114186
currency="USD"
187+
symbol={args.symbol}
188+
code={args.code}
115189
schema={requiredSchema}
116190
label="Required Price *"
117191
required
@@ -120,50 +194,75 @@ export const RequiredFieldValidation: Story = {
120194
};
121195

122196
const customValidationSchema = z.object({
123-
price: z.number()
124-
.min(1, 'Custom error: Price must be at least $1')
125-
.max(100, 'Custom error: Price cannot exceed $100'),
197+
price: z.string().refine((val) => {
198+
const num = Number.parseFloat(val);
199+
return !Number.isNaN(num) && num >= 1 && num <= 100;
200+
}, 'Custom error: Price must be between $1 and $100'),
126201
});
127202

128203
export const CustomValidationMessage: Story = {
129-
render: () => (
130-
<CurrencyInputWithHookForm
204+
args: {
205+
symbol: '$',
206+
code: 'usd',
207+
},
208+
render: (args) => (
209+
<CurrencyInputWithHookForm
131210
currency="USD"
211+
symbol={args.symbol}
212+
code={args.code}
132213
schema={customValidationSchema}
133-
defaultValues={{ price: 150 }}
214+
defaultValues={{ price: '150' }}
134215
label="Custom Validation Messages"
135216
/>
136217
),
137218
};
138219

139220
// 4. Different Currency Codes
140221
export const JPYCurrency: Story = {
141-
render: () => (
142-
<CurrencyInputWithHookForm
143-
currency="JPY"
144-
defaultValues={{ price: 11000 }}
222+
args: {
223+
symbol: '¥',
224+
code: 'jpy',
225+
},
226+
render: (args) => (
227+
<CurrencyInputWithHookForm
228+
currency="JPY"
229+
symbol={args.symbol}
230+
code={args.code}
231+
defaultValues={{ price: '11000' }}
145232
label="Price (JPY)"
146233
/>
147234
),
148235
};
149236

150237
export const CADCurrency: Story = {
151-
render: () => (
152-
<CurrencyInputWithHookForm
153-
currency="CAD"
154-
defaultValues={{ price: 125.75 }}
238+
args: {
239+
symbol: 'C$',
240+
code: 'cad',
241+
},
242+
render: (args) => (
243+
<CurrencyInputWithHookForm
244+
currency="CAD"
245+
symbol={args.symbol}
246+
code={args.code}
247+
defaultValues={{ price: '125.75' }}
155248
label="Price (CAD)"
156249
/>
157250
),
158251
};
159252

160253
export const AUDCurrency: Story = {
161-
render: () => (
162-
<CurrencyInputWithHookForm
163-
currency="AUD"
164-
defaultValues={{ price: 135.50 }}
254+
args: {
255+
name: 'price',
256+
symbol: 'A$',
257+
code: 'aud',
258+
},
259+
render: (args) => (
260+
<CurrencyInputWithHookForm
261+
currency="AUD"
262+
symbol={args.symbol}
263+
code={args.code}
264+
defaultValues={{ price: '135.50' }}
165265
label="Price (AUD)"
166266
/>
167267
),
168268
};
169-

0 commit comments

Comments
 (0)