139 lines
5.1 KiB
TypeScript
139 lines
5.1 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 { DeleteAssistantDialog } from '@/containers/dialogs'
|
|
import { AvatarEmoji } from '@/containers/AvatarEmoji'
|
|
import { useTranslation } from '@/i18n/react-i18next-compat'
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
export const Route = createFileRoute(route.assistant as any)({
|
|
component: Assistant,
|
|
})
|
|
|
|
function Assistant() {
|
|
const { t } = useTranslation()
|
|
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>{t('assistants:title')}</span>
|
|
</HeaderPage>
|
|
<div className="h-full p-4 overflow-y-auto">
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
|
|
{assistants
|
|
.slice()
|
|
.sort((a, b) => a.created_at - b.created_at)
|
|
.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">
|
|
{assistant?.avatar && (
|
|
<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={t('assistants:editAssistant')}
|
|
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={t('assistants:deleteAssistant')}
|
|
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 min-h-[88px] 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}
|
|
/>
|
|
<DeleteAssistantDialog
|
|
open={deleteConfirmOpen}
|
|
onOpenChange={setDeleteConfirmOpen}
|
|
onConfirm={confirmDelete}
|
|
/>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|