165 lines
5.8 KiB
TypeScript
165 lines
5.8 KiB
TypeScript
import { createFileRoute } from '@tanstack/react-router'
|
|
import { route } from '@/constants/routes'
|
|
import { useState } from 'react'
|
|
|
|
import { useAssistant } from '@/hooks/useAssistant'
|
|
|
|
import HeaderPage from '@/containers/HeaderPage'
|
|
import { IconCirclePlus, IconPencil, IconTrash } from '@tabler/icons-react'
|
|
import AddEditAssistant from '@/containers/dialogs/AddEditAssistant'
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from '@/components/ui/dialog'
|
|
import { Button } from '@/components/ui/button'
|
|
import { AvatarEmoji } from '@/containers/AvatarEmoji'
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
export const Route = createFileRoute(route.assistant as any)({
|
|
component: Assistant,
|
|
})
|
|
|
|
function Assistant() {
|
|
const { assistants, addAssistant, updateAssistant, deleteAssistant } =
|
|
useAssistant()
|
|
const [open, setOpen] = useState(false)
|
|
const [editingKey, setEditingKey] = useState<string | null>(null)
|
|
const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false)
|
|
const [deletingId, setDeletingId] = useState<string | null>(null)
|
|
|
|
const handleDelete = (id: string) => {
|
|
setDeletingId(id)
|
|
setDeleteConfirmOpen(true)
|
|
}
|
|
|
|
const confirmDelete = () => {
|
|
if (deletingId) {
|
|
deleteAssistant(deletingId)
|
|
setDeleteConfirmOpen(false)
|
|
setDeletingId(null)
|
|
}
|
|
}
|
|
|
|
const handleSave = (assistant: Assistant) => {
|
|
if (editingKey) {
|
|
updateAssistant(assistant)
|
|
} else {
|
|
addAssistant(assistant)
|
|
}
|
|
setOpen(false)
|
|
setEditingKey(null)
|
|
}
|
|
|
|
return (
|
|
<div className="flex h-full flex-col flex-justify-center">
|
|
<HeaderPage>
|
|
<span>Assistants</span>
|
|
</HeaderPage>
|
|
<div className="h-full p-4 overflow-y-auto">
|
|
<div className="grid grid-cols-3 gap-4">
|
|
{assistants.map((assistant) => (
|
|
<div
|
|
className="bg-main-view-fg/3 p-3 rounded-md"
|
|
key={assistant.id}
|
|
>
|
|
<div className="flex items-center justify-between gap-2">
|
|
<h3 className="text-base font-medium text-main-view-fg/80">
|
|
<div className="flex items-center gap-1">
|
|
<span className="shrink-0 w-4 h-4 relative flex items-center justify-center">
|
|
<AvatarEmoji
|
|
avatar={assistant?.avatar}
|
|
imageClassName="object-cover"
|
|
textClassName="text-sm"
|
|
/>
|
|
</span>
|
|
<span className="line-clamp-1">{assistant.name}</span>
|
|
</div>
|
|
</h3>
|
|
<div className="flex items-center gap-0.5">
|
|
{/* <div
|
|
className="size-6 cursor-pointer flex items-center justify-center rounded hover:bg-main-view-fg/10 transition-all duration-200 ease-in-out"
|
|
title="Edit Assistant in JSON"
|
|
>
|
|
<IconCodeCircle
|
|
size={18}
|
|
className="text-main-view-fg/50"
|
|
/>
|
|
</div> */}
|
|
<div
|
|
className="size-6 cursor-pointer flex items-center justify-center rounded hover:bg-main-view-fg/10 transition-all duration-200 ease-in-out"
|
|
title="Edit Assistant"
|
|
onClick={() => {
|
|
setEditingKey(assistant.id)
|
|
setOpen(true)
|
|
}}
|
|
>
|
|
<IconPencil size={18} className="text-main-view-fg/50" />
|
|
</div>
|
|
<div
|
|
className="size-6 cursor-pointer flex items-center justify-center rounded hover:bg-main-view-fg/10 transition-all duration-200 ease-in-out"
|
|
title="Delete Assistant"
|
|
onClick={() => handleDelete(assistant.id)}
|
|
>
|
|
<IconTrash size={18} className="text-main-view-fg/50" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<p
|
|
className="text-main-view-fg/50 mt-1 line-clamp-2"
|
|
title={assistant.description}
|
|
>
|
|
{assistant.description}
|
|
</p>
|
|
</div>
|
|
))}
|
|
<div
|
|
className="bg-main-view p-3 rounded-md border border-dashed border-main-view-fg/10 flex items-center justify-center cursor-pointer hover:bg-main-view-fg/1 transition-all duration-200 ease-in-out"
|
|
key="new-assistant"
|
|
onClick={() => {
|
|
setEditingKey(null)
|
|
setOpen(true)
|
|
}}
|
|
>
|
|
<IconCirclePlus className="text-main-view-fg/50" />
|
|
</div>
|
|
</div>
|
|
<AddEditAssistant
|
|
open={open}
|
|
onOpenChange={setOpen}
|
|
editingKey={editingKey}
|
|
initialData={
|
|
editingKey ? assistants.find((a) => a.id === editingKey) : undefined
|
|
}
|
|
onSave={handleSave}
|
|
/>
|
|
<Dialog open={deleteConfirmOpen} onOpenChange={setDeleteConfirmOpen}>
|
|
<DialogContent>
|
|
<DialogHeader>
|
|
<DialogTitle>Delete Assistant</DialogTitle>
|
|
<DialogDescription>
|
|
Are you sure you want to delete this assistant? This action
|
|
cannot be undone.
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
<DialogFooter>
|
|
<Button
|
|
variant="link"
|
|
onClick={() => setDeleteConfirmOpen(false)}
|
|
>
|
|
Cancel
|
|
</Button>
|
|
<Button variant="destructive" onClick={confirmDelete} autoFocus>
|
|
Delete
|
|
</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|