feat: histories in global chat and roadmap chat (#8775)

* feat: ai chat history

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip: skeleton loading

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* fix: chat history

* wip

* wip

* fix: responsiveness

* wip

* wip

* Chat history UI

* Update chat history

* wip

* Update chat history

* Update chat history

* Fix ai chat not working

* Update

* wip

* feat: show chat history always

* feat: upgrade to pro

* wip

* Update history design

* UI design improvement for empty sidebar

* feat: chat history title

* Fix, delete chat throwing error

* Plus icon when chat is closed

* fix: action z-index

* Improve skeleton and logged out user workflow

* Chat history improvements

* Add plus for chat icons

---------

Co-authored-by: Arik Chakma <arikchangma@gmail.com>
This commit is contained in:
Kamran AhmedandArik Chakma authored and GitHub committed 2025-06-13 01:19:01 +01:00
1 parent 7d91696c85
commit 0f99964bd6
32 files changed
+1995 -325

No files matched your search

+121
View File
@@ -0,0 +1,121 @@
import { infiniteQueryOptions, queryOptions } from '@tanstack/react-query';
import { httpGet } from '../lib/query-http';
import { isLoggedIn } from '../lib/jwt';
import { markdownToHtml } from '../lib/markdown';
import { aiChatRenderer } from '../components/AIChat/AIChat';
import {
type MessagePartRenderer,
renderMessage,
} from '../lib/render-chat-message';
import {
htmlFromTiptapJSON,
type RoadmapAIChatHistoryType,
} from '../hooks/use-roadmap-ai-chat';
import type { JSONContent } from '@tiptap/core';
export type ChatHistoryMessage = {
_id: string;
role: 'user' | 'assistant';
content: string;
json?: JSONContent;
};
export interface ChatHistoryDocument {
_id: string;
userId: string;
roadmapId?: string;
title: string;
messages: ChatHistoryMessage[];
createdAt: Date;
updatedAt: Date;
}
export function chatHistoryOptions(
chatHistoryId?: string,
renderer?: Record<string, MessagePartRenderer>,
) {
return queryOptions({
queryKey: ['chat-history-details', chatHistoryId],
queryFn: async () => {
const data = await httpGet<ChatHistoryDocument>(
`/v1-chat-history/${chatHistoryId}`,
);
if (data.title) {
document.title = data.title;
}
const messages: RoadmapAIChatHistoryType[] = [];
for (const message of data.messages) {
messages.push({
role: message.role,
content: message.content,
...(message.role === 'user' &&
!message?.json && {
html: markdownToHtml(message.content),
}),
...(message.role === 'user' &&
message?.json && {
html: htmlFromTiptapJSON(message.json),
}),
...(message.role === 'assistant' && {
jsx: await renderMessage(message.content, renderer ?? {}, {
isLoading: false,
}),
}),
});
}
return {
...data,
messages,
};
},
enabled: !!isLoggedIn() && !!chatHistoryId,
});
}
type ListChatHistoryQuery = {
perPage?: string;
currPage?: string;
query?: string;
roadmapId?: string;
};
export type ChatHistoryWithoutMessages = Omit<ChatHistoryDocument, 'messages'>;
type ListChatHistoryResponse = {
data: ChatHistoryWithoutMessages[];
totalCount: number;
totalPages: number;
currPage: number;
perPage: number;
};
export function listChatHistoryOptions(
query: ListChatHistoryQuery = {
query: '',
roadmapId: '',
},
) {
return infiniteQueryOptions({
queryKey: ['list-chat-history', query],
queryFn: ({ pageParam }) => {
return httpGet<ListChatHistoryResponse>('/v1-list-chat-history', {
...(query?.query ? { query: query.query } : {}),
...(query?.roadmapId ? { roadmapId: query.roadmapId } : {}),
...(pageParam ? { currPage: pageParam } : {}),
perPage: '21',
});
},
enabled: !!isLoggedIn(),
getNextPageParam: (lastPage, pages) => {
return lastPage.currPage < lastPage.totalPages
? lastPage.currPage + 1
: undefined;
},
initialPageParam: 1,
});
}