Pular para o conteúdo principal

CarouselSection

O CarouselSection é um componente React funcional projetado para exibir uma coleção de mídias — tanto imagens quanto vídeos — em um carrossel interativo. Ele foi refatorado para suportar múltiplos tipos de mídia de forma unificada, proporcionando uma experiência de usuário coesa.

Responsabilidades

  • Renderizar um carrossel horizontal usando os componentes Carousel da biblioteca shadcn/ui.
  • Exibir imagens e vídeos em um layout consistente.
  • Gerenciar a interação do usuário, abrindo o visualizador apropriado para cada tipo de mídia (imagens no ImageViewerModal, vídeos no VideoViewerModal).
  • Orquestrar o download sob demanda e a geração de thumbnails para os vídeos, otimizando o carregamento inicial da página.

Props

O componente aceita as seguintes propriedades:

  • title?: string: Um título opcional exibido acima do carrossel.
  • images?: string[]: Um array de URLs de imagens.
  • videos?: VideoData[]: Um array de objetos contendo os metadados dos vídeos.
  • nuPrm: string: O identificador único da nota de promotoria, necessário para construir a requisição de download do vídeo.

Lógica Interna

O componente possui uma lógica interna sofisticada para gerenciar o ciclo de vida das mídias.

Unificação de Mídia

Imagens e vídeos são combinados em um único array mediaItems do tipo MediaItem. Isso permite renderizar a lista em um único loop, simplificando a estrutura do componente.

// Definição do tipo MediaItem
type MediaItem = {
type: "image" | "video";
url: string; // URL para imagem, vazio para vídeo
videoData?: VideoData; // Metadados do vídeo
};

// Unificação no componente
const mediaItems: MediaItem[] = [
...images.map((img) => ({ type: "image" as const, url: img })),
...videos.map((video) => ({
type: "video" as const,
url: "",
videoData: video,
})),
];

Download Sob Demanda com useQuery

Para evitar o carregamento pesado de todos os vídeos ao mesmo tempo, o download é feito apenas quando o usuário clica em um item de vídeo.

  • Um estado selectedVideo rastreia qual vídeo foi clicado.
  • O hook useQuery da @tanstack/react-query é ativado (enabled: !!selectedVideo) quando selectedVideo é definido.
  • A função queryFn (downloadVideo) faz uma requisição POST para a API, enviando o ID do vídeo e recebendo o Blob como resposta.
  • Os dados baixados são cacheados pelo react-query (staleTime e gcTime), evitando downloads repetidos do mesmo vídeo em uma sessão.

Geração de Thumbnails Dinâmicas

Após o download bem-sucedido de um vídeo, uma thumbnail é gerada no cliente para ser exibida no carrossel. Isso melhora a experiência do usuário, que passa a ver uma prévia do conteúdo do vídeo.

  • A função generateThumbnailFromBlob cria um elemento <video> e um <canvas> em memória.
  • O Blob do vídeo é carregado no elemento <video>.
  • Quando os metadados do vídeo são carregados, o player avança para um ponto específico (ex: 1 segundo) e desenha o frame atual no <canvas>.
  • O conteúdo do canvas é exportado como um Blob de imagem (image/jpeg), e uma URL de objeto é criada (URL.createObjectURL).
  • Essa URL da thumbnail é armazenada no estado thumbnails, que é um mapa do ID do vídeo para a URL da sua thumbnail.

Interação do Usuário

  • handleMediaClick: Função central que é chamada quando um item do carrossel é clicado.
  • Se o item for uma imagem, ele delega a abertura para o useImageViewerModal, passando a lista de todas as imagens e o índice da imagem clicada.
  • Se o item for um vídeo, ele chama handleVideoClick, que atualiza o estado selectedVideo e dispara todo o fluxo de download e visualização.

O componente exibe diferentes estados visuais para um item de vídeo:

  1. Inicial: Mostra um ícone de play e os metadados do vídeo (nome, tamanho).
  2. Carregando: Se o vídeo está sendo baixado, exibe um CircularProgress.
  3. Com Thumbnail: Após o download, exibe a thumbnail gerada com um ícone de play sobreposto.