"use client"; import { useState, useEffect } from "react"; import Lightbox from "yet-another-react-lightbox"; import Zoom from "yet-another-react-lightbox/plugins/zoom"; import Captions from "yet-another-react-lightbox/plugins/captions"; import "yet-another-react-lightbox/styles.css"; import "yet-another-react-lightbox/plugins/captions.css"; import Swal from "sweetalert2"; import { MediaDto } from "@/interface/media"; import { URL_MEDIA } from "../../../api"; import { deleteMedia } from "@/service/mediaService"; import { INITIAL_LIMIT } from "../../../constant"; export default function MediaLibrary({ data, onRefresh, }: { data: MediaDto; onRefresh?: () => void; }) { const [index, setIndex] = useState(-1); const [showAllImages, setShowAllImages] = useState(false); const [showAllDocs, setShowAllDocs] = useState(false); const [localMedia, setLocalMedia] = useState(data?.data || []); const [isSelectionMode, setIsSelectionMode] = useState(false); const [selectedIds, setSelectedIds] = useState([]); useEffect(() => { setLocalMedia(data?.data || []); }, [data]); const isImageFile = (file: any) => { const isImageMime = file.mime_type?.startsWith("image/"); const isImageExt = /\.(jpg|jpeg|png|webp|gif)$/i.test(file.storage_key); return isImageMime || isImageExt; }; const imageFiles = localMedia.filter(isImageFile); const documentFiles = localMedia.filter((file) => !isImageFile(file)); const displayedImages = showAllImages ? imageFiles : imageFiles.slice(0, INITIAL_LIMIT); const displayedDocs = showAllDocs ? documentFiles : documentFiles.slice(0, INITIAL_LIMIT); const imageSlides = imageFiles.map((item) => ({ src: `${URL_MEDIA}${item.storage_key}`, title: item.original_name, description: `Kích thước: ${(item.size / 1024).toFixed(2)} KB - Loại: ${item.mime_type}`, })); const toggleSelectionMode = () => { setIsSelectionMode(!isSelectionMode); if (isSelectionMode) { setSelectedIds([]); } }; const toggleItemSelection = (id: string, e?: React.MouseEvent) => { if (e) e.stopPropagation(); if (!isSelectionMode) { setIsSelectionMode(true); setSelectedIds([id]); return; } if (selectedIds.includes(id)) { setSelectedIds(selectedIds.filter((selectedId) => selectedId !== id)); } else { setSelectedIds([...selectedIds, id]); } }; const handleItemClick = (item: any, idx: number, isImage: boolean) => { if (isSelectionMode) { toggleItemSelection(item.id); } else { if (isImage) { setIndex(idx); } else { const fileUrl = `${URL_MEDIA}${item.storage_key}`; const googleDocsUrl = `https://docs.google.com/viewer?url=${encodeURIComponent(fileUrl)}&embedded=true`; window.open(googleDocsUrl, "_blank"); } } }; const handleDeleteSelected = async () => { const result = await Swal.fire({ title: "Xóa tệp đính kèm?", text: `Bạn chuẩn bị xóa ${selectedIds.length} tệp. Hành động này không thể hoàn tác!`, icon: "warning", showCancelButton: true, confirmButtonColor: "#ef4444", cancelButtonColor: "#6b7280", confirmButtonText: "Xóa vĩnh viễn", cancelButtonText: "Hủy", }); if (result.isConfirmed) { try { await deleteMedia(selectedIds); setLocalMedia((prev) => prev.filter((item) => !selectedIds.includes(item.id)), ); setIsSelectionMode(false); setSelectedIds([]); Swal.fire("Thành công!", "Các tệp đã được xóa.", "success"); if (onRefresh) onRefresh(); } catch (error) { Swal.fire("Lỗi!", "Không thể xóa tệp, vui lòng thử lại.", "error"); } } }; const handleDeleteFromLightbox = async () => { const currentImage = imageFiles[index]; if (!currentImage) return; const result = await Swal.fire({ title: "Xóa ảnh này?", text: "Bạn có chắc chắn muốn xóa ảnh này không?", icon: "warning", showCancelButton: true, confirmButtonColor: "#ef4444", cancelButtonColor: "#6b7280", confirmButtonText: "Xóa", cancelButtonText: "Hủy", // customClass: { container: 'z-99999999999999999999999' } }); if (result.isConfirmed) { try { await deleteMedia([currentImage.id]); setLocalMedia((prev) => prev.filter((item) => item.id !== currentImage.id), ); if (imageFiles.length === 1) { setIndex(-1); } else if (index >= imageFiles.length - 1) { setIndex(index - 1); } Swal.fire({ title: "Thành công!", text: "Ảnh đã được xóa.", icon: "success", customClass: { container: "z-[9999999999]" }, }); if (onRefresh) onRefresh(); } catch (error) { Swal.fire({ title: "Lỗi!", text: "Không thể xóa ảnh.", icon: "error", customClass: { container: "z-[9999999999]" }, }); } } }; const renderItemCard = (item: any, isImage: boolean, idx: number) => { const isSelected = selectedIds.includes(item.id); return (
handleItemClick(item, idx, isImage)} className={`group relative aspect-square cursor-pointer overflow-hidden rounded-xl border-2 transition-all ${ isSelected ? "border-blue-500 ring-2 ring-blue-500/30" : "border-gray-200 hover:ring-2 hover:ring-blue-500 hover:ring-offset-2 dark:border-zinc-700 dark:hover:ring-offset-zinc-900" } ${isImage ? "bg-gray-100 dark:bg-zinc-800" : "bg-gray-50 dark:bg-zinc-800"}`} >
toggleItemSelection(item.id, e)} className={`absolute right-2 top-2 z-30 flex h-6 w-6 items-center justify-center rounded-full border-2 transition-all duration-200 ${ isSelected ? "border-blue-500 bg-blue-500" : "border-white bg-black/40 opacity-0 group-hover:opacity-100" } ${isSelectionMode && !isSelected ? "opacity-100" : ""}`} > {isSelected && ( )}
{isImage ? ( <> {item.original_name}

{item.original_name}

{(item.size / 1024).toFixed(0)} KB

{!isSelectionMode && (
Xem ảnh
)} ) : ( <>
📄
{item.original_name}
{!isSelectionMode && (
Xem file
)} )}
); }; return (

Media Assets ({localMedia.length} tệp)

{selectedIds.length > 0 && ( )}
{imageFiles.length > 0 && (

Hình ảnh ({imageFiles.length})

{" "} {displayedImages.map((item, idx) => renderItemCard(item, true, idx), )}
{imageFiles.length > INITIAL_LIMIT && (
)}
)} {documentFiles.length > 0 && (

Tài liệu ({documentFiles.length})

{displayedDocs.map((item, idx) => renderItemCard(item, false, idx), )}
{documentFiles.length > INITIAL_LIMIT && (
)}
)}
= 0} close={() => setIndex(-1)} slides={imageSlides} plugins={[Zoom, Captions]} toolbar={{ buttons: [ , "zoom", "close", ], }} zoom={{ maxZoomPixelRatio: 3 }} animation={{ zoom: 200 }} styles={{ root: { zIndex: 99, "--yarl__color_backdrop": "rgba(0, 0, 0, 0.9)" }, }} />
); }