Skip to content

Commit

Permalink
Merge pull request #8 from UofA-Blueprint/ASC-73
Browse files Browse the repository at this point in the history
ASC-73: Upload Media Zone
  • Loading branch information
TienDucHo authored Feb 26, 2024
2 parents babceff + 381639d commit 499c8ce
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import DropdownItem from "@/components/DropdownItem";
import SortDropdownListTestRoute from "@/routes/SortDropdownListTestRoute";
import NavigationTest from "@/routes/NavigationTest";
import ToastTestRoute from "@/routes/ToastTestRoute";
import MediaUploadZoneTestRoute from "@/routes/MediaUploadZoneTestRoute";

const router = createBrowserRouter([
{
Expand All @@ -35,6 +36,11 @@ const router = createBrowserRouter([
element: <NavigationTest />,
},
{
path: "/upload-file-test",
element: <MediaUploadZoneTestRoute />,
},
{

path: "/toast-test",
element: <ToastTestRoute />,
},
Expand Down
121 changes: 121 additions & 0 deletions src/components/MediaUploadZone.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import { UploadSimple, WarningCircle } from "@phosphor-icons/react";
import { useState, useEffect, useRef } from "react";

interface MediaUploadZoneProps {
onFilesDropped: (files: File[]) => void;
fontSize?: string;
}

const MediaUploadZone: React.FC<MediaUploadZoneProps> = ({
onFilesDropped,
}) => {
// parent ref
const parentRef = useRef<HTMLDivElement>(null);

// handling sizing
// handling drop in file
const [isDragOver, setIsDragOver] = useState(false);
const [droppedFiles, setDroppedFiles] = useState<File[]>([]);
const [isValidFile, setIsValidFile] = useState(true);

const UploadZoneClassName =
"w-full h-full border-2 border-dashed flex flex-col justify-center items-center rounded-md border-primary-main text-base" +
(isDragOver
? " transform transition-transform duration-300 border-primary-dark ease-in-out scale-95"
: "");

// handle drop events, drop the PNG, JPEG and GIF type of file
const handleDrop = (event: React.DragEvent<HTMLDivElement>) => {
event.preventDefault();
const files = Array.from(event.dataTransfer.files);
const validFiles = filterValidFiles(files);

setDroppedFiles((prevFiles) => [...prevFiles, ...validFiles]);
setIsDragOver(false);
};

const filterValidFiles = (files: File[]): File[] => {
const allowedExtensions = [".jpg", ".jpeg", ".png", ".gif"];

return files.filter((file) => {
const extension = file.name
.toLowerCase()
.slice(file.name.lastIndexOf("."));
const isValid = allowedExtensions.includes(extension);
isValid ? setIsValidFile(true) : setIsValidFile(false);
console.log(`File ${file.name} is ${isValid ? "valid" : "invalid"}.`);
return isValid;
});
};

const handleDragOver = (event: React.DragEvent<HTMLDivElement>) => {
event.preventDefault();
setIsDragOver(true);
};

const handleDragLeave = (event: React.DragEvent<HTMLDivElement>) => {
event.preventDefault();
setIsDragOver(false);
};

useEffect(() => {
console.log("Dropped files:", droppedFiles);
}, [droppedFiles]);

return (
<div className="w-full h-full ">
<div
className={UploadZoneClassName}
onDrop={handleDrop}
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
>
<div className="flex flex-col justify-center items-center flex-grow text-body-reg sm:text-body-sm ">
<UploadSimple className="mb-3 leading-normal scale-[2]" />
<div className="leading-normal ">Drag and Drop here</div>
<div className="leading-normal"> or </div>
<input
type="file"
id="fileInput"
onChange={(event) => {
if (event.target.files) {
const files = Array.from(event.target.files);
const validFiles = filterValidFiles(files);
setDroppedFiles((prevFiles) => [...prevFiles, ...validFiles]);
}
}}
className="hidden"
/>
<label
htmlFor="fileInput"
className="text-primary-main cursor-pointer leading-normal"
>
Browse file
</label>
</div>
{droppedFiles.length > 0 && (
<div className="truncate w-5/6 flex flex-col items-center overflow-hidden">
{droppedFiles.slice(0, 3).map((file, index) => (
<div key={index} className="truncate w-full text-center">
{file.name}
</div>
))}
{droppedFiles.length > 3 && <div>...</div>}
</div>
)}
</div>
<div className="flex flex-row justify-between text-xs text-gray-500 mt-0.5">
<div>Accepted file types: png, jpeg</div>
<div>Max size: 25MB</div>
</div>
{!isValidFile && (
<div className="flex flex-row text-xs text-red-500">
<WarningCircle className="mt-0.5 mr-0.5"></WarningCircle> File type
not supported
</div>
)}
</div>
);
};

export default MediaUploadZone;
22 changes: 22 additions & 0 deletions src/routes/MediaUploadZoneTestRoute.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from "react";
import MediaUploadZone from "@/components/MediaUploadZone";

const MediaUploadZonetestRoute: React.FC = () => {
const handleFilesDropped = (files: File[]) => {
// handle file
console.log("Dropped files:", files);
};

return (
<div className="w-full h-full flex flex-col">
<div className="grid place-items-center h-screen ">
{/* renember to put it in a parent div that is large enough */}
<div className="w-9/12 h-64 mb-4 ">
<MediaUploadZone onFilesDropped={handleFilesDropped} />
</div>
</div>
</div>
);
};

export default MediaUploadZonetestRoute;

0 comments on commit 499c8ce

Please sign in to comment.