|
|
@ -53,6 +53,10 @@ export default function ChatPage() {
|
|
|
|
const [editingFactId, setEditingFactId] = useState<string | null>(null);
|
|
|
|
const [editingFactId, setEditingFactId] = useState<string | null>(null);
|
|
|
|
const [editingFactContent, setEditingFactContent] = useState("");
|
|
|
|
const [editingFactContent, setEditingFactContent] = useState("");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// State for editing fact triggers
|
|
|
|
|
|
|
|
const [editingFactTriggerId, setEditingFactTriggerId] = useState<string | null>(null);
|
|
|
|
|
|
|
|
const [editingFactTriggerContent, setEditingFactTriggerContent] = useState("");
|
|
|
|
|
|
|
|
|
|
|
|
// Handle clicking outside to cancel editing
|
|
|
|
// Handle clicking outside to cancel editing
|
|
|
|
useEffect(() => {
|
|
|
|
useEffect(() => {
|
|
|
|
function handleClickOutside(event: MouseEvent) {
|
|
|
|
function handleClickOutside(event: MouseEvent) {
|
|
|
@ -62,13 +66,20 @@ export default function ChatPage() {
|
|
|
|
setEditingFactId(null);
|
|
|
|
setEditingFactId(null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (editingFactTriggerId && event.target instanceof Element) {
|
|
|
|
|
|
|
|
const editingElement = event.target.closest('.editing-fact-trigger');
|
|
|
|
|
|
|
|
if (!editingElement) {
|
|
|
|
|
|
|
|
setEditingFactTriggerId(null);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
document.addEventListener('mousedown', handleClickOutside);
|
|
|
|
document.addEventListener('mousedown', handleClickOutside);
|
|
|
|
return () => {
|
|
|
|
return () => {
|
|
|
|
document.removeEventListener('mousedown', handleClickOutside);
|
|
|
|
document.removeEventListener('mousedown', handleClickOutside);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}, [editingFactId]);
|
|
|
|
}, [editingFactId, editingFactTriggerId]);
|
|
|
|
|
|
|
|
|
|
|
|
const {
|
|
|
|
const {
|
|
|
|
conversation,
|
|
|
|
conversation,
|
|
|
@ -125,6 +136,16 @@ export default function ChatPage() {
|
|
|
|
await trpc.chat.factTriggers.deleteOne.mutate({ factTriggerId });
|
|
|
|
await trpc.chat.factTriggers.deleteOne.mutate({ factTriggerId });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function handleUpdateFactTrigger(factTriggerId: string, content: string) {
|
|
|
|
|
|
|
|
// Update the local state first
|
|
|
|
|
|
|
|
setFactTriggers(factTriggers.map(factTrigger =>
|
|
|
|
|
|
|
|
factTrigger.id === factTriggerId ? { ...factTrigger, content } : factTrigger
|
|
|
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Then update the database
|
|
|
|
|
|
|
|
await trpc.chat.factTriggers.update.mutate({ factTriggerId, content });
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<>
|
|
|
|
<div>
|
|
|
|
<div>
|
|
|
@ -285,16 +306,59 @@ export default function ChatPage() {
|
|
|
|
<List>
|
|
|
|
<List>
|
|
|
|
{factTriggers.map((factTrigger) => (
|
|
|
|
{factTriggers.map((factTrigger) => (
|
|
|
|
<List.Item key={factTrigger.id}>
|
|
|
|
<List.Item key={factTrigger.id}>
|
|
|
|
{factTrigger.content}{" "}
|
|
|
|
{editingFactTriggerId === factTrigger.id ? (
|
|
|
|
<IconTrash
|
|
|
|
<Group wrap="nowrap" className="editing-fact-trigger">
|
|
|
|
size={16}
|
|
|
|
<Textarea
|
|
|
|
stroke={1.5}
|
|
|
|
value={editingFactTriggerContent}
|
|
|
|
onClick={(e) => {
|
|
|
|
onChange={(e) => setEditingFactTriggerContent(e.target.value)}
|
|
|
|
e.stopPropagation();
|
|
|
|
onKeyDown={(e) => {
|
|
|
|
e.preventDefault();
|
|
|
|
if (e.key === "Enter") {
|
|
|
|
handleDeleteFactTrigger(factTrigger.id);
|
|
|
|
e.preventDefault();
|
|
|
|
}}
|
|
|
|
handleUpdateFactTrigger(factTrigger.id, editingFactTriggerContent);
|
|
|
|
/>
|
|
|
|
setEditingFactTriggerId(null);
|
|
|
|
|
|
|
|
} else if (e.key === "Escape") {
|
|
|
|
|
|
|
|
setEditingFactTriggerId(null);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
autoFocus
|
|
|
|
|
|
|
|
style={{ flex: 1 }}
|
|
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
<ActionIcon
|
|
|
|
|
|
|
|
onClick={() => {
|
|
|
|
|
|
|
|
handleUpdateFactTrigger(factTrigger.id, editingFactTriggerContent);
|
|
|
|
|
|
|
|
setEditingFactTriggerId(null);
|
|
|
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
|
|
<IconCheck size={16} />
|
|
|
|
|
|
|
|
</ActionIcon>
|
|
|
|
|
|
|
|
<ActionIcon
|
|
|
|
|
|
|
|
onClick={() => setEditingFactTriggerId(null)}
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
|
|
<IconX size={16} />
|
|
|
|
|
|
|
|
</ActionIcon>
|
|
|
|
|
|
|
|
</Group>
|
|
|
|
|
|
|
|
) : (
|
|
|
|
|
|
|
|
<Group wrap="nowrap">
|
|
|
|
|
|
|
|
<span style={{ flex: 1 }}>{factTrigger.content}</span>
|
|
|
|
|
|
|
|
<ActionIcon
|
|
|
|
|
|
|
|
onClick={() => {
|
|
|
|
|
|
|
|
setEditingFactTriggerId(factTrigger.id);
|
|
|
|
|
|
|
|
setEditingFactTriggerContent(factTrigger.content);
|
|
|
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
|
|
<IconEdit size={16} />
|
|
|
|
|
|
|
|
</ActionIcon>
|
|
|
|
|
|
|
|
<IconTrash
|
|
|
|
|
|
|
|
size={16}
|
|
|
|
|
|
|
|
stroke={1.5}
|
|
|
|
|
|
|
|
onClick={(e) => {
|
|
|
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
|
|
handleDeleteFactTrigger(factTrigger.id);
|
|
|
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
</Group>
|
|
|
|
|
|
|
|
)}
|
|
|
|
</List.Item>
|
|
|
|
</List.Item>
|
|
|
|
))}
|
|
|
|
))}
|
|
|
|
</List>
|
|
|
|
</List>
|
|
|
|