feat(chat): implement pull-to-refresh functionality and pagination for chat history
This commit is contained in:
@@ -21,12 +21,88 @@ export function applyNetworkHistoryLoadedOutput(
|
||||
output: {
|
||||
messages: UiMessage[];
|
||||
localCount: number;
|
||||
total: number;
|
||||
limit: number;
|
||||
},
|
||||
): Pick<ChatState, "messages" | "historyLoaded"> {
|
||||
): Pick<
|
||||
ChatState,
|
||||
| "messages"
|
||||
| "historyLoaded"
|
||||
| "historyTotal"
|
||||
| "historyLimit"
|
||||
| "nextHistoryOffset"
|
||||
| "isLoadingMoreHistory"
|
||||
> {
|
||||
const localSnapshotSize = output.localCount === 0 ? 1 : output.localCount;
|
||||
const optimisticTail = context.messages.slice(localSnapshotSize);
|
||||
const historyLimit = normalizeHistoryLimit(output.limit);
|
||||
return {
|
||||
messages: [...output.messages, ...optimisticTail],
|
||||
historyLoaded: true,
|
||||
historyTotal: Math.max(0, output.total),
|
||||
historyLimit,
|
||||
nextHistoryOffset: historyLimit,
|
||||
isLoadingMoreHistory: false,
|
||||
};
|
||||
}
|
||||
|
||||
export function applyOlderHistoryLoadedOutput(
|
||||
context: ChatState,
|
||||
output: {
|
||||
messages: UiMessage[];
|
||||
offset: number;
|
||||
total: number;
|
||||
limit: number;
|
||||
},
|
||||
): Pick<
|
||||
ChatState,
|
||||
| "messages"
|
||||
| "historyTotal"
|
||||
| "historyLimit"
|
||||
| "nextHistoryOffset"
|
||||
| "isLoadingMoreHistory"
|
||||
> {
|
||||
const historyLimit = normalizeHistoryLimit(
|
||||
output.limit,
|
||||
context.historyLimit,
|
||||
);
|
||||
return {
|
||||
messages: prependUniqueHistoryMessages(context.messages, output.messages),
|
||||
historyTotal: Math.max(0, output.total),
|
||||
historyLimit,
|
||||
nextHistoryOffset: output.offset + historyLimit,
|
||||
isLoadingMoreHistory: false,
|
||||
};
|
||||
}
|
||||
|
||||
export function canLoadMoreHistory(context: ChatState): boolean {
|
||||
return (
|
||||
context.historyLoaded &&
|
||||
!context.isLoadingMoreHistory &&
|
||||
context.nextHistoryOffset < context.historyTotal
|
||||
);
|
||||
}
|
||||
|
||||
export function normalizeHistoryLimit(
|
||||
limit: number,
|
||||
fallback = CHAT_HISTORY_LIMIT,
|
||||
): number {
|
||||
return Number.isFinite(limit) && limit > 0 ? Math.floor(limit) : fallback;
|
||||
}
|
||||
|
||||
export function prependUniqueHistoryMessages(
|
||||
currentMessages: readonly UiMessage[],
|
||||
olderMessages: readonly UiMessage[],
|
||||
): UiMessage[] {
|
||||
const existingIds = new Set(
|
||||
currentMessages.flatMap((message) => (message.id ? [message.id] : [])),
|
||||
);
|
||||
const pageIds = new Set<string>();
|
||||
const uniqueOlderMessages = olderMessages.filter((message) => {
|
||||
if (!message.id) return true;
|
||||
if (existingIds.has(message.id) || pageIds.has(message.id)) return false;
|
||||
pageIds.add(message.id);
|
||||
return true;
|
||||
});
|
||||
return [...uniqueOlderMessages, ...currentMessages];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user