oxios 1.12.0

Oxios Agent OS — Agent Operating System powered by oxi-sdk
import { Upload } from 'lucide-react'
import { useCallback, useRef, useState } from 'react'
import { api } from '@/lib/api-client'

interface UploadDropZoneProps {
  currentDir: string
  onUploaded: () => void
}

export function UploadDropZone({ currentDir, onUploaded }: UploadDropZoneProps) {
  const [isDragging, setIsDragging] = useState(false)
  const [uploading, setUploading] = useState(false)
  const inputRef = useRef<HTMLInputElement>(null)

  const uploadFile = useCallback(
    async (file: File) => {
      setUploading(true)
      try {
        const text = await file.text()
        const filePath = currentDir ? `${currentDir}/${file.name}` : file.name
        await api.put(`/api/workspace/file/${encodeURIComponent(filePath)}`, text, true)
        onUploaded()
      } catch (err) {
        console.error('Upload failed:', err)
      } finally {
        setUploading(false)
      }
    },
    [currentDir, onUploaded],
  )

  const handleDrop = useCallback(
    (e: React.DragEvent) => {
      e.preventDefault()
      setIsDragging(false)
      const files = Array.from(e.dataTransfer.files)
      for (const file of files) {
        uploadFile(file)
      }
    },
    [uploadFile],
  )

  const handleFileSelect = useCallback(
    (e: React.ChangeEvent<HTMLInputElement>) => {
      const files = Array.from(e.target.files ?? [])
      for (const file of files) {
        uploadFile(file)
      }
      // Reset so the same file can be re-uploaded
      e.target.value = ''
    },
    [uploadFile],
  )

  return (
    <div
      className={`relative rounded-lg border-2 border-dashed p-4 text-center transition-colors ${
        isDragging
          ? 'border-primary bg-primary/5'
          : 'border-muted-foreground/25 hover:border-muted-foreground/50'
      }`}
      onDragOver={(e) => {
        e.preventDefault()
        setIsDragging(true)
      }}
      onDragLeave={() => setIsDragging(false)}
      onDrop={handleDrop}
    >
      <input ref={inputRef} type="file" className="hidden" multiple onChange={handleFileSelect} />
      <button
        type="button"
        className="flex flex-col items-center gap-1 w-full text-sm text-muted-foreground hover:text-foreground transition-colors"
        onClick={() => inputRef.current?.click()}
        disabled={uploading}
      >
        <Upload className="h-5 w-5" />
        {uploading ? 'Uploading...' : 'Drop files here or click to upload'}
      </button>
    </div>
  )
}