@@ -2,32 +2,59 @@ import {
22 Avatar ,
33 Button ,
44 ButtonDomRef ,
5+ Form ,
6+ FormGroup ,
7+ FormItem ,
58 Icon ,
9+ Label ,
610 List ,
711 ListItemStandard ,
812 Popover ,
913 PopoverDomRef ,
14+ RatingIndicator ,
1015 ShellBar ,
1116 ShellBarDomRef ,
17+ ShellBarItem ,
18+ ShellBarItemDomRef ,
19+ TextArea ,
20+ TextAreaDomRef ,
1221 Ui5CustomEvent ,
1322} from '@ui5/webcomponents-react' ;
1423import { useAuth } from '../../spaces/onboarding/auth/AuthContext.tsx' ;
15- import { RefObject , useEffect , useRef , useState } from 'react' ;
24+ import {
25+ Dispatch ,
26+ RefObject ,
27+ SetStateAction ,
28+ useEffect ,
29+ useRef ,
30+ useState ,
31+ } from 'react' ;
1632import { ShellBarProfileClickEventDetail } from '@ui5/webcomponents-fiori/dist/ShellBar.js' ;
1733import PopoverPlacement from '@ui5/webcomponents/dist/types/PopoverPlacement.js' ;
1834import { useTranslation } from 'react-i18next' ;
1935import { generateInitialsForEmail } from '../Helper/generateInitialsForEmail.ts' ;
2036import styles from './ShellBar.module.css' ;
2137import { ThemingParameters } from '@ui5/webcomponents-react-base' ;
38+ import { ShellBarItemClickEventDetail } from '@ui5/webcomponents-fiori/dist/ShellBarItem.js' ;
39+ import { t } from 'i18next' ;
40+
41+ type UI5RatingIndicatorElement = HTMLElement & { value : number } ;
2242
2343export function ShellBarComponent ( ) {
2444 const auth = useAuth ( ) ;
2545 const profilePopoverRef = useRef < PopoverDomRef > ( null ) ;
2646 const betaPopoverRef = useRef < PopoverDomRef > ( null ) ;
47+ const feedbackPopoverRef = useRef < PopoverDomRef > ( null ) ;
2748 const [ profilePopoverOpen , setProfilePopoverOpen ] = useState ( false ) ;
2849 const [ betaPopoverOpen , setBetaPopoverOpen ] = useState ( false ) ;
50+ const [ feedbackPopoverOpen , setFeedbackPopoverOpen ] = useState ( false ) ;
51+ const [ rating , setRating ] = useState ( 0 ) ;
52+ const [ feedbackMessage , setFeedbackMessage ] = useState ( '' ) ;
53+ const [ feedbackSent , setFeedbackSent ] = useState ( false ) ;
2954 const betaButtonRef = useRef < ButtonDomRef > ( null ) ;
3055
56+ const { user } = useAuth ( ) ;
57+
3158 const onProfileClick = (
3259 e : Ui5CustomEvent < ShellBarDomRef , ShellBarProfileClickEventDetail > ,
3360 ) => {
@@ -42,6 +69,45 @@ export function ShellBarComponent() {
4269 }
4370 } ;
4471
72+ const onFeedbackClick = (
73+ e : Ui5CustomEvent < ShellBarItemDomRef , ShellBarItemClickEventDetail > ,
74+ ) => {
75+ feedbackPopoverRef . current ! . opener = e . detail . targetRef ;
76+ setFeedbackPopoverOpen ( ! feedbackPopoverOpen ) ;
77+ } ;
78+
79+ const onFeedbackMessageChange = (
80+ event : Ui5CustomEvent <
81+ TextAreaDomRef ,
82+ { value : string ; previousValue : string }
83+ > ,
84+ ) => {
85+ const newValue = event . target . value ;
86+ setFeedbackMessage ( newValue ) ;
87+ } ;
88+
89+ async function onFeedbackSent ( ) {
90+ const payload = {
91+ message : feedbackMessage ,
92+ rating : rating . toString ( ) ,
93+ user : user ?. email ,
94+ environment : window . location . hostname ,
95+ } ;
96+ try {
97+ await fetch ( '/api/feedback' , {
98+ method : 'POST' ,
99+ headers : {
100+ 'Content-Type' : 'application/json' ,
101+ } ,
102+ body : JSON . stringify ( payload ) ,
103+ } ) ;
104+ } catch ( err ) {
105+ console . log ( err ) ;
106+ } finally {
107+ setFeedbackSent ( true ) ;
108+ }
109+ }
110+
45111 useEffect ( ( ) => {
46112 const shellbar = document . querySelector ( 'ui5-shellbar' ) ;
47113 const el = shellbar ?. shadowRoot ?. querySelector (
@@ -82,7 +148,13 @@ export function ShellBarComponent() {
82148 </ div >
83149 }
84150 onProfileClick = { onProfileClick }
85- />
151+ >
152+ < ShellBarItem
153+ icon = "feedback"
154+ text = { t ( 'ShellBar.feedbackNotification' ) }
155+ onClick = { onFeedbackClick }
156+ />
157+ </ ShellBar >
86158
87159 < ProfilePopover
88160 open = { profilePopoverOpen }
@@ -94,6 +166,17 @@ export function ShellBarComponent() {
94166 setOpen = { setBetaPopoverOpen }
95167 popoverRef = { betaPopoverRef }
96168 />
169+ < FeedbackPopover
170+ open = { feedbackPopoverOpen }
171+ setOpen = { setFeedbackPopoverOpen }
172+ popoverRef = { feedbackPopoverRef }
173+ setRating = { setRating }
174+ rating = { rating }
175+ feedbackMessage = { feedbackMessage }
176+ feedbackSent = { feedbackSent }
177+ onFeedbackSent = { onFeedbackSent }
178+ onFeedbackMessageChange = { onFeedbackMessageChange }
179+ />
97180 </ >
98181 ) ;
99182}
@@ -163,3 +246,106 @@ const BetaPopover = ({
163246 </ Popover >
164247 ) ;
165248} ;
249+
250+ const FeedbackPopover = ( {
251+ open,
252+ setOpen,
253+ popoverRef,
254+ setRating,
255+ rating,
256+ onFeedbackSent,
257+ feedbackMessage,
258+ onFeedbackMessageChange,
259+ feedbackSent,
260+ } : {
261+ open : boolean ;
262+ setOpen : ( arg0 : boolean ) => void ;
263+ popoverRef : RefObject < PopoverDomRef | null > ;
264+ setRating : Dispatch < SetStateAction < number > > ;
265+ rating : number ;
266+ onFeedbackSent : ( ) => void ;
267+ feedbackMessage : string ;
268+ onFeedbackMessageChange : (
269+ event : Ui5CustomEvent <
270+ TextAreaDomRef ,
271+ {
272+ value : string ;
273+ previousValue : string ;
274+ }
275+ > ,
276+ ) => void ;
277+ feedbackSent : boolean ;
278+ } ) => {
279+ const { t } = useTranslation ( ) ;
280+
281+ const onRatingChange = (
282+ event : Event & { target : UI5RatingIndicatorElement } ,
283+ ) => {
284+ setRating ( event . target . value ) ;
285+ } ;
286+
287+ return (
288+ < >
289+ < Popover
290+ ref = { popoverRef }
291+ placement = { PopoverPlacement . Bottom }
292+ open = { open }
293+ onClose = { ( ) => setOpen ( false ) }
294+ >
295+ < div
296+ style = { {
297+ padding : '1rem' ,
298+ width : '250px' ,
299+ } }
300+ >
301+ { ! feedbackSent ? (
302+ < Form headerText = { t ( 'ShellBar.feedbackHeader' ) } >
303+ < FormGroup >
304+ < FormItem
305+ labelContent = {
306+ < Label style = { { color : 'black' } } >
307+ { t ( 'ShellBar.feedbackRatingLabel' ) }
308+ </ Label >
309+ }
310+ >
311+ < RatingIndicator
312+ value = { rating }
313+ max = { 5 }
314+ onChange = { onRatingChange }
315+ />
316+ </ FormItem >
317+ < FormItem
318+ className = "formAlignLabelStart"
319+ labelContent = {
320+ < Label style = { { color : 'black' } } >
321+ { t ( 'ShellBar.feedbackMessageLabel' ) }
322+ </ Label >
323+ }
324+ >
325+ < TextArea
326+ value = { feedbackMessage }
327+ placeholder = { t ( 'ShellBar.feedbackPlaceholder' ) }
328+ rows = { 5 }
329+ onInput = { onFeedbackMessageChange }
330+ />
331+ </ FormItem >
332+ < FormItem >
333+ < Button design = "Emphasized" onClick = { ( ) => onFeedbackSent ( ) } >
334+ { t ( 'ShellBar.feedbackButton' ) }
335+ </ Button >
336+ </ FormItem >
337+ < FormItem >
338+ < Label style = { { color : 'gray' } } >
339+ { t ( 'ShellBar.feedbackNotification' ) }
340+ </ Label >
341+ </ FormItem >
342+ </ FormGroup >
343+ </ Form >
344+ ) : (
345+ < Label > { t ( 'ShellBar.feedbackThanks' ) } </ Label >
346+ ) }
347+ </ div >
348+ </ Popover >
349+ </ >
350+ ) ;
351+ } ;
0 commit comments