Skip to content

Commit 97eb18c

Browse files
authored
Merge pull request #23 from XRPL-Hackathon/19-feat-파일-업로드-페이지
19 feat 파일 업로드 페이지
2 parents 6c884a5 + 7372435 commit 97eb18c

6 files changed

Lines changed: 525 additions & 1 deletion

File tree

src/assets/image/remove.svg

Lines changed: 14 additions & 0 deletions
Loading

src/assets/image/upload.svg

Lines changed: 4 additions & 0 deletions
Loading
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import styled from "styled-components";
2+
3+
export const UploadWrapper = styled.div`
4+
display: flex;
5+
flex-direction: column;
6+
align-items: center;
7+
justify-content: center;
8+
width: 55vh;
9+
height: 330px;
10+
flex-shrink: 0;
11+
border-radius: 16px;
12+
border: 0px solid #9095a1;
13+
background: #fff;
14+
box-shadow: 0px 0px 2px 0px rgba(23, 26, 31, 0.12),
15+
0px 4px 9px 0px rgba(23, 26, 31, 0.11);
16+
17+
.desdiv {
18+
display: flex;
19+
flex-direction: column;
20+
align-items: center;
21+
justify-content: center;
22+
padding: 16px;
23+
height: 200px;
24+
gap: 20%;
25+
}
26+
27+
.text {
28+
color: #379ae6;
29+
text-align: center;
30+
font-family: Archivo;
31+
font-size: 18px;
32+
font-style: normal;
33+
font-weight: 500;
34+
line-height: 28px; /* 155.556% */
35+
}
36+
37+
.UploadWrapperActive {
38+
background: #0000000f;
39+
width: 400px;
40+
height: 200px;
41+
border: 2px dotted black;
42+
opacity: 0.7;
43+
}
44+
45+
.UploadArea {
46+
display: flex;
47+
justify-content: center;
48+
align-items: center;
49+
width: 100%;
50+
height: 100%;
51+
}
52+
53+
.FileContainer {
54+
display: flex;
55+
flex-direction: column;
56+
justify-content: center;
57+
align-items: start;
58+
margin-top: 10px;
59+
gap: 2px;
60+
}
61+
62+
.UploadFile {
63+
display: flex;
64+
flex-direction: row;
65+
justify-content: space-between;
66+
align-items: center;
67+
width: 100%;
68+
padding: 5px;
69+
background-color: #0000000f;
70+
border-radius: 5px;
71+
}
72+
73+
.Filename {
74+
display: flex;
75+
flex-direction: row;
76+
justify-content: center;
77+
align-items: center;
78+
}
79+
80+
.DeleteBtn {
81+
display: flex;
82+
flex-direction: row;
83+
justify-content: center;
84+
align-items: center;
85+
text-align: center;
86+
vertical-align: center;
87+
}
88+
89+
.DeleteBtn:hover {
90+
cursor: pointer;
91+
}
92+
`;
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
import * as S from "@/pages/FileUploadPage/FileUpload.style";
2+
import { ChangeEvent, useCallback, useRef, useState, useEffect } from "react";
3+
import upload from "@/assets/image/upload.svg";
4+
import remove from "@/assets/image/remove.svg";
5+
6+
interface FileFormat {
7+
id: number;
8+
content: File;
9+
}
10+
11+
const Upload = () => {
12+
const [files, setFiles] = useState<FileFormat[]>([]);
13+
const [isDragging, setIsDragging] = useState<boolean>(false);
14+
const dragRef = useRef<HTMLLabelElement | null>(null);
15+
const fileId = useRef<number>(0);
16+
17+
const onChangeFiles = useCallback(
18+
(e: ChangeEvent<HTMLInputElement> | any): void => {
19+
let selectFiles: File[] = [];
20+
let tempFiles: FileFormat[] = [];
21+
22+
e.type === "drop"
23+
? (selectFiles = e.dataTransfer.files)
24+
: (selectFiles = e.target.files);
25+
26+
// 새로운 파일을 하나만 추가
27+
const file = selectFiles[0];
28+
if (file) {
29+
tempFiles = [
30+
{
31+
id: fileId.current++,
32+
content: file,
33+
},
34+
];
35+
setFiles(tempFiles);
36+
}
37+
},
38+
[]
39+
);
40+
41+
const handleLabelClick = (e: any) => {
42+
e.preventDefault();
43+
};
44+
45+
const handleDeleteFile = useCallback(
46+
(id: number): void => {
47+
setFiles(files.filter((file: FileFormat) => file.id !== id));
48+
},
49+
[files]
50+
);
51+
52+
const handleDragIn = useCallback((e: DragEvent): void => {
53+
e.preventDefault();
54+
e.stopPropagation();
55+
}, []);
56+
57+
const handleDragOut = useCallback((e: DragEvent): void => {
58+
e.preventDefault();
59+
e.stopPropagation();
60+
61+
setIsDragging(false);
62+
}, []);
63+
64+
const handleDragOver = useCallback((e: DragEvent): void => {
65+
e.preventDefault();
66+
e.stopPropagation();
67+
68+
if (e.dataTransfer!.files) {
69+
setIsDragging(true);
70+
}
71+
}, []);
72+
73+
const handleDrop = useCallback(
74+
(e: DragEvent): void => {
75+
e.preventDefault();
76+
e.stopPropagation();
77+
78+
onChangeFiles(e);
79+
setIsDragging(false);
80+
},
81+
[onChangeFiles]
82+
);
83+
84+
const initDragEvents = useCallback((): void => {
85+
if (dragRef.current !== null) {
86+
dragRef.current.addEventListener("dragenter", handleDragIn);
87+
dragRef.current.addEventListener("dragleave", handleDragOut);
88+
dragRef.current.addEventListener("dragover", handleDragOver);
89+
dragRef.current.addEventListener("drop", handleDrop);
90+
}
91+
}, [handleDragIn, handleDragOut, handleDragOver, handleDrop]);
92+
93+
const resetDragEvents = useCallback((): void => {
94+
if (dragRef.current !== null) {
95+
dragRef.current.removeEventListener("dragenter", handleDragIn);
96+
dragRef.current.removeEventListener("dragleave", handleDragOut);
97+
dragRef.current.removeEventListener("dragover", handleDragOver);
98+
dragRef.current.removeEventListener("drop", handleDrop);
99+
}
100+
}, [handleDragIn, handleDragOut, handleDragOver, handleDrop]);
101+
102+
useEffect(() => {
103+
initDragEvents();
104+
return () => resetDragEvents();
105+
}, [initDragEvents, resetDragEvents]);
106+
107+
return (
108+
<S.UploadWrapper>
109+
<div
110+
className={`${isDragging ? "UploadWrapperActive" : "UploadWrapper"}`}
111+
>
112+
<label
113+
className="UploadArea"
114+
htmlFor="fileUpload"
115+
ref={dragRef}
116+
onClick={handleLabelClick}
117+
>
118+
{files.length === 0 ? (
119+
<div className="desdiv">
120+
<img src={upload} alt="upload" />
121+
<span className="text">파일을 드래그 하여 업로드</span>
122+
</div>
123+
) : (
124+
""
125+
)}
126+
</label>
127+
</div>
128+
129+
<div className="FileContainer">
130+
{files.length > 0 &&
131+
files.map((file: FileFormat) => {
132+
const {
133+
id,
134+
content: { name },
135+
} = file;
136+
137+
return (
138+
<div className="UploadFile" key={id}>
139+
<div className="Filename">{name} </div>
140+
<div className="DeleteBtn" onClick={() => handleDeleteFile(id)}>
141+
<img src={remove} alt="remove" />
142+
</div>
143+
</div>
144+
);
145+
})}
146+
</div>
147+
<input
148+
type="file"
149+
id="fileUpload"
150+
style={{ display: "none" }}
151+
onChange={onChangeFiles} // 하나의 파일만 추가
152+
/>
153+
</S.UploadWrapper>
154+
);
155+
};
156+
157+
export default Upload;

0 commit comments

Comments
 (0)