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
Carouselda bibliotecashadcn/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 noVideoViewerModal). - 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
selectedVideorastreia qual vídeo foi clicado. - O hook
useQueryda@tanstack/react-queryé ativado (enabled: !!selectedVideo) quandoselectedVideoé definido. - A função
queryFn(downloadVideo) faz uma requisição POST para a API, enviando o ID do vídeo e recebendo oBlobcomo resposta. - Os dados baixados são cacheados pelo
react-query(staleTimeegcTime), 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
generateThumbnailFromBlobcria um elemento<video>e um<canvas>em memória. - O
Blobdo 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
Blobde 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 estadoselectedVideoe dispara todo o fluxo de download e visualização.
O componente exibe diferentes estados visuais para um item de vídeo:
- Inicial: Mostra um ícone de play e os metadados do vídeo (nome, tamanho).
- Carregando: Se o vídeo está sendo baixado, exibe um
CircularProgress. - Com Thumbnail: Após o download, exibe a thumbnail gerada com um ícone de play sobreposto.