Skip to content

Commit e47bf8b

Browse files
authored
chore: Remove react-form package (#1952)
### 💡 Overview Remove react-form and use native form implementation
1 parent 58e0bc4 commit e47bf8b

File tree

3 files changed

+51
-129
lines changed

3 files changed

+51
-129
lines changed
Lines changed: 51 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import { HTMLInputTypeAttribute, useCallback, useMemo, useState } from 'react';
1+
import { FormEvent, useCallback, useState } from 'react';
22
import clsx from 'clsx';
3-
import { useField, useForm } from 'react-form';
43
import { Icon, useCall, useMenuContext } from '@stream-io/video-react-sdk';
54
import { getCookie } from '../../helpers/getCookie';
65

@@ -10,89 +9,30 @@ export type Props = {
109
inMeeting?: boolean;
1110
};
1211

13-
function required(value: string | number, name: string) {
14-
if (!value) {
15-
return `Please enter a ${name}`;
16-
}
17-
return false;
18-
}
19-
20-
const Input = (props: {
21-
className?: string;
22-
type: HTMLInputTypeAttribute;
23-
placeholder: string;
24-
name: string;
25-
required?: boolean;
26-
}) => {
27-
const { name, className, ...rest } = props;
28-
const {
29-
meta: { error, isTouched },
30-
getInputProps,
31-
} = useField(name, {
32-
validate: props.required ? (value) => required(value, name) : undefined,
33-
});
34-
35-
return (
36-
<input
37-
className={clsx(className, isTouched && error && 'rd__feedback-error')}
38-
{...getInputProps()}
39-
{...rest}
40-
/>
41-
);
42-
};
43-
44-
const TextArea = (props: {
45-
placeholder: string;
46-
name: string;
47-
required?: boolean;
48-
}) => {
49-
const { name, ...rest } = props;
50-
const {
51-
meta: { error, isTouched },
52-
getInputProps,
53-
} = useField(name, {
54-
validate: props.required ? (value) => required(value, name) : undefined,
55-
});
56-
57-
return (
58-
<textarea
59-
className={clsx(
60-
'rd__feedback-textarea',
61-
isTouched && error && 'rd__feedback-error',
62-
)}
63-
{...getInputProps()}
64-
{...rest}
65-
/>
66-
);
67-
};
68-
69-
type FeedbackFormType = {
70-
email?: string;
71-
message?: string;
72-
};
73-
7412
const basePath = process.env.NEXT_PUBLIC_BASE_PATH || '';
7513

7614
export const Feedback = ({ callId, inMeeting = true }: Props) => {
7715
const [rating, setRating] = useState({ current: 0, maxAmount: 5 });
16+
const [email, setEmail] = useState('');
17+
const [message, setMessage] = useState('');
18+
const [isSubmitting, setIsSubmitting] = useState(false);
19+
7820
const [feedbackSent, setFeedbackSent] = useState(false);
7921
const [errorMessage, setError] = useState<string | null>(null);
8022
const call = useCall();
81-
const defaultValues = useMemo<FeedbackFormType>(
82-
() => ({ email: '', message: '' }),
83-
[],
84-
);
85-
const {
86-
Form,
87-
meta: { isSubmitting },
88-
} = useForm({
89-
defaultValues,
90-
onSubmit: async (values: FeedbackFormType) => {
23+
24+
const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
25+
e.preventDefault();
26+
27+
setIsSubmitting(true);
28+
29+
try {
9130
await call
9231
?.submitFeedback(Math.min(Math.max(1, rating.current), 5), {
93-
reason: values.message,
32+
reason: message,
9433
custom: {
95-
...values,
34+
message,
35+
email,
9636
},
9737
})
9838
.catch((err) => console.warn(`Failed to submit call feedback`, err));
@@ -101,31 +41,29 @@ export const Feedback = ({ callId, inMeeting = true }: Props) => {
10141
pageUrl.searchParams.set('meeting', inMeeting ? 'true' : 'false');
10242
pageUrl.searchParams.set('id', callId || call?.id || '');
10343

104-
const response = await fetch(
105-
`https://getstream.io/api/crm/video_feedback/`,
106-
{
107-
method: 'POST',
108-
headers: {
109-
Accept: 'application/json',
110-
'Content-Type': 'application/json',
111-
'X-CSRFToken': getCookie('csrftoken') || '',
112-
},
113-
body: JSON.stringify({
114-
email: values.email || '[email protected]',
115-
message: values.message || '<no-message-provided>',
116-
rating: rating.current,
117-
page_url: pageUrl.toString(),
118-
}),
44+
await fetch(`https://getstream.io/api/crm/video_feedback/`, {
45+
method: 'POST',
46+
headers: {
47+
Accept: 'application/json',
48+
'Content-Type': 'application/json',
49+
'X-CSRFToken': getCookie('csrftoken') || '',
11950
},
120-
);
121-
if (response.status >= 400) {
122-
setError('Something went wrong, please try again.');
123-
} else {
124-
setFeedbackSent(true);
125-
}
126-
},
127-
debugForm: false,
128-
});
51+
body: JSON.stringify({
52+
email: email || '[email protected]',
53+
message: message || '<no-message-provided>',
54+
rating: rating.current,
55+
page_url: pageUrl.toString(),
56+
}),
57+
});
58+
59+
setFeedbackSent(true);
60+
} catch (error) {
61+
console.warn(`Failed to submit call feedback`, error);
62+
setError('Something went wrong, please try again.');
63+
} finally {
64+
setIsSubmitting(false);
65+
}
66+
};
12967

13068
const handleSetRating = useCallback((value: number) => {
13169
setRating((currentRating) => ({ ...currentRating, current: value }));
@@ -196,7 +134,7 @@ export const Feedback = ({ callId, inMeeting = true }: Props) => {
196134
{inMeeting && !errorMessage && 'How is your calling experience?'}
197135
{!inMeeting && !errorMessage && 'How was your calling experience?'}
198136
</p>
199-
<Form className="rd__feedback-form">
137+
<form className="rd__feedback-form" onSubmit={handleSubmit}>
200138
<div className="rd__feedback-rating-stars">
201139
{[...new Array(rating.maxAmount)].map((_, index) => {
202140
const grade = index + 1;
@@ -219,13 +157,21 @@ export const Feedback = ({ callId, inMeeting = true }: Props) => {
219157
);
220158
})}
221159
</div>
222-
<Input
223-
className="rd__feedback-input"
224-
name="email"
160+
<input
225161
type="email"
162+
value={email}
226163
placeholder="Email"
164+
id="feedback_input"
165+
className="rd__feedback-input"
166+
onChange={(e) => setEmail(e.target.value)}
167+
/>
168+
<textarea
169+
value={message}
170+
placeholder="Message"
171+
id="feedback_message"
172+
className="rd__feedback-textarea"
173+
onChange={(e) => setMessage(e.target.value)}
227174
/>
228-
<TextArea name="message" placeholder="Message" />
229175
<div className="rd__feedback-footer">
230176
<div className="rd__feedback-actions">
231177
{inMeeting ? (
@@ -247,7 +193,6 @@ export const Feedback = ({ callId, inMeeting = true }: Props) => {
247193
Contact an expert
248194
</button>
249195
)}
250-
251196
<button
252197
className="rd__button rd__button--primary"
253198
type="submit"
@@ -257,7 +202,7 @@ export const Feedback = ({ callId, inMeeting = true }: Props) => {
257202
</button>
258203
</div>
259204
</div>
260-
</Form>
205+
</form>
261206
</div>
262207
);
263208
};

sample-apps/react/react-dogfood/package.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
"raw-body": "^3.0.0",
3535
"react": "19.0.0",
3636
"react-dom": "19.0.0",
37-
"react-form": "^4.0.1",
3837
"stream-chat": "^9.6.1",
3938
"stream-chat-react": "^13.1.0",
4039
"swr": "^2.3.3",
@@ -45,7 +44,6 @@
4544
"@types/mapbox-gl": "^2.7.19",
4645
"@types/react": "^19.1.3",
4746
"@types/react-dom": "^19.1.3",
48-
"@types/react-form": "^4.0.6",
4947
"@types/yargs": "^17.0.33",
5048
"rimraf": "^6.0.1",
5149
"sass": "^1.89.2",

yarn.lock

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8792,7 +8792,6 @@ __metadata:
87928792
"@types/mapbox-gl": "npm:^2.7.19"
87938793
"@types/react": "npm:^19.1.3"
87948794
"@types/react-dom": "npm:^19.1.3"
8795-
"@types/react-form": "npm:^4.0.6"
87968795
"@types/yargs": "npm:^17.0.33"
87978796
axios: "npm:^1.8.1"
87988797
clsx: "npm:^2.0.0"
@@ -8810,7 +8809,6 @@ __metadata:
88108809
raw-body: "npm:^3.0.0"
88118810
react: "npm:19.0.0"
88128811
react-dom: "npm:19.0.0"
8813-
react-form: "npm:^4.0.1"
88148812
rimraf: "npm:^6.0.1"
88158813
sass: "npm:^1.89.2"
88168814
source-map-loader: "npm:^5.0.0"
@@ -9547,15 +9545,6 @@ __metadata:
95479545
languageName: node
95489546
linkType: hard
95499547

9550-
"@types/react-form@npm:^4.0.6":
9551-
version: 4.0.6
9552-
resolution: "@types/react-form@npm:4.0.6"
9553-
dependencies:
9554-
"@types/react": "npm:*"
9555-
checksum: 10/1f4a4fc7ac66d968593bb7bfb36a76a02d178855269b984647a5ed9dbcde80f98c3627ea142e1ece351c4ee9d192f1c9d281a7f6253fcdb20249c6f022c00264
9556-
languageName: node
9557-
linkType: hard
9558-
95599548
"@types/react-native-video@npm:^5.0.20":
95609549
version: 5.0.20
95619550
resolution: "@types/react-native-video@npm:5.0.20"
@@ -22869,16 +22858,6 @@ __metadata:
2286922858
languageName: node
2287022859
linkType: hard
2287122860

22872-
"react-form@npm:^4.0.1":
22873-
version: 4.0.1
22874-
resolution: "react-form@npm:4.0.1"
22875-
peerDependencies:
22876-
prop-types: ^15.5.4
22877-
react: ^16.8.3
22878-
checksum: 10/677b7ea812b557a116afe433f4d59c1c9c931bc866d35dd00d737df88f560557abd0ebb3295d51aa3a51266b774389f46e8c0909a46589963b914c84edcfe94b
22879-
languageName: node
22880-
linkType: hard
22881-
2288222861
"react-freeze@npm:^1.0.0":
2288322862
version: 1.0.3
2288422863
resolution: "react-freeze@npm:1.0.3"

0 commit comments

Comments
 (0)