Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix : [BYOc- Client Advisor] Chat history view #64

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ClientAdvisor/App/frontend/src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export const historyList = async (offset = 0): Promise<Conversation[] | null> =>
title: conv.title,
date: conv.createdAt,
messages: convMessages,
updatedAt : conv.updatedAt
}
return conversation
})
Expand Down
1 change: 1 addition & 0 deletions ClientAdvisor/App/frontend/src/api/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export type Conversation = {
title: string
messages: ChatMessage[]
date: string
updatedAt? : string
}

export enum ChatCompletionType {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,68 +6,105 @@ import { AppStateContext } from '../../state/AppProvider'

import { ChatHistoryListItemGroups } from './ChatHistoryListItem'

interface ChatHistoryListProps {}
interface ChatHistoryListProps { }

export interface GroupedChatHistory {
month: string
title: string
entries: Conversation[]
}

const groupByMonth = (entries: Conversation[]) => {
const groups: GroupedChatHistory[] = [{ month: 'Recent', entries: [] }]
const currentDate = new Date()

entries.forEach(entry => {
const date = new Date(entry.date)
const daysDifference = (currentDate.getTime() - date.getTime()) / (1000 * 60 * 60 * 24)
const monthYear = date.toLocaleString('default', { month: 'long', year: 'numeric' })
const existingGroup = groups.find(group => group.month === monthYear)

if (daysDifference <= 7) {
groups[0].entries.push(entry)
} else {
if (existingGroup) {
existingGroup.entries.push(entry)
} else {
groups.push({ month: monthYear, entries: [entry] })
}
// Helper function to format dates
const formatDate = (date: Date, includeWeekday = false) => {
const options: Intl.DateTimeFormatOptions = { year: 'numeric', month: 'long', day: 'numeric' };
if (includeWeekday) {
options.weekday = 'long';
}
return date.toLocaleDateString(undefined, options);
};


function isLastSevenDaysRange(dateToCheck: any) {
// Get the current date
const currentDate = new Date();
// Calculate the date 2 days ago
const twoDaysAgo = new Date();
twoDaysAgo.setDate(currentDate.getDate() - 2);
// Calculate the date 8 days ago
const eightDaysAgo = new Date();
eightDaysAgo.setDate(currentDate.getDate() - 8);
// Ensure the comparison dates are in the correct order
// We need eightDaysAgo to be earlier than twoDaysAgo
return dateToCheck >= eightDaysAgo && dateToCheck <= twoDaysAgo;
}

const segregateItems = (items: Conversation[]) => {
const today = new Date();
const yesterday = new Date(today);
const last7Days = []
yesterday.setDate(today.getDate() - 1);

// Sort items by updatedAt in descending order
items.sort(
(a, b) => new Date(b.updatedAt ? b.updatedAt : new Date()).getTime() - new Date(a.updatedAt ? a.updatedAt : new Date()).getTime()
);

const groupedItems: {
Today: Conversation[],
Yesterday: Conversation[],
Last7Days: Conversation[],
Older: Conversation[],
Past: { [key: string]: Conversation[] },
} = {
Today: [],
Yesterday: [],
Last7Days: [],
Older: [],
Past: {},
};

items.forEach(item => {
const itemDate = new Date(item.updatedAt ? item.updatedAt : new Date());
const itemDateOnly = itemDate.toDateString();
if (itemDateOnly === today.toDateString()) {
groupedItems.Today.push(item);
} else if (itemDateOnly === yesterday.toDateString()) {
groupedItems.Yesterday.push(item);
}
})

groups.sort((a, b) => {
// Check if either group has no entries and handle it
if (a.entries.length === 0 && b.entries.length === 0) {
return 0 // No change in order
} else if (a.entries.length === 0) {
return 1 // Move 'a' to a higher index (bottom)
} else if (b.entries.length === 0) {
return -1 // Move 'b' to a higher index (bottom)
else if (isLastSevenDaysRange(itemDate)) {
groupedItems.Last7Days.push(item);
}
const dateA = new Date(a.entries[0].date)
const dateB = new Date(b.entries[0].date)
return dateB.getTime() - dateA.getTime()
})

groups.forEach(group => {
group.entries.sort((a, b) => {
const dateA = new Date(a.date)
const dateB = new Date(b.date)
return dateB.getTime() - dateA.getTime()
})
})

return groups
}
else {
groupedItems.Older.push(item);
}
});

const finalResult = [
{ title: `Today`, entries: groupedItems.Today },
{
title: `Yesterday`,
entries: groupedItems.Yesterday,
},
{
title: `Last 7 days`,
entries: groupedItems.Last7Days,
},
{
title: `Older`,
entries: groupedItems.Older,
},
];

return finalResult;
};


const ChatHistoryList: React.FC<ChatHistoryListProps> = () => {
const appStateContext = useContext(AppStateContext)
const chatHistory = appStateContext?.state.chatHistory

React.useEffect(() => {}, [appStateContext?.state.chatHistory])

React.useEffect(() => { }, [appStateContext?.state.chatHistory])
let groupedChatHistory
if (chatHistory && chatHistory.length > 0) {
groupedChatHistory = groupByMonth(chatHistory)
groupedChatHistory = segregateItems(chatHistory)
} else {
return (
<Stack horizontal horizontalAlign="center" verticalAlign="center" style={{ width: '100%', marginTop: 10 }}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ interface ChatHistoryListItemCellProps {
}

interface ChatHistoryListItemGroupsProps {
groupedChatHistory: GroupedChatHistory[]
groupedChatHistory: GroupedChatHistory[],
}

const formatMonth = (month: string) => {
Expand Down Expand Up @@ -95,11 +95,11 @@ export const ChatHistoryListItemCell: React.FC<ChatHistoryListItemCellProps> = (
}
}, [appStateContext?.state.currentChat?.id, item?.id])

useEffect(()=>{
useEffect(() => {
let v = appStateContext?.state.isRequestInitiated;
if(v!=undefined)
if (v != undefined)
setIsButtonDisabled(v && isSelected)
},[appStateContext?.state.isRequestInitiated])
}, [appStateContext?.state.isRequestInitiated])

const onDelete = async () => {
appStateContext?.dispatch({ type: 'TOGGLE_LOADER' });
Expand Down Expand Up @@ -188,24 +188,20 @@ export const ChatHistoryListItemCell: React.FC<ChatHistoryListItemCellProps> = (
key={item.id}
tabIndex={0}
aria-label="chat history item"
className={styles.itemCell}
className={`${styles.itemCell} ${isSelected ? styles.selectedItemCell : ""}`}
onClick={() => handleSelectItem()}
onKeyDown={e => (e.key === 'Enter' || e.key === ' ' ? handleSelectItem() : null)}
verticalAlign="center"
// horizontal
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
styles={{
root: {
backgroundColor: isSelected ? '#e6e6e6' : 'transparent'
}
}}>
>
{edit ? (
<>
<Stack.Item style={{ width: '100%' }}>
<form aria-label="edit title form" onSubmit={e => handleSaveEdit(e)} style={{ padding: '5px 0px' }}>
<Stack horizontal verticalAlign={'start'}>
<Stack.Item>
<Stack horizontal verticalAlign={'start'} style={{ width: '100%', justifyContent: 'space-between' }}>
<Stack.Item style={{ flex: 1 }}>
<TextField
componentRef={textFieldRef}
autoFocus={textFieldFocused}
Expand All @@ -222,21 +218,23 @@ export const ChatHistoryListItemCell: React.FC<ChatHistoryListItemCellProps> = (
<Stack aria-label="action button group" horizontal verticalAlign={'center'}>
<IconButton
role="button"
className={styles.itemButton}
disabled={errorRename !== undefined}
onKeyDown={e => (e.key === ' ' || e.key === 'Enter' ? handleSaveEdit(e) : null)}
onClick={e => handleSaveEdit(e)}
aria-label="confirm new title"
iconProps={{ iconName: 'CheckMark' }}
styles={{ root: { color: 'green', marginLeft: '5px' } }}
styles={{ root: { color: 'green' } }}
/>
<IconButton
role="button"
className={styles.itemButton}
disabled={errorRename !== undefined}
onKeyDown={e => (e.key === ' ' || e.key === 'Enter' ? cancelEditTitle() : null)}
onClick={() => cancelEditTitle()}
aria-label="cancel edit title"
iconProps={{ iconName: 'Cancel' }}
styles={{ root: { color: 'red', marginLeft: '5px' } }}
styles={{ root: { color: 'red' } }}
/>
</Stack>
</Stack.Item>
Expand All @@ -255,28 +253,26 @@ export const ChatHistoryListItemCell: React.FC<ChatHistoryListItemCellProps> = (
</>
) : (
<>
<Stack horizontal verticalAlign={'center'} style={{ width: '100%' }}>
<Stack horizontal verticalAlign={'center'} style={{ width: '100%', justifyContent: 'space-between' }}>
<div className={styles.chatTitle}>{truncatedTitle}</div>
{(isSelected || isHovered) && (
<Stack horizontal horizontalAlign="end">
<IconButton
className={styles.itemButton}
disabled={isButtonDisabled}
iconProps={{ iconName: 'Delete' }}
title="Delete"
onClick={toggleDeleteDialog}
onKeyDown={e => (e.key === ' ' ? toggleDeleteDialog() : null)}
/>
<IconButton
className={styles.itemButton}
disabled={isButtonDisabled}
iconProps={{ iconName: 'Edit' }}
title="Edit"
onClick={onEdit}
onKeyDown={e => (e.key === ' ' ? onEdit() : null)}
/>
</Stack>
)}
<Stack horizontal horizontalAlign="end">
<IconButton
className={styles.itemButton}
disabled={isButtonDisabled}
iconProps={{ iconName: 'Delete' }}
title="Delete"
onClick={toggleDeleteDialog}
onKeyDown={e => (e.key === ' ' ? toggleDeleteDialog() : null)}
/>
<IconButton
className={styles.itemButton}
disabled={isButtonDisabled}
iconProps={{ iconName: 'Edit' }}
title="Edit"
onClick={onEdit}
onKeyDown={e => (e.key === ' ' ? onEdit() : null)}
/>
</Stack>
</Stack>
</>
)}
Expand Down Expand Up @@ -369,11 +365,11 @@ export const ChatHistoryListItemGroups: React.FC<ChatHistoryListItemGroupsProps>
<Stack
horizontalAlign="start"
verticalAlign="center"
key={group.month}
key={group.title}
className={styles.chatGroup}
aria-label={`chat history group: ${group.month}`}>
<Stack aria-label={group.month} className={styles.chatMonth}>
{formatMonth(group.month)}
aria-label={`chat history group: ${group.title}`}>
<Stack aria-label={group.title} className={styles.chatMonth}>
{group.title}
</Stack>
<List
aria-label={`chat history list`}
Expand All @@ -382,20 +378,11 @@ export const ChatHistoryListItemGroups: React.FC<ChatHistoryListItemGroupsProps>
className={styles.chatList}
/>
<div ref={observerTarget} />
<Separator
styles={{
root: {
width: '100%',
position: 'relative',
'::before': {
backgroundColor: '#d6d6d6'
}
}
}}
/>
</Stack>
)
)}


{showSpinner && (
<div className={styles.spinnerContainer}>
<Spinner size={SpinnerSize.small} aria-label="loading more chat history" className={styles.spinner} />
Expand Down
Loading