@@ -13,6 +13,7 @@ import Tooltip from '@mui/material/Tooltip';
1313import  Stack  from  '@mui/material/Stack' ; 
1414import  Snackbar  from  '@mui/material/Snackbar' ; 
1515import  IconButton  from  '@mui/material/IconButton' ; 
16+ import  CircularProgress  from  '@mui/material/CircularProgress' ; 
1617// Icons 
1718import  ThumbUpAltRoundedIcon  from  '@mui/icons-material/ThumbUpAltRounded' ; 
1819import  ThumbDownAltRoundedIcon  from  '@mui/icons-material/ThumbDownAltRounded' ; 
@@ -30,7 +31,8 @@ import PageContext from 'docs/src/modules/components/PageContext';
3031import  SvgMuiLogotype  from  'docs/src/icons/SvgMuiLogotype' ; 
3132import  EditPage  from  'docs/src/modules/components/EditPage' ; 
3233import  {  useUserLanguage ,  useTranslate  }  from  '@mui/docs/i18n' ; 
33- import  {  getCookie ,  pageToTitleI18n  }  from  'docs/src/modules/utils/helpers' ; 
34+ import  {  pageToTitleI18n  }  from  'docs/src/modules/utils/helpers' ; 
35+ import  useLocalStorageState  from  '@mui/utils/useLocalStorageState' ; 
3436
3537const  FooterLink  =  styled ( Link ) ( ( {  theme } )  =>  { 
3638  return  { 
@@ -80,25 +82,7 @@ function orderedPages(pages, current = []) {
8082    } ) ; 
8183} 
8284
83- async  function  postFeedback ( data )  { 
84-   const  env  =  process . env . DEPLOY_ENV  ===  'production'  ? 'prod'  : 'dev' ; 
85-   try  { 
86-     const  response  =  await  fetch ( `${ process . env . FEEDBACK_URL }  /${ env }  /feedback` ,  { 
87-       method : 'POST' , 
88-       referrerPolicy : 'origin' , 
89-       headers : {  'Content-Type' : 'application/json'  } , 
90-       body : JSON . stringify ( data ) , 
91-     } ) ; 
92-     return  response . json ( ) ; 
93-   }  catch  ( error )  { 
94-     console . error ( error ) ; 
95-     return  null ; 
96-   } 
97- } 
98- 
99- async  function  postFeedbackOnSlack ( data )  { 
100-   const  {  rating,  comment,  commentedSection,  productId }  =  data ; 
101- 
85+ async  function  submitFeedback ( page ,  rating ,  comment ,  language ,  commentedSection ,  productId )  { 
10286  const  sentData  =  { 
10387    callback_id : 'send_feedback' , 
10488    rating, 
@@ -172,64 +156,6 @@ async function postFeedbackOnSlack(data) {
172156  */ 
173157} 
174158
175- async  function  getUserFeedback ( id )  { 
176-   const  env  =  location . hostname  ===  'mui.com'  ? 'prod'  : 'dev' ; 
177-   const  URL  =  `${ process . env . FEEDBACK_URL }  /${ env }  /feedback/${ id }  ` ; 
178- 
179-   try  { 
180-     const  response  =  await  fetch ( URL ,  { 
181-       method : 'GET' , 
182-       cache : 'no-store' , 
183-       referrerPolicy : 'origin' , 
184-     } ) ; 
185-     return  response . json ( ) ; 
186-   }  catch  ( error )  { 
187-     console . error ( error ) ; 
188-     return  null ; 
189-   } 
190- } 
191- 
192- async  function  submitFeedback ( page ,  rating ,  comment ,  language ,  commentedSection ,  productId )  { 
193-   const  resultSlack  =  await  postFeedbackOnSlack ( {  rating,  comment,  commentedSection,  productId } ) ; 
194- 
195-   if  ( rating  !==  undefined )  { 
196-     const  resultVote  =  await  postFeedback ( { 
197-       id : getCookie ( 'feedbackId' ) , 
198-       page, 
199-       rating, 
200-       comment, 
201-       version : process . env . LIB_VERSION , 
202-       language, 
203-     } ) ; 
204-     if  ( resultVote )  { 
205-       document . cookie  =  `feedbackId=${ resultVote . id }  ;path=/;max-age=31536000` ; 
206-       setTimeout ( async  ( )  =>  { 
207-         const  userFeedback  =  await  getUserFeedback ( resultVote . id ) ; 
208-         if  ( userFeedback )  { 
209-           document . cookie  =  `feedback=${ JSON . stringify ( userFeedback ) }  ;path=/;max-age=31536000` ; 
210-         } 
211-       } ) ; 
212-     } 
213-     return  resultSlack  &&  resultVote ; 
214-   } 
215- 
216-   return  resultSlack ; 
217- } 
218- 
219- function  getCurrentRating ( pathname )  { 
220-   let  userFeedback ; 
221-   if  ( typeof  window  !==  'undefined' )  { 
222-     try  { 
223-       userFeedback  =  getCookie ( 'feedback' ) ; 
224-       userFeedback  =  userFeedback  &&  JSON . parse ( userFeedback ) ; 
225-     }  catch  { 
226-       // For unknown reason the `userFeedback` can be uncomplet, leading the JSON.parse to crash the entire docs 
227-       return  undefined ; 
228-     } 
229-   } 
230-   return  userFeedback  &&  userFeedback [ pathname ]  &&  userFeedback [ pathname ] . rating ; 
231- } 
232- 
233159/** 
234160 * @returns  { { prevPage: OrderedMuiPage | null; nextPage: OrderedMuiPage | null }  } 
235161 */ 
@@ -263,14 +189,17 @@ export default function AppLayoutDocsFooter(props) {
263189  const  t  =  useTranslate ( ) ; 
264190  const  userLanguage  =  useUserLanguage ( ) ; 
265191  const  {  activePage,  productId }  =  React . useContext ( PageContext ) ; 
266-   const  [ rating ,  setRating ]  =  React . useState ( ) ; 
192+   const  [ storedRating ,  setRating ]  =  useLocalStorageState ( `feedback- ${ activePage ?. pathname } ` ) ; 
267193  const  [ comment ,  setComment ]  =  React . useState ( '' ) ; 
194+   const  [ loading ,  setLoading ]  =  React . useState ( false ) ; 
268195  const  [ snackbarOpen ,  setSnackbarOpen ]  =  React . useState ( false ) ; 
269196  const  [ snackbarMessage ,  setSnackbarMessage ]  =  React . useState ( false ) ; 
270197  const  inputRef  =  React . useRef ( ) ; 
271198  const  [ commentOpen ,  setCommentOpen ]  =  React . useState ( false ) ; 
272199  const  [ commentedSection ,  setCommentedSection ]  =  React . useState ( EMPTY_SECTION ) ; 
273200
201+   const  rating  =  storedRating  ? Number ( storedRating )  : null ; 
202+ 
274203  const  {  nextPage,  prevPage }  =  usePageNeighbours ( ) ; 
275204
276205  const  sectionOptions  =  React . useMemo ( 
@@ -285,36 +214,32 @@ export default function AppLayoutDocsFooter(props) {
285214    [ tableOfContents ] , 
286215  ) ; 
287216
288-   const  setCurrentRatingFromCookie  =  React . useCallback ( ( )  =>  { 
289-     if  ( activePage  !==  null )  { 
290-       setRating ( getCurrentRating ( activePage . pathname ) ) ; 
291-     } 
292-   } ,  [ activePage ] ) ; 
217+   async  function  processFeedback ( )  { 
218+     try  { 
219+       setLoading ( true ) ; 
293220
294-   React . useEffect ( ( )   =>  { 
295-     setCurrentRatingFromCookie ( ) ; 
296-   } ,   [ setCurrentRatingFromCookie ] ) ; 
221+        if   ( activePage   ===   null )  { 
222+          setSnackbarMessage ( t ( 'feedbackFailed' ) ) ; 
223+        } 
297224
298-   async  function  processFeedback ( )  { 
299-     if  ( activePage  ===  null )  { 
300-       setSnackbarMessage ( t ( 'feedbackFailed' ) ) ; 
301-     } 
225+       const  result  =  await  submitFeedback ( 
226+         activePage . pathname , 
227+         rating , 
228+         comment , 
229+         userLanguage , 
230+         commentedSection , 
231+         productId , 
232+       ) ; 
302233
303-     const  result  =  await  submitFeedback ( 
304-       activePage . pathname , 
305-       rating , 
306-       comment , 
307-       userLanguage , 
308-       commentedSection , 
309-       productId , 
310-     ) ; 
311-     if  ( result )  { 
312-       setSnackbarMessage ( t ( 'feedbackSubmitted' ) ) ; 
313-     }  else  { 
314-       setCurrentRatingFromCookie ( ) ; 
315-       setSnackbarMessage ( t ( 'feedbackFailed' ) ) ; 
234+       if  ( result )  { 
235+         setSnackbarMessage ( t ( 'feedbackSubmitted' ) ) ; 
236+       }  else  { 
237+         setSnackbarMessage ( t ( 'feedbackFailed' ) ) ; 
238+       } 
239+       setSnackbarOpen ( true ) ; 
240+     }  finally  { 
241+       setLoading ( false ) ; 
316242    } 
317-     setSnackbarOpen ( true ) ; 
318243  } 
319244
320245  const  handleClickThumb  =  ( vote )  =>  async  ( )  =>  { 
@@ -359,7 +284,6 @@ export default function AppLayoutDocsFooter(props) {
359284
360285  const  handleCancelComment  =  ( )  =>  { 
361286    setCommentOpen ( false ) ; 
362-     setCurrentRatingFromCookie ( ) ; 
363287    setCommentedSection ( EMPTY_SECTION ) ; 
364288  } ; 
365289
@@ -411,17 +335,31 @@ export default function AppLayoutDocsFooter(props) {
411335              { t ( 'feedbackMessage' ) } 
412336            </ Typography > 
413337            < Tooltip  title = { t ( 'feedbackYes' ) } > 
414-               < IconButton  onClick = { handleClickThumb ( 1 ) }  aria-pressed = { rating  ===  1 } > 
415-                 < ThumbUpAltRoundedIcon 
416-                   sx = { {  fontSize : 15 ,  color : rating  ===  1  ? 'primary'  : 'text.secondary'  } } 
417-                 /> 
338+               < IconButton 
339+                 onClick = { handleClickThumb ( 1 ) } 
340+                 disabled = { loading } 
341+                 aria-pressed = { rating  ===  1 } 
342+                 sx = { {  fontSize : 15 ,  color : rating  ===  1  ? 'primary.main'  : 'text.secondary'  } } 
343+               > 
344+                 { rating  ===  1  &&  loading  ? ( 
345+                   < CircularProgress  size = { 15 }  /> 
346+                 )  : ( 
347+                   < ThumbUpAltRoundedIcon  fontSize = "inherit"  /> 
348+                 ) } 
418349              </ IconButton > 
419350            </ Tooltip > 
420351            < Tooltip  title = { t ( 'feedbackNo' ) } > 
421-               < IconButton  onClick = { handleClickThumb ( 0 ) }  aria-pressed = { rating  ===  0 } > 
422-                 < ThumbDownAltRoundedIcon 
423-                   sx = { {  fontSize : 15 ,  color : rating  ===  0  ? 'error'  : 'text.secondary'  } } 
424-                 /> 
352+               < IconButton 
353+                 onClick = { handleClickThumb ( 0 ) } 
354+                 disabled = { loading } 
355+                 aria-pressed = { rating  ===  0 } 
356+                 sx = { {  fontSize : 15 ,  color : rating  ===  0  ? 'error.main'  : 'text.secondary'  } } 
357+               > 
358+                 { rating  ===  0  &&  loading  ? ( 
359+                   < CircularProgress  size = { 15 }  /> 
360+                 )  : ( 
361+                   < ThumbDownAltRoundedIcon  fontSize = "inherit"  /> 
362+                 ) } 
425363              </ IconButton > 
426364            </ Tooltip > 
427365          </ Stack > 
0 commit comments