import { useEffect } from 'react'
import { ClapEntity, ClapSegmentCategory, newEntity } from '@aitube/clap'
import { useTimeline } from '@aitube/timeline'
import { FormFile } from '@/components/forms/FormFile'
import { FormInput } from '@/components/forms/FormInput'
import { FormSection } from '@/components/forms/FormSection'
import { FormSelect } from '@/components/forms/FormSelect'
import { Button } from '@/components/ui/button'
import { useEntityEditor, useIO } from '@/services'
function EntityList({
onSelectEntity,
}: {
onSelectEntity: (entityId: string) => void
}) {
const entities = useTimeline((s) => s.entities)
const setCurrent = useEntityEditor((s) => s.setCurrent)
const addEntity = useEntityEditor((s) => s.addEntity)
const removeEntity = useEntityEditor((s) => s.removeEntity)
const handleAddEntity = () => {
const entity: ClapEntity = newEntity({
id: Date.now().toString(),
label: 'NEW_ENTITY',
category: ClapSegmentCategory.CHARACTER,
description: '',
appearance: '',
}) // ignoring some fields for now
addEntity(entity)
}
return (
Entities
{entities.map((entity: ClapEntity) => (
-
))}
)
}
export function EntityEditor() {
const entities = useTimeline((s) => s.entities)
const updateEntities = useTimeline((s) => s.updateEntities)
const saveEntitiesToClap = useIO((s) => s.saveEntitiesToClap)
const openEntitiesFromClap = useIO((s) => s.openEntitiesFromClap)
const current = useEntityEditor((s) => s.current)
const setCurrent = useEntityEditor((s) => s.setCurrent)
const draft = useEntityEditor((s) => s.draft)
const setDraft = useEntityEditor((s) => s.setDraft)
const showEntityList = useEntityEditor((s) => s.showEntityList)
const setShowEntityList = useEntityEditor((s) => s.setShowEntityList)
useEffect(() => {
setCurrent(entities.at(0))
}, [entities, setCurrent])
useEffect(() => {
setDraft(current)
}, [current, setDraft])
const handleInputChange = (
field: keyof ClapEntity,
value: string | number | undefined
) => {
if (!draft) {
return
}
let updatedValue = value
if (field === 'age') {
updatedValue = value === '' ? undefined : parseInt(value as string)
}
if (field === 'label') {
updatedValue = value?.toString().toUpperCase()
}
setDraft({ ...draft, [field]: updatedValue })
}
const handleSave = () => {
if (!draft) {
return
}
updateEntities([draft])
}
const handleFileUpload = async (field: 'imageId' | 'audioId', file: File) => {
if (!draft) {
return
}
const dataUrl = await new Promise((resolve) => {
const reader = new FileReader()
reader.onload = (e) => resolve(e.target?.result as string)
reader.readAsDataURL(file)
})
setDraft({ ...draft, [field]: dataUrl })
}
const handleExport = async () => {
if (!draft) {
return
}
await saveEntitiesToClap([draft])
}
const handleImport = async (file: File) => {
await openEntitiesFromClap(file)
}
const handleBack = () => {
setShowEntityList(true)
}
const handleSelectEntity = (entityId: string) => {
setShowEntityList(false)
}
return (
{showEntityList ? (
) : (
{draft && (
handleInputChange('label', value)}
/>
label="Category"
selectedItemId={draft.category}
items={Object.values(ClapSegmentCategory).map(
(category: ClapSegmentCategory) => ({
id: category,
label: category,
value: category,
})
)}
onSelect={(value) => handleInputChange('category', value)}
/>
{/* ... form fields ... */}
files[0] && handleFileUpload('imageId', files[0])
}
/>
{draft.imageId && (
)}
files[0] && handleFileUpload('audioId', files[0])
}
/>
{draft.audioId && (
)}
handleInputChange('description', value)}
/>
handleInputChange('appearance', value)}
/>
handleInputChange('age', value)}
/>
handleInputChange('gender', value)}
/>
files[0] && handleImport(files[0])}
/>
)}
)}
)
}