11import { hooks } from 'botframework-webchat-api' ;
22import { getOrgSchemaMessage , OrgSchemaAction , parseAction , WebChatActivity } from 'botframework-webchat-core' ;
33import classNames from 'classnames' ;
4- import React , { memo , useCallback , useMemo , useState } from 'react' ;
4+ import React , { memo , useCallback , useEffect , useMemo , useState } from 'react' ;
55
66import useStyleSet from '../hooks/useStyleSet' ;
77import dereferenceBlankNodes from '../Utils/JSONLinkedData/dereferenceBlankNodes' ;
88import Feedback from './private/Feedback' ;
99import FeedbackForm from './private/FeedbackForm' ;
1010import getDisclaimer from './private/getDisclaimer' ;
1111import hasFeedbackLoop from './private/hasFeedbackLoop' ;
12- import { useRefFrom } from 'use-ref-from' ;
1312
1413const { useStyleOptions } = hooks ;
1514
@@ -43,18 +42,7 @@ const defaultFeedbackEntities = {
4342 ]
4443} ;
4544
46- function ActivityFeedback ( { activity } : ActivityFeedbackProps ) {
47- const [ { feedbackActionsPlacement } ] = useStyleOptions ( ) ;
48- const [ { feedbackForm } ] = useStyleSet ( ) ;
49-
50- const [ selectedAction , setSelectedAction ] = useState < OrgSchemaAction | undefined > ( ) ;
51- const selectedActionRef = useRefFrom ( selectedAction ) ;
52- const [ feedbackSubmitted , setFeedbackSubmitted ] = useState < boolean > ( false ) ;
53- const feedbackSubmittedRef = useRefFrom ( feedbackSubmitted ) ;
54- const submittedAction = feedbackSubmitted ? selectedAction : undefined ;
55-
56- const isFeedbackLoopSupported = hasFeedbackLoop ( activity ) ;
57-
45+ const useFeedbackActions = ( activity : WebChatActivity , isFeedbackLoopSupported : boolean ) => {
5846 const { graph, messageThing } = useMemo ( ( ) => {
5947 if ( isFeedbackLoopSupported ) {
6048 return parseActivity ( [ defaultFeedbackEntities ] ) ;
@@ -63,87 +51,113 @@ function ActivityFeedback({ activity }: ActivityFeedbackProps) {
6351 return parseActivity ( activity . entities ) ;
6452 } , [ activity . entities , isFeedbackLoopSupported ] ) ;
6553
66- const feedbackActions = useMemo < ReadonlySet < OrgSchemaAction > > ( ( ) => {
54+ const feedbackActions = useMemo < OrgSchemaAction [ ] > ( ( ) => {
6755 try {
68- const reactActions = ( messageThing ?. potentialAction || [ ] )
69- . filter ( ( { '@type' : type } ) => type === 'LikeAction' || type === 'DislikeAction' )
70- . map ( action => ( submittedAction && action [ '@type' ] === submittedAction [ '@type' ] ? submittedAction : action ) ) ;
56+ const reactActions = ( messageThing ?. potentialAction || [ ] ) . filter (
57+ ( { '@type' : type } ) => type === 'LikeAction' || type === 'DislikeAction'
58+ ) ;
7159
7260 if ( reactActions . length ) {
73- return Object . freeze ( new Set ( reactActions ) ) ;
61+ return reactActions ;
7462 }
7563
7664 const voteActions = graph . filter ( ( { type } ) => type === 'https://schema.org/VoteAction' ) . map ( parseAction ) ;
7765
7866 if ( voteActions . length ) {
79- return Object . freeze ( new Set ( voteActions ) ) ;
67+ return voteActions ;
8068 }
8169 } catch {
8270 // Intentionally left blank.
8371 }
84- return Object . freeze ( new Set ( [ ] as OrgSchemaAction [ ] ) ) ;
85- } , [ graph , messageThing , submittedAction ] ) ;
72+ return [ ] as OrgSchemaAction [ ] ;
73+ } , [ graph , messageThing ] ) ;
8674
87- const handleFeedbackActionClick = useCallback (
88- ( action : OrgSchemaAction ) => setSelectedAction ( action === selectedAction ? undefined : action ) ,
89- [ selectedAction , setSelectedAction ]
90- ) ;
75+ const [ currentFeedbackActions , setCurrentFeedbackActions ] = useState ( feedbackActions ) ;
9176
92- const handleFeedbackFormReset = useCallback ( ( ) => {
93- if ( feedbackSubmittedRef . current ) {
94- return ;
95- }
77+ // Handle feedback actions update via incoming activity
78+ useEffect ( ( ) => {
79+ setCurrentFeedbackActions ( feedbackActions ) ;
80+ } , [ feedbackActions ] ) ;
9681
97- setSelectedAction ( undefined ) ;
98- setFeedbackSubmitted ( false ) ;
99- } , [ feedbackSubmittedRef ] ) ;
82+ return { currentFeedbackActions, setCurrentFeedbackActions } ;
83+ } ;
10084
101- const handleFeedbackFormSubmit = useCallback ( ( ) => {
102- if ( feedbackSubmittedRef . current || ! selectedActionRef . current ) {
103- return ;
104- }
85+ function ActivityFeedback ( { activity } : ActivityFeedbackProps ) {
86+ const [ { feedbackActionsPlacement } ] = useStyleOptions ( ) ;
87+ const [ { feedbackForm } ] = useStyleSet ( ) ;
88+
89+ const isFeedbackLoopSupported = hasFeedbackLoop ( activity ) ;
90+
91+ const { currentFeedbackActions : feedbackActions , setCurrentFeedbackActions } = useFeedbackActions (
92+ activity ,
93+ isFeedbackLoopSupported
94+ ) ;
95+
96+ const selectedAction = feedbackActions . find (
97+ action => action . actionStatus === 'CompletedActionStatus' || action . actionStatus === 'ActiveActionStatus'
98+ ) ;
10599
106- setSelectedAction ( {
107- ...selectedActionRef . current ,
108- actionStatus : 'CompletedActionStatus' as const
109- } ) ;
110- setFeedbackSubmitted ( true ) ;
111- } , [ feedbackSubmittedRef , selectedActionRef ] ) ;
100+ const handleFeedbackActionClick = useCallback (
101+ ( action : OrgSchemaAction ) => {
102+ const newActions : OrgSchemaAction [ ] = feedbackActions . map ( feedbackAction => {
103+ // reset all actions to potential action status (unclicked the active action)
104+ if ( action . actionStatus === 'ActiveActionStatus' ) {
105+ return {
106+ ...feedbackAction ,
107+ actionStatus : 'PotentialActionStatus'
108+ } ;
109+ }
110+
111+ return {
112+ ...feedbackAction ,
113+ actionStatus : feedbackAction === action ? 'ActiveActionStatus' : 'PotentialActionStatus'
114+ } ;
115+ } ) ;
116+ setCurrentFeedbackActions ( newActions ) ;
117+ } ,
118+ [ feedbackActions , setCurrentFeedbackActions ]
119+ ) ;
120+
121+ const handleFeedbackFormClick = useCallback (
122+ ( isSubmitted = false ) => {
123+ const newActions : OrgSchemaAction [ ] = feedbackActions . map ( action => ( {
124+ ...action ,
125+ actionStatus :
126+ action . actionStatus === 'ActiveActionStatus' && isSubmitted
127+ ? 'CompletedActionStatus'
128+ : 'PotentialActionStatus'
129+ } ) ) ;
130+ setCurrentFeedbackActions ( newActions ) ;
131+ } ,
132+ [ feedbackActions , setCurrentFeedbackActions ]
133+ ) ;
112134
113135 const FeedbackComponent = useMemo (
114136 ( ) => (
115137 < Feedback
116138 actions = { feedbackActions }
117139 className = { classNames ( {
118140 'webchat__thumb-button--large' : feedbackActionsPlacement === 'activity-actions' ,
119- 'webchat__thumb-button--submitted' : feedbackSubmitted
141+ 'webchat__thumb-button--submitted' : selectedAction ?. actionStatus === 'CompletedActionStatus'
120142 } ) }
121143 isFeedbackFormSupported = { isFeedbackLoopSupported }
122144 onActionClick = { handleFeedbackActionClick }
123145 selectedAction = { selectedAction }
124146 />
125147 ) ,
126- [
127- feedbackActions ,
128- feedbackActionsPlacement ,
129- feedbackSubmitted ,
130- handleFeedbackActionClick ,
131- isFeedbackLoopSupported ,
132- selectedAction
133- ]
148+ [ feedbackActions , feedbackActionsPlacement , handleFeedbackActionClick , isFeedbackLoopSupported , selectedAction ]
134149 ) ;
135150
136151 const FeedbackFormComponent = useMemo (
137152 ( ) => (
138153 < FeedbackForm
139154 disclaimer = { getDisclaimer ( activity ) }
140155 feedbackType = { selectedAction ?. [ '@type' ] }
141- onReset = { handleFeedbackFormReset }
142- onSubmit = { handleFeedbackFormSubmit }
156+ onFeedbackFormButtonClick = { handleFeedbackFormClick }
143157 replyToId = { activity . id }
144158 />
145159 ) ,
146- [ activity , handleFeedbackFormReset , handleFeedbackFormSubmit , selectedAction ]
160+ [ activity , handleFeedbackFormClick , selectedAction ]
147161 ) ;
148162
149163 if ( feedbackActionsPlacement === 'activity-actions' && isFeedbackLoopSupported ) {
@@ -153,7 +167,7 @@ function ActivityFeedback({ activity }: ActivityFeedbackProps) {
153167 { FeedbackComponent }
154168 </ div >
155169 { /* Hide feedback form if feedback has already been submitted */ }
156- { ! feedbackSubmitted && selectedAction && selectedAction [ '@type' ] && FeedbackFormComponent }
170+ { selectedAction ?. [ '@type' ] && selectedAction ?. actionStatus === 'ActiveActionStatus' && FeedbackFormComponent }
157171 </ div >
158172 ) ;
159173 }
0 commit comments