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}
/>
>
);
};