Single File
Upload, replace, and edit a single file attached to a record.
Schema
Use zaf to bind FileInput.Root to a file field:
import { FileInput } from '@repo/storage'
import { zaf } from '@repo/form'
import { z } from 'zod'
export const myFormSchema = z.object({
name: z.string(),
file: zaf(z.file(), {
component: FileInput.Root
}),
})
Create
Upload the file and store the returned createdFile.id as a foreign key:
export const createForm = form(myFormSchema, async ({ file, ...data }) => {
await serverFileManager.createBucket('my-bucket')
const { createdFile } = await serverFileManager.sync('my-bucket', { file })
await db.insert(myTable).values({ ...data, fileId: createdFile.id })
})
Update
Pass oldFileId to replace the previous file. The old file is deleted from both S3 and the database:
export const updateForm = form(myFormSchema, async ({ file, ...data }) => {
if (file) {
const oldFileId = await db.select({ fileId }).from(myTable).where(...).then(r => r[0]?.fileId)
const { createdFile } = await serverFileManager.sync('my-bucket', { file, oldFileId })
// createdFile replaces old file
}
})
Editing -- FileInput.Provider
Wrap the form in FileInput.Provider to show the existing file in the input. This enables preview and replacement:
<FileInput.Provider fileMeta={data.existingFile}>
<TypedForm.Remote form={updateForm} enctype='multipart/form-data' />
</FileInput.Provider>
fileMeta expects an object with name, mimeType, size, key, and bucket.