Skip to content

Commit

Permalink
Merge pull request #34 from ai-cfia/30-give-users-the-ability-to-send…
Browse files Browse the repository at this point in the history
…-multiple-picture-at-once

30 + 24
  • Loading branch information
SamuelPelletierEvraire authored May 29, 2024
2 parents ff24974 + d799520 commit 2ba136a
Show file tree
Hide file tree
Showing 12 changed files with 353 additions and 100 deletions.
4 changes: 2 additions & 2 deletions src/Components/DragDropFileInput/DragDropFileInput.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
display: flex;
justify-content: center;
align-items: center;
width: 300px; /* Set your desired width here */
height: 200px; /* Set your desired height here */
width: 100%;
height: 400px;
background-color: #fff; /* White background color */
border: 2px solid #ccc; /* Gray border color */
border-radius: 5px; /* Rounded corners */
Expand Down
23 changes: 11 additions & 12 deletions src/Components/DragDropFileInput/DragDropFileInput.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import React, { useState, useRef } from "react";
import React, { useState, useRef, useEffect } from "react";
import "./DragDropFileInput.css";
interface FileInputProps {
sendChange: (files: File[]) => void;
file: string;
}

const DragDropFileInput: React.FC<FileInputProps> = ({ sendChange }) => {
const DragDropFileInput: React.FC<FileInputProps> = ({ sendChange, file }) => {
const [dragActive, setDragActive] = useState(false);
const fileInput = useRef(null);
const [file, setFile] = useState("");

const fileInput = useRef<null | HTMLInputElement>(null);
useEffect(()=>{
if(file==""){
const input = fileInput!.current as HTMLInputElement;
input.value="";
}
},[file])
const handleDrag = (event: React.DragEvent<HTMLLabelElement>) => {
event.preventDefault();
if (event.type === "dragover") {
Expand All @@ -35,12 +40,6 @@ const DragDropFileInput: React.FC<FileInputProps> = ({ sendChange }) => {

const handleFileChange = (files: File[]) => {
if (files!.length > 0) {
const reader = new FileReader();
reader.onload = (e) => {
const newFile = e!.target!.result! as string;
setFile(newFile);
};
reader.readAsDataURL(files[0]!);
sendChange(files);
}
};
Expand All @@ -51,7 +50,7 @@ const DragDropFileInput: React.FC<FileInputProps> = ({ sendChange }) => {
};

const handleCancel = () => {
setFile("");
sendChange([]);
};

return (
Expand Down
79 changes: 77 additions & 2 deletions src/Components/FileList/FileElement/FileElement.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,78 @@
.file-element{
border: 2px solid #ddd;
}
position: relative;
border: 2px solid #999;
border-radius: 5px;
background-color: #ccc;
display:grid;
grid-template-areas: "pic title";
grid-template-columns: 36% 62%;
gap: 2%;
align-items: center;
width: 95%;
margin: 5px 2%;
transition: box-shadow 0.3s ease;
transition: border-color 0.3s ease;
}


.file-element:hover{
box-shadow: 0 8px 16px rgba(255, 255, 255, 0.2);
}

.file-element.selected{
background-color: #aaa;
border-color: #666;
}

.file-element img{
max-width:100px;
margin:5px;
height: auto;
grid-area: pic;
}

.file-element p{
grid-area: title;
overflow: hidden;
}
.file-element:hover .cross {
opacity: 1;
}
.cross {
position: absolute;
top: -15px;
right: -15px;
width: 30px;
height: 30px;
background-color: transparent;
cursor: pointer;
opacity: 0;
transition: opacity 0.3s ease;
border: solid;
border-radius: 100%;
background: #777a;
}

.card:hover .cross {
opacity: 1;
}

.cross:before,
.cross:after {
content: "";
position: absolute;
top: 50%;
left: 50%;
width: 2px;
height: 15px;
background-color: #333;
transform: translate(-50%, -50%);
}

.cross:before {
transform: translate(-50%, -50%) rotate(45deg);
}

.cross:after {
transform: translate(-50%, -50%) rotate(-45deg);
}
65 changes: 46 additions & 19 deletions src/Components/FileList/FileElement/FileElement.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,52 @@
import React from "react";

interface FileElementProps{
file: File;
position: number;
import React, { useState, useEffect, useRef } from "react";
import "./FileElement.css"
interface FileElementProps {
key: number;
file: File;
position: number;
onClick: (selected:boolean) => void; // Function to be called on click
onDelete: ()=>void;
}

const FileElement: React.FC<FileElementProps> = ({file, position})=>{
console.log(file)
let fileUrl = "";
const FileElement: React.FC<FileElementProps> = ({ file, position, onClick, onDelete }) => {
const [fileUrl, setFileUrl] = useState("");
const fileCard = useRef<null | HTMLDivElement>(null);
useEffect(() => {
const reader = new FileReader();
reader.onload = (e) => {
const newFile = e!.target!.result!;
fileUrl = newFile as string
};
reader.onload = (e) => setFileUrl(e?.target?.result as string || "");
reader.readAsDataURL(file);
return(
<div className="file-element" id={"file_"+position}>
<img src={fileUrl}></img>
</div>
)
}, [file]);

}
const handleClick = (event: React.MouseEvent<HTMLDivElement>) => {
event.preventDefault(); // Prevent default navigation
const element = event.target as HTMLElement;
if(element.className !== ("cross")){
document.querySelectorAll(".file-element").forEach(div=>(div.id!=fileCard.current?.id && div.classList.remove("selected")))
if(fileCard.current?.classList.contains("selected")){
onClick?.(false);
fileCard.current?.classList.remove("selected");
}else{
onClick?.(true);
fileCard.current?.classList.add("selected");
}
}
};

const deleteImage = (event: React.MouseEvent<HTMLDivElement>)=>{
event.preventDefault()
onDelete();
}

return (
<div ref={fileCard} className="file-element" id={"file_" + position} onClick={handleClick}>
<img
src={fileUrl}
alt={file.name}
/>
<p className="file-title black bold unselectable">{file.name}</p>
<div className="cross" onClick={deleteImage}></div>
</div>
);
};

export default FileElement
export default FileElement;
56 changes: 47 additions & 9 deletions src/Components/FileList/FileList.css
Original file line number Diff line number Diff line change
@@ -1,21 +1,59 @@
.file-list{
.file-list {
border: 2px solid #ccc;
border-radius: 5px;
grid-area: b;
padding: 5px;
width: 105%;

}

@media only screen and (min-width:850px) {
.file-list.empty{
width: 100%;
}
}

.file-list.empty{
@media only screen and (max-width:850px){
.file-list.empty{
width: 96%;
}
.file-list{
display: flex;
align-items: center;
justify-content: center;
width: 159%;
flex-direction: column;
}
}

.no-element{

.file-list.empty {
display: flex;
align-items: center;
justify-content: center;
}

.no-element {
display: none;
}

.no-element.active{
}
.no-element.active {
display: block;
}
}

.overlay {
position: absolute; /* Positioned absolutely within FileList */
top: 0;
left: 0; /* Initial position (can be adjusted based on selection) */
width: 100%; /* Adjust width/height as needed */
height: 100%;
background-color: rgba(0, 0, 0, 0.5); /* Gray overlay with opacity */
display: flex; /* Center image content horizontally and vertically */
align-items: center;
justify-content: center;
z-index: 1; /* Ensure overlay is above FileElement components */
visibility: hidden; /* Initially hidden */
}

.overlay.active {
visibility: visible; /* Show overlay when an image is selected */
}

59 changes: 41 additions & 18 deletions src/Components/FileList/FileList.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,47 @@
import React, { useState } from "react";
import React, { useState, useRef } from "react";
import "./FileList.css";
import FileElement from "./FileElement/FileElement";
interface FileListProps{
files: File[]

interface FileListProps {
files: File[];
onSelectedChange: (file:File|null)=>void;
propagateDelete: (file:File, wasShown:boolean)=>void;
}

const FileList: React.FC<FileListProps> = ({files})=>{
const FileList: React.FC<FileListProps> = ({ files, onSelectedChange, propagateDelete}) => {
const [selectedFile, setSelectedFile] = useState<File | null>(null);

return (
<div className={`file-list ${files.length==0 ? 'empty' : ''}`}>
<div className={`no-element ${files.length==0 ? 'active' : ''}`}>
No element to show
</div>
{[...files].map(
(file: File, index: number, array: File[]) => (
<FileElement file={file} position={index} key={index}/>
)
)}
</div>
);
}
const handleSelectFile = (file: File|null, index: number) => {
setSelectedFile(file);
onSelectedChange(file)
};

const handleDelete = (file: File, index:number)=>{
if(selectedFile===file){
setSelectedFile(null)
propagateDelete(file, false)
}else{
propagateDelete(file, files[files.length-1]===file);
}

}

return (
<div className={`file-list ${files.length === 0 ? "empty" : ""}`}>
<div className={`no-element ${files.length === 0 ? "active" : ""}`}>
No element to show
</div>
{[...files].map((file: File, index: number, array: File[]) => (
<FileElement
key={index}
file={file}
position={index}
onClick={(selected) => selected ? handleSelectFile(file, index): handleSelectFile(null,-1)}
onDelete={()=>handleDelete(file, index)}
/>
))}
</div>
);
};

export default FileList;
export default FileList;
27 changes: 25 additions & 2 deletions src/Components/Header/Header.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
header {
header nav {
background-color: #05486c;
width: 100%;
display: flex;
Expand All @@ -9,7 +9,6 @@ header {

#version {
font-weight: 700;
position: absolute;
right: 12px;
color: red;
align-content: center;
Expand All @@ -18,6 +17,30 @@ header {
border-radius: 5px;
}


#header-img{
max-height: 50px;
width: 90%;
}

@media only screen and (min-width:850px) {
#version{
position: absolute;
}
}

@media only screen and (max-width:850px){
#version{
width: 90%;
position: initial;
}
header ul{
padding:0;
flex-direction: column;
align-items: center;
}
}

ul {
list-style-type: none;
display: flex;
Expand Down
Loading

0 comments on commit 2ba136a

Please sign in to comment.