80 lines
2.8 KiB
TypeScript
80 lines
2.8 KiB
TypeScript
"use client";
|
|
|
|
import { useChatHistory } from "../../hooks/use-chat-history.ts";
|
|
import type { NarrativeMessage } from "../../game-engine/narrative-provider.tsx";
|
|
import urlcat from "@bureaudouble/outils/urlcat.ts";
|
|
import { useClientLocale } from "../../game-engine/locale-provider.tsx";
|
|
|
|
export const ChatHistory = () => {
|
|
const { t } = useClientLocale();
|
|
const { history, deleteChat, downloadChat } = useChatHistory<
|
|
NarrativeMessage
|
|
>();
|
|
const sortedHistory = Object.entries(history ?? {}).sort(
|
|
([, a], [, b]) =>
|
|
new Date(b?.at(-1)?.metadata?.createdAt ?? 0).getTime() -
|
|
new Date(a?.at(-1)?.metadata?.createdAt ?? 0).getTime(),
|
|
);
|
|
|
|
return (
|
|
<div className="flex flex-col gap-2 py-1 px-2 text-sm">
|
|
{sortedHistory.length > 0
|
|
? (
|
|
sortedHistory
|
|
.filter(([_, messages]) => Array.isArray(messages))
|
|
.map(([id, messages]) => (
|
|
<div
|
|
key={id}
|
|
className="flex items-start justify-between gap-2 border border-transparent hover:border-ui"
|
|
>
|
|
<a
|
|
href={urlcat("/chat", {
|
|
"session-id": id,
|
|
"model-id": messages
|
|
.filter((v) => v.metadata?.model?.id !== "hardcoded")
|
|
.toReversed()
|
|
.at(-1)?.metadata?.model
|
|
?.id,
|
|
})}
|
|
className="flex-grow truncate group"
|
|
>
|
|
<div className="truncate group-hover:underline">
|
|
{messages
|
|
.filter((v) => v.role === "user")
|
|
.slice(1)
|
|
.flatMap((v) => v.parts)
|
|
.filter((v) => v.type === "text")
|
|
.map((v) => v.text)
|
|
.at(0)}
|
|
</div>
|
|
<div className="text-xs text-muted-foreground">
|
|
{t("lastUpdate")}{" "}
|
|
{new Date(messages.at(-1)?.metadata?.createdAt ?? 0)
|
|
.toLocaleString()}
|
|
</div>
|
|
</a>
|
|
<button
|
|
type="button"
|
|
onClick={() => downloadChat(id)}
|
|
className="cursor-pointer shrink-0 inline hover:underline text-xs"
|
|
>
|
|
{t("exportAction")}
|
|
</button>
|
|
<button
|
|
type="button"
|
|
className="cursor-pointer shrink-0 inline text-red-500 hover:underline text-xs"
|
|
onClick={() => deleteChat(id)}
|
|
>
|
|
{t("deleteAction")}
|
|
</button>
|
|
</div>
|
|
))
|
|
)
|
|
: (
|
|
<p>
|
|
{t("noSavedChats")}
|
|
</p>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|