diff --git a/sparkle/src/components/FeedbackSelector.tsx b/sparkle/src/components/FeedbackSelector.tsx index 6713200e56c8..fdf55b2b19fb 100644 --- a/sparkle/src/components/FeedbackSelector.tsx +++ b/sparkle/src/components/FeedbackSelector.tsx @@ -1,6 +1,7 @@ -import React, { useEffect, useRef } from "react"; +import React, { useCallback, useEffect, useRef } from "react"; import { Button } from "@sparkle/components/Button"; +import { Checkbox } from "@sparkle/components/Checkbox"; import { Page } from "@sparkle/components/Page"; import { PopoverContent, @@ -12,23 +13,19 @@ import { TextArea } from "@sparkle/components/TextArea"; import { Tooltip } from "@sparkle/components/Tooltip"; import { HandThumbDownIcon, HandThumbUpIcon } from "@sparkle/icons/solid"; -export type FeedbackAssistantBuilder = { - name: string; - pictureUrl: string; -}; - export type ThumbReaction = "up" | "down"; export type FeedbackType = { thumb: ThumbReaction; feedbackContent: string | null; + isConversationShared: boolean; }; export interface FeedbackSelectorProps { feedback: FeedbackType | null; onSubmitThumb: ( p: FeedbackType & { - isToRemove: boolean; + shouldRemoveExistingFeedback: boolean; } ) => Promise; isSubmittingThumb: boolean; @@ -49,26 +46,92 @@ export function FeedbackSelector({ const [popOverInfo, setPopoverInfo] = React.useState( null ); + const [isConversationShared, setIsConversationShared] = React.useState( + feedback?.isConversationShared ?? false + ); + // This is required to adjust the content of the popover even when feedback is null. + const [lastSelectedThumb, setLastSelectedThumb] = + React.useState(feedback?.thumb ?? null); useEffect(() => { if (isPopoverOpen) { if (getPopoverInfo) { setPopoverInfo(getPopoverInfo()); } - setLocalFeedbackContent(feedback?.feedbackContent ?? null); + if (feedback?.thumb === lastSelectedThumb) { + setLocalFeedbackContent(feedback?.feedbackContent ?? null); + } } - }, [isPopoverOpen, feedback?.feedbackContent]); + }, [ + isPopoverOpen, + feedback?.feedbackContent, + getPopoverInfo, + lastSelectedThumb, + ]); + + const selectThumb = useCallback( + async (thumb: ThumbReaction) => { + // Whether to remove the thumb reaction + const shouldRemoveExistingFeedback = feedback?.thumb === thumb; + setIsPopoverOpen(!shouldRemoveExistingFeedback); + setLastSelectedThumb(shouldRemoveExistingFeedback ? null : thumb); - const selectThumb = async (thumb: ThumbReaction) => { - const isToRemove = feedback?.thumb === thumb; - setIsPopoverOpen(!isToRemove); + // Checkbox ticked by default only for new thumbs down + setIsConversationShared(thumb === "down"); - await onSubmitThumb({ - feedbackContent: localFeedbackContent, - thumb, - isToRemove, - }); - }; + // We enforce written feedback for thumbs down. + // -> Not saving the reaction until then. + if (thumb === "down" && !shouldRemoveExistingFeedback) { + return; + } + + await onSubmitThumb({ + feedbackContent: localFeedbackContent, + thumb, + shouldRemoveExistingFeedback, + // The sharing option was never displayed so far -> Opt out of sharing. + isConversationShared: false, + }); + }, + [feedback?.thumb, localFeedbackContent, onSubmitThumb, isConversationShared] + ); + + const handleThumbUp = useCallback(async () => { + await selectThumb("up"); + }, [selectThumb]); + + const handleThumbDown = useCallback(async () => { + await selectThumb("down"); + }, [selectThumb]); + + const handleTextAreaChange = useCallback( + (e: React.ChangeEvent) => { + setLocalFeedbackContent(e.target.value); + }, + [] + ); + + const closePopover = useCallback(() => { + setIsPopoverOpen(false); + }, []); + + const handleSubmit = useCallback(async () => { + setIsPopoverOpen(false); + if (lastSelectedThumb) { + await onSubmitThumb({ + thumb: lastSelectedThumb, + shouldRemoveExistingFeedback: false, + feedbackContent: localFeedbackContent, + isConversationShared, + }); + setLocalFeedbackContent(null); + } + }, [ + onSubmitThumb, + localFeedbackContent, + isConversationShared, + lastSelectedThumb, + ]); return (
@@ -82,7 +145,7 @@ export function FeedbackSelector({ variant={feedback?.thumb === "up" ? "primary" : "ghost"} size="xs" disabled={isSubmittingThumb} - onClick={() => selectThumb("up")} + onClick={handleThumbUp} icon={HandThumbUpIcon} className={ feedback?.thumb === "up" @@ -99,7 +162,7 @@ export function FeedbackSelector({ variant={feedback?.thumb === "down" ? "primary" : "ghost"} size="xs" disabled={isSubmittingThumb} - onClick={() => selectThumb("down")} + onClick={handleThumbDown} icon={HandThumbDownIcon} className={ feedback?.thumb === "down" @@ -111,7 +174,11 @@ export function FeedbackSelector({ />
- + {isSubmittingThumb ? (
@@ -119,39 +186,44 @@ export function FeedbackSelector({ ) : (
- {feedback?.thumb === "up" + {lastSelectedThumb === "up" ? "🎉 Glad you liked it! Tell us more?" : "🫠 Help make the answers better!"}