Untitled

 avatar
unknown
plain_text
14 days ago
6.3 kB
0
Indexable
"use client";

import { HelperText } from "@/components";
import Image from "next/image";
import React, { useCallback, useState, useRef, useEffect } from "react";
import { toast } from "sonner";

interface MediaFile {
  id: string;
  file: File;
  preview: string;
}

const MediaUpload: React.FC<{
  loading: boolean;
  setSelectedImage: (files: File[]) => void;
  selectedImage: File[];
  name: string;
  title: string;
  value: string[];
  onChange: (e: { target: { name: string; value: string[] } }) => void;
  onBlur: (e: { target: { name: string; value: string[] } }) => void;
  message?: string | string[];
  touched?: boolean;
}> = ({
  name,
  title,
  onChange,
  onBlur,
  message,
  touched,
  //  selectedImage,
  setSelectedImage,
  loading,
  value,
}) => {
  const [files, setFiles] = useState<MediaFile[]>([]);
  const [dragActive, setDragActive] = useState(false);
  const fileInputRef = useRef<HTMLInputElement>(null);
  const maxFiles = 3;
  const maxSize = 5;

  const handleClick = () => {
    fileInputRef.current?.click();
  };

  const handleFiles = useCallback(
    async (inputFiles: FileList | null) => {
      if (!inputFiles) return;

      const newFiles = Array.from(inputFiles).filter((file) => {
        const isImage = file.type.startsWith("image/");
        const sizeInMB = file.size / (1024 * 1024);
        return isImage && sizeInMB <= maxSize;
      });

      if (files.length + newFiles.length > maxFiles) {
        toast.message(`Maximum ${maxFiles} files allowed`);
        return;
      }

      // Create preview files for UI
      const previewFiles = newFiles.map((file) => ({
        id: Math.random().toString(36).substring(7),
        file,
        preview: URL.createObjectURL(file),
      }));

      // Update local state for previews
      const newFilesList = [...files, ...previewFiles];
      setFiles(newFilesList);

      // Update parent component for Azure upload
      setSelectedImage(newFiles);

      // Update form field with existing URLs
      // Note: The actual URLs will be managed by the parent through imageUrls
      onChange({ target: { name, value } });
      onBlur({ target: { name, value } });
    },
    [files, name, onChange, onBlur, setSelectedImage, value]
  );

  const handleDrop = useCallback(
    (e: React.DragEvent<HTMLDivElement>) => {
      e.preventDefault();
      e.stopPropagation();
      setDragActive(false);
      handleFiles(e.dataTransfer.files);
    },
    [handleFiles]
  );

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    handleFiles(e.target.files);
  };

  const removeFile = (id: string) => {
    const fileToRemove = files.find((file) => file.id === id);
    if (fileToRemove) {
      URL.revokeObjectURL(fileToRemove.preview);

      const updatedFiles = files.filter((file) => file.id !== id);
      setFiles(updatedFiles);

      // Update parent with remaining files
      const remainingFiles = updatedFiles.map((file) => file.file);
      setSelectedImage(remainingFiles);

      // Update form field
      onChange({ target: { name, value } });
      onBlur({ target: { name, value } });
    }
  };

  // Cleanup function to prevent memory leaks
  useEffect(() => {
    return () => {
      files.forEach((file) => {
        URL.revokeObjectURL(file.preview);
      });
    };
  }, [files]);
  console.log(files,"--files fies")

  return (
    <div className="w-full space-y-4">
      <div className="space-y-2">
        <p className="border-b border-grey-100 bg-grey-25 px-1 py-2 text-base font-semibold text-gray-900">
          {title}
        </p>

        <div className="flex flex-wrap gap-4">
          {files.map((file) => (
            <div
              key={file.id}
              className="relative h-48 w-48 overflow-hidden rounded-lg border">
              <Image
                src={file.preview}
                alt="Product"
                fill
                className="h-full w-full object-cover"
              />
              <button
                type="button"
                onClick={() => removeFile(file.id)}
                className="absolute right-2 top-2 flex h-6 w-6 items-center justify-center rounded-full bg-red-500 text-white">
                ×
              </button>
            </div>
          ))}

          {files.length < maxFiles && (
            <div
              role="button"
              tabIndex={0}
              className={`flex h-48 w-48 cursor-pointer flex-col items-center justify-center rounded-lg border-2 border-dashed transition-colors ${
                dragActive
                  ? "border-blue-500 bg-blue-50"
                  : "border-grey-300 hover:border-grey-400"
              }`}
              onDragOver={(e) => {
                e.preventDefault();
                setDragActive(true);
              }}
              onDragLeave={() => setDragActive(false)}
              onDrop={handleDrop}
              onClick={handleClick}
              onKeyDown={(e) => {
                if (e.key === "Enter" || e.key === " ") {
                  e.preventDefault();
                  handleClick();
                }
              }}>
              <svg
                className="mb-2 h-8 w-8 text-gray-400"
                fill="none"
                stroke="currentColor"
                viewBox="0 0 24 24">
                <path
                  strokeLinecap="round"
                  strokeLinejoin="round"
                  strokeWidth={2}
                  d="M12 4v16m8-8H4"
                />
              </svg>
              <span className="text-gray-500">
                {dragActive
                  ? "Drop here"
                  : loading
                    ? "Uploading..."
                    : "Tap to upload"}
              </span>
            </div>
          )}
        </div>

        <input
          ref={fileInputRef}
          type="file"
          multiple
          accept="image/*"
          className="hidden"
          onChange={handleChange}
        />

        <p className="text-sm text-gray-500">
          Maximum of {maxFiles} images ({maxSize}MB) // File format: PNG and
          JPEG
        </p>

        <HelperText touched={touched} message={message} />
      </div>
    </div>
  );
};

export default MediaUpload;
Leave a Comment