1- import { HTMLInputTypeAttribute , useCallback , useMemo , useState } from 'react' ;
1+ import { FormEvent , useCallback , useState } from 'react' ;
22import clsx from 'clsx' ;
3- import { useField , useForm } from 'react-form' ;
43import { Icon , useCall , useMenuContext } from '@stream-io/video-react-sdk' ;
54import { 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-
7412const basePath = process . env . NEXT_PUBLIC_BASE_PATH || '' ;
7513
7614export 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} ;
0 commit comments