npm package: @krlosmgd/uploader
Description: Solución personalizada en React + TypeScript para subir archivos (imágenes y videos) a un servidor mediante URLs firmadas (presigned URLs). Incluye componentes listos para usar y hooks para gestionar el proceso de subida y previsualización.
Latest version: 1.0.1

# Byte Media Uploader

Solución personalizada en React + TypeScript para subir archivos (imágenes y videos) a un servidor mediante URLs firmadas (presigned URLs). Incluye componentes listos para usar y hooks para gestionar el proceso de subida y previsualización.

## Instalación

Instala la librería y sus dependencias:

```sh
npm install @krlosmgd/uploader axios hls.js react react-dom
```

## Configuración

Agrega la variable de entorno con la URL base de tu API:

```env
VITE_API_BASE_URL=http://127.0.0.1:8000/api
```

## Uso Básico

### 1. Subida tradicional

```tsx
import { MediaUploader } from '@krlosmgd/uploader'

function App() {
  const handleUploaded = (url: string) => {
    console.log('Archivo subido en:', url)
  }

  return <MediaUploader onUploaded={handleUploaded} />
}
```

### 2. Drag & Drop

```tsx
import { MediaUploaderDragAndDrop } from '@krlosmgd/uploader'

function App() {
  const handleUploaded = (url: string) => {
    alert('Archivo subido en: ' + url)
  }

  return <MediaUploaderDragAndDrop onUploaded={handleUploaded} />
}
```

### 3. Previsualización de archivos

```tsx
import { MediaPreview } from '@krlosmgd/uploader'

function PreviewExample({ file }: { file: File }) {
  return <MediaPreview file={file} />
}
```

### 4. Reproductor de video (incluye soporte para m3u8/HLS)

```tsx
import { VideoPlayer } from '@krlosmgd/uploader'

function VideoExample() {
  return <VideoPlayer src="https://mi-servidor.com/video.m3u8" />
}
```

## Hook para subida personalizada

Si quieres controlar el proceso de subida manualmente:

```tsx
import { useSignedUpload } from '@krlosmgd/uploader'

function CustomUploader() {
  const { generateSignedUpload, status, progress } = useSignedUpload()

  const handleFile = async (file: File) => {
    const url = await generateSignedUpload(file)
    if (url) {
      // Subida exitosa
    } else {
      // Error al subir
    }
  }

  // ...tu lógica y UI
}
```

## Manejo de errores

- **Error de red o servidor:** Si la API no responde o devuelve error, el estado será `"error"`. Puedes mostrar un mensaje y permitir reintentar.
- **Archivo no soportado:** Usa el componente `MediaPreview` para mostrar un mensaje si el formato no es válido.
- **Progreso de subida:** El hook y los componentes muestran el progreso en tiempo real.
- **Validación:** Puedes limitar los tipos de archivos aceptados usando la prop `accepted` en `MediaUploader`.

## Ejemplo completo

```tsx
import {
  MediaUploader,
  MediaUploaderDragAndDrop,
  MediaPreview,
  VideoPlayer,
  useSignedUpload
} from '@krlosmgd/uploader'

function App() {
  const [fileUrl, setFileUrl] = useState<string | null>(null)

  return (
    <div>
      <h1>Sube tu archivo</h1>
      <MediaUploader onUploaded={setFileUrl} />
      <MediaUploaderDragAndDrop onUploaded={setFileUrl} />
      {fileUrl && (
        <>
          <h2>Previsualización</h2>
          {/* Si es imagen/video, puedes usar MediaPreview o VideoPlayer */}
          <VideoPlayer src={fileUrl} />
        </>
      )}
    </div>
  )
}
```

## Consideraciones

- La API debe implementar un endpoint `/r2/upload-url` que reciba el nombre del archivo y devuelva una URL firmada para la subida.
- El archivo se sube directamente a la URL firmada usando un PUT.
- El hook y los componentes gestionan el estado de subida, progreso y errores.
- Soporta imágenes (`jpg`, `jpeg`, `png`, `webp`, `gif`) y videos (`mp4`, `mov`, `mkv`, `avi`, `webm`, `m3u8`).

## Personalización

Puedes adaptar los estilos y la lógica de los componentes según tus necesidades. Los componentes están pensados para ser reutilizables y fáciles de integrar.

---

¿Dudas o problemas? Revisa los logs en consola y asegúrate de que la API responde correctamente. Si el estado es `"error"`, revisa la conexión y los permisos del bucket/servidor.