// ============================================================================ // Chatbot Main - Messages - Feedback Complete Card // ============================================================================ import type { MouseEvent as ReactMouseEvent, FunctionComponent } from 'react'; import { useState, useRef, useEffect } from 'react'; import { Card, CardBody, CardHeader, CardProps, CardTitle, OUIAProps, useOUIAProps } from '@patternfly/react-core'; import CloseButton from './CloseButton'; export interface UserFeedbackCompleteProps extends Omit, OUIAProps { /** Additional classes for the pagination navigation container. */ className?: string; /** Substitute for the English phrase "Thank you". */ title?: string; /** Substitute for the English phrase "You have successfully sent your feedback! Thank you for responding." */ body?: string | React.ReactNode; /** Callback function for when close button is clicked */ onClose?: () => void; /** Aria label for close button */ closeButtonAriaLabel?: string; /** Function to be executed on timeout. Relevant when the timeout prop is set. */ onTimeout?: () => void; /** If set to true, the timeout is 8000 milliseconds. If a number is provided, card will * be dismissed after that amount of time in milliseconds. */ timeout?: number | boolean; /** If the user hovers over the card and `timeout` expires, this is how long to wait * before finally dismissing the alert. */ timeoutAnimation?: number; /** Callback for when mouse hovers over card */ onMouseEnter?: (e: React.MouseEvent) => void; /** Callback for when mouse stops hovering over card */ onMouseLeave?: (e: React.MouseEvent) => void; /** Value to overwrite the randomly generated data-ouia-component-id.*/ ouiaId?: number | string; /** Set the value of data-ouia-safe. Only set to true when the component is in a static state, i.e. no animations are occurring. At all other times, this value must be false. */ ouiaSafe?: boolean; /** Flag to indicate if the card is in a live region. */ isLiveRegion?: boolean; /** Uniquely identifies the completion card. */ id?: string; /** Whether to focus card on load */ focusOnLoad?: boolean; /** Timestamp passed in by Message for more context in aria announcements */ timestamp?: string; } export const UserFeedbackComplete: FunctionComponent = ({ className, title = 'Feedback submitted', body = "We've received your response. Thank you for sharing your feedback!", timestamp, timeout = false, timeoutAnimation = 3000, onTimeout, onClose, closeButtonAriaLabel = `Close feedback for message received at ${timestamp}`, onMouseEnter, onMouseLeave, ouiaId, ouiaSafe, isLiveRegion, id, focusOnLoad = true, isCompact, ...props }: UserFeedbackCompleteProps) => { const [timedOut, setTimedOut] = useState(false); const [timedOutAnimation, setTimedOutAnimation] = useState(true); const [isMouseOver, setIsMouseOver] = useState(); const [containsFocus, setContainsFocus] = useState(); const dismissed = timedOut && timedOutAnimation && !isMouseOver && !containsFocus; const divRef = useRef(null); const ouiaProps = useOUIAProps('User Feedback Complete', ouiaId, ouiaSafe); useEffect(() => { if (focusOnLoad) { divRef.current?.focus(); } }, []); useEffect(() => { const calculatedTimeout = timeout === true ? 8000 : Number(timeout); if (calculatedTimeout > 0) { const timer = setTimeout(() => setTimedOut(true), calculatedTimeout); return () => clearTimeout(timer); } }, [timeout]); useEffect(() => { const onDocumentFocus = () => { if (divRef.current) { if (divRef.current.contains(document.activeElement)) { setContainsFocus(true); setTimedOutAnimation(false); } else if (containsFocus) { setContainsFocus(false); } } }; document.addEventListener('focus', onDocumentFocus, true); return () => document.removeEventListener('focus', onDocumentFocus, true); }, [containsFocus]); useEffect(() => { if (containsFocus === false || isMouseOver === false) { const timer = setTimeout(() => setTimedOutAnimation(true), timeoutAnimation); return () => clearTimeout(timer); } }, [containsFocus, isMouseOver, timeoutAnimation]); useEffect(() => { dismissed && onTimeout && onTimeout(); }, [dismissed, onTimeout]); if (dismissed) { return null; } const myOnMouseEnter = (ev: ReactMouseEvent) => { setIsMouseOver(true); setTimedOutAnimation(false); onMouseEnter && onMouseEnter(ev); }; const myOnMouseLeave = (ev: ReactMouseEvent) => { setIsMouseOver(false); onMouseLeave && onMouseLeave(ev); }; return ( /* card does not have ref forwarding; hence wrapper div */
} : undefined /* eslint-enable indent */ } >
{title} {body}
); }; export default UserFeedbackComplete;