Skip to content

Commit c5604fb

Browse files
authored
chore: Improve configuration step form components (#2461)
* add checkbox and radio components * f * f
1 parent e388d2e commit c5604fb

File tree

7 files changed

+227
-94
lines changed

7 files changed

+227
-94
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import React from 'react';
2+
import { useSettings } from '../../contexts/SettingsContext';
3+
4+
interface CheckboxProps {
5+
id: string;
6+
label: string;
7+
helpText?: string;
8+
error?: string;
9+
required?: boolean;
10+
checked: boolean;
11+
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
12+
disabled?: boolean;
13+
className?: string;
14+
labelClassName?: string;
15+
dataTestId?: string;
16+
}
17+
18+
const Checkbox: React.FC<CheckboxProps> = ({
19+
id,
20+
label,
21+
helpText,
22+
error,
23+
required,
24+
checked,
25+
onChange,
26+
disabled = false,
27+
className = '',
28+
labelClassName = '',
29+
dataTestId,
30+
}) => {
31+
const { settings } = useSettings();
32+
const themeColor = settings.themeColor;
33+
34+
return (
35+
<div className="mb-4">
36+
<div className="flex items-center space-x-3">
37+
<input
38+
id={id}
39+
type="checkbox"
40+
checked={checked}
41+
onChange={onChange}
42+
disabled={disabled}
43+
className={`h-4 w-4 focus:ring-offset-2 border-gray-300 rounded ${className}`}
44+
data-testid={dataTestId}
45+
style={{
46+
color: themeColor,
47+
'--tw-ring-color': themeColor,
48+
accentColor: themeColor,
49+
} as React.CSSProperties}
50+
/>
51+
<label htmlFor={id} className={`text-sm text-gray-700 ${labelClassName}`}>
52+
{label}
53+
{required && <span className="text-red-500 ml-1">*</span>}
54+
</label>
55+
</div>
56+
{error && <p className="mt-1 text-sm text-red-500">{error}</p>}
57+
{helpText && !error && <p className="mt-1 text-sm text-gray-500">{helpText}</p>}
58+
</div>
59+
);
60+
};
61+
62+
export default Checkbox;

web/src/components/common/Input.tsx

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,38 +4,38 @@ import { useSettings } from '../../contexts/SettingsContext';
44
interface InputProps {
55
id: string;
66
label: string;
7+
helpText?: string;
8+
error?: string;
9+
required?: boolean;
710
type?: string;
811
value: string;
9-
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
12+
icon?: React.ReactNode;
13+
placeholder?: string;
1014
onKeyDown?: (e: React.KeyboardEvent) => void;
15+
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
1116
onFocus?: (e: React.FocusEvent<HTMLInputElement>) => void;
12-
placeholder?: string;
13-
required?: boolean;
1417
disabled?: boolean;
15-
error?: string;
16-
helpText?: string;
1718
className?: string;
1819
labelClassName?: string;
19-
icon?: React.ReactNode;
2020
dataTestId?: string;
2121
}
2222

2323
const Input: React.FC<InputProps> = ({
2424
id,
2525
label,
26+
helpText,
27+
error,
28+
required,
2629
type = 'text',
2730
value,
28-
onChange,
31+
icon,
32+
placeholder = '',
2933
onKeyDown,
34+
onChange,
3035
onFocus,
31-
placeholder = '',
32-
required = false,
3336
disabled = false,
34-
error,
35-
helpText,
3637
className = '',
3738
labelClassName = '',
38-
icon,
3939
dataTestId,
4040
}) => {
4141
const { settings } = useSettings();

web/src/components/common/Label.tsx

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import React from 'react';
2+
import Markdown from 'react-markdown';
3+
import remarkGfm from 'remark-gfm';
4+
5+
interface LabelProps {
6+
content: string;
7+
className?: string;
8+
dataTestId?: string;
9+
}
10+
11+
const Label: React.FC<LabelProps> = ({
12+
content,
13+
className = '',
14+
dataTestId,
15+
}) => {
16+
return (
17+
<div className={`mb-4 ${className}`} data-testid={dataTestId}>
18+
<div className="prose prose-sm prose-gray max-w-none">
19+
<Markdown
20+
remarkPlugins={[remarkGfm]}
21+
components={{
22+
a: ({ ...props }) => (
23+
<a
24+
{...props}
25+
target="_blank"
26+
rel="noopener noreferrer"
27+
className="text-blue-600 hover:text-blue-800 underline"
28+
/>
29+
),
30+
}}
31+
>
32+
{content}
33+
</Markdown>
34+
</div>
35+
</div>
36+
);
37+
};
38+
39+
export default Label;

web/src/components/common/Radio.tsx

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import React from 'react';
2+
import { useSettings } from '../../contexts/SettingsContext';
3+
import { AppConfigChildItem } from '../../types';
4+
5+
interface RadioProps {
6+
id: string;
7+
label: string;
8+
helpText?: string;
9+
error?: string;
10+
required?: boolean;
11+
value: string;
12+
options: AppConfigChildItem[];
13+
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
14+
disabled?: boolean;
15+
className?: string;
16+
labelClassName?: string;
17+
}
18+
19+
const Radio: React.FC<RadioProps> = ({
20+
id,
21+
label,
22+
helpText,
23+
error,
24+
required,
25+
value,
26+
options,
27+
onChange,
28+
disabled = false,
29+
className = '',
30+
labelClassName = '',
31+
}) => {
32+
const { settings } = useSettings();
33+
const themeColor = settings.themeColor;
34+
35+
return (
36+
<div className="mb-4">
37+
<label className={`block text-sm font-medium text-gray-700 mb-2 ${labelClassName}`}>
38+
{label}
39+
{required && <span className="text-red-500 ml-1">*</span>}
40+
</label>
41+
<div className="space-y-2">
42+
{options.map(option => (
43+
<div key={option.name} className="flex items-center">
44+
<input
45+
type="radio"
46+
id={option.name}
47+
name={id}
48+
value={option.name}
49+
checked={value === option.name}
50+
onChange={onChange}
51+
disabled={disabled}
52+
className={`h-4 w-4 focus:ring-offset-2 border-gray-300 ${className}`}
53+
data-testid={`radio-input-${option.name}`}
54+
style={{
55+
color: themeColor,
56+
'--tw-ring-color': themeColor,
57+
accentColor: themeColor,
58+
} as React.CSSProperties}
59+
/>
60+
<label htmlFor={option.name} className="ml-3 text-sm text-gray-700">
61+
{option.title}
62+
</label>
63+
</div>
64+
))}
65+
</div>
66+
{error && <p className="mt-1 text-sm text-red-500">{error}</p>}
67+
{helpText && !error && <p className="mt-1 text-sm text-gray-500">{helpText}</p>}
68+
</div>
69+
);
70+
};
71+
72+
export default Radio;

web/src/components/common/Textarea.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ import { useSettings } from '../../contexts/SettingsContext';
44
interface TextareaProps {
55
id: string;
66
label: string;
7+
helpText?: string;
8+
error?: string;
9+
required?: boolean;
710
value: string;
8-
onChange: (e: ChangeEvent<HTMLTextAreaElement>) => void;
911
rows?: number;
1012
placeholder?: string;
11-
required?: boolean;
13+
onChange: (e: ChangeEvent<HTMLTextAreaElement>) => void;
1214
disabled?: boolean;
13-
error?: string;
14-
helpText?: string;
1515
className?: string;
1616
labelClassName?: string;
1717
dataTestId?: string;
@@ -20,14 +20,14 @@ interface TextareaProps {
2020
const Textarea = ({
2121
id,
2222
label,
23+
helpText,
24+
error,
25+
required = false,
2326
value,
24-
onChange,
2527
rows = 4,
2628
placeholder = '',
27-
required = false,
29+
onChange,
2830
disabled = false,
29-
error,
30-
helpText,
3131
className = '',
3232
labelClassName = '',
3333
dataTestId,

0 commit comments

Comments
 (0)