import { useState, useEffect, useRef, FunctionComponent } from 'react'; import { ChatbotDisplayMode } from '@patternfly/chatbot/dist/dynamic/Chatbot'; import ChatbotConversationHistoryNav, { Conversation } from '@patternfly/chatbot/dist/dynamic/ChatbotConversationHistoryNav'; import { Checkbox, EmptyStateStatus, Spinner } from '@patternfly/react-core'; import { OutlinedCommentsIcon, SearchIcon } from '@patternfly/react-icons'; const initialConversations: { [key: string]: Conversation[] } = { Today: [{ id: '1', text: 'Red Hat products and services' }], 'This month': [ { id: '2', text: 'Enterprise Linux installation and setup' }, { id: '3', text: 'Troubleshoot system crash' } ], March: [ { id: '4', text: 'Ansible security and updates' }, { id: '5', text: 'Red Hat certification' }, { id: '6', text: 'Lightspeed user documentation' } ], February: [ { id: '7', text: 'Crashing pod assistance' }, { id: '8', text: 'OpenShift AI pipelines' }, { id: '9', text: 'Updating subscription plan' }, { id: '10', text: 'Red Hat licensing options' } ], January: [ { id: '11', text: 'RHEL system performance' }, { id: '12', text: 'Manage user accounts' } ] }; const ERROR = { bodyText: ( <> To try again, check your connection and reload this page. If the issue persists,{' '} contact the support team. ), buttonText: 'Reload', buttonIcon: , hasButton: true, titleText: 'Could not load chat history', status: EmptyStateStatus.danger, onClick: () => alert('Clicked Reload') }; const NO_RESULTS = { bodyText: 'Adjust your search query and try again. Check your spelling or try a more general term.', titleText: 'No results found', icon: SearchIcon }; const EMPTY_STATE = { bodyText: 'Access timely assistance by starting a conversation with an AI model.', titleText: 'Start a new chat', icon: OutlinedCommentsIcon }; export const ChatbotHeaderTitleDemo: FunctionComponent = () => { const [isOpen, setIsOpen] = useState(true); const [isButtonOrderReversed, setIsButtonOrderReversed] = useState(false); const [isNewChatButtonDisabled, setIsNewChatButtonDisabled] = useState(false); const [isCompact, setIsCompact] = useState(false); const [conversations, setConversations] = useState( initialConversations ); const [isLoading, setIsLoading] = useState(false); const [hasError, setHasError] = useState(false); const [isEmpty, setIsEmpty] = useState(false); const [hasNoResults, setHasNoResults] = useState(false); const [announcement, setAnnouncement] = useState(''); const [debouncedAnnouncement, setDebouncedAnnouncement] = useState(''); const announcementTimeoutRef = useRef(); const displayMode = ChatbotDisplayMode.embedded; // Debounce announcement updates to prevent screen reader overload useEffect(() => { if (announcementTimeoutRef.current) { clearTimeout(announcementTimeoutRef.current); } announcementTimeoutRef.current = setTimeout(() => { setDebouncedAnnouncement(announcement); }, 500); return () => { if (announcementTimeoutRef.current) { clearTimeout(announcementTimeoutRef.current); } }; }, [announcement]); const findMatchingItems = (targetValue: string) => { const filteredConversations = Object.entries(initialConversations).reduce((acc, [key, items]) => { const filteredItems = items.filter((item) => item.text.toLowerCase().includes(targetValue.toLowerCase())); if (filteredItems.length > 0) { acc[key] = filteredItems; } return acc; }, {}); // append message if no items are found if (Object.keys(filteredConversations).length === 0) { setHasNoResults(true); } else { setHasNoResults(false); } return filteredConversations; }; return ( <> { setIsOpen(!isOpen); setConversations(initialConversations); }} id="drawer-visible" name="drawer-visible" /> setIsButtonOrderReversed(!isButtonOrderReversed)} id="drawer-actions-visible" name="drawer-actions-visible" > setIsNewChatButtonDisabled(!isNewChatButtonDisabled)} id="drawer-actions-disabled" name="drawer-actions-disabled" > setIsLoading(!isLoading)} id="drawer-is-loading" name="drawer-is-loading" > setHasError(!hasError)} id="drawer-has-error" name="drawer-has-error" > setIsEmpty(!isEmpty)} id="drawer-is-empty" name="drawer-is-empty" > setHasNoResults(!hasNoResults)} id="drawer-has-no-results" name="drawer-has-no-results" > setIsCompact(!isCompact)} id="drawer-compact" name="drawer-compact" > setIsOpen(!isOpen)} isDrawerOpen={isOpen} setIsDrawerOpen={setIsOpen} // eslint-disable-next-line no-console onSelectActiveItem={(e, selectedItem) => console.log(`Selected history item with id ${selectedItem}`)} conversations={conversations} newChatButtonProps={{ isDisabled: isNewChatButtonDisabled }} onNewChat={() => { setIsOpen(!isOpen); }} reverseButtonOrder={isButtonOrderReversed} handleTextInputChange={(value: string) => { if (value === '') { setConversations(initialConversations); setAnnouncement(''); setDebouncedAnnouncement(''); setHasNoResults(false); } else { // this is where you would perform search on the items in the drawer // and update the state const newConversations: { [key: string]: Conversation[] } = findMatchingItems(value); const totalCount = Object.values(newConversations).flat().length; const newAnnouncement = totalCount === 1 ? `${totalCount} conversation matches "${value}"` : `${totalCount} conversations match "${value}"`; setAnnouncement(newAnnouncement); setConversations(newConversations); } }} searchInputScreenReaderText={debouncedAnnouncement} drawerContent={
Drawer content
} isLoading={isLoading} errorState={hasError ? ERROR : undefined} emptyState={isEmpty ? EMPTY_STATE : undefined} noResultsState={hasNoResults ? NO_RESULTS : undefined} isCompact={isCompact} /> ); };