Feat: 이미지 폴더 업로드 컴포넌트 구현
This commit is contained in:
parent
0557def88e
commit
5fde35a619
@ -51,11 +51,11 @@ export async function uploadImageList(projectId: number, folderId: number, membe
|
||||
.then(({ data }) => data);
|
||||
}
|
||||
|
||||
export async function uploadImageFolder(projectId: number, folderZip: File[], parentId: number, memberId: number) {
|
||||
export async function uploadImageFolder(memberId: number, projectId: number, files: File[], parentId: number = 0) {
|
||||
return api
|
||||
.post(
|
||||
`/projects/${projectId}/folders/0/images/upload`,
|
||||
{ folderZip, parentId },
|
||||
{ files, parentId },
|
||||
{
|
||||
params: { memberId },
|
||||
}
|
||||
|
@ -1,59 +1,16 @@
|
||||
import { uploadImageFolder, uploadImageList } from '@/api/imageApi';
|
||||
import useAuthStore from '@/stores/useAuthStore';
|
||||
import { useState } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import ImageFolderUploadModal from '../ImageFolderUploadModal';
|
||||
|
||||
export default function FolderUploadTest() {
|
||||
const params = useParams<{ workspaceId: string; projectId: string }>();
|
||||
const projectId = Number(params.projectId);
|
||||
const profile = useAuthStore((state) => state.profile);
|
||||
const memberId = profile?.id || 0;
|
||||
const [files, setFiles] = useState<Array<File>>([]);
|
||||
const [isUploading, setIsUploading] = useState<boolean>(false);
|
||||
|
||||
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const selectedFiles = e.target.files;
|
||||
if (selectedFiles) {
|
||||
setFiles(Array.from(selectedFiles));
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpload = async () => {
|
||||
if (!files || files.length === 0) {
|
||||
console.log('No selected files');
|
||||
return;
|
||||
}
|
||||
|
||||
setIsUploading(true);
|
||||
// uploadImageFolder(projectId, files, 0, memberId);
|
||||
uploadImageList(projectId, 0, memberId, files);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen w-full bg-blue-300">
|
||||
<h1>hello infikei</h1>
|
||||
<input
|
||||
type="file"
|
||||
id="folderInput"
|
||||
// webkitdirectory=""
|
||||
multiple
|
||||
onChange={handleFileChange}
|
||||
<div className="min-h-screen w-full">
|
||||
<ImageFolderUploadModal
|
||||
projectId={projectId}
|
||||
parentId={0}
|
||||
/>
|
||||
<button
|
||||
onClick={handleUpload}
|
||||
disabled={isUploading}
|
||||
>
|
||||
{isUploading ? '업로드하는 중...' : '폴더 업로드'}
|
||||
</button>
|
||||
<div>
|
||||
{files.length > 0 && (
|
||||
<ul>
|
||||
{files.map((file, index) => (
|
||||
<li key={index}>{file.webkitRelativePath}</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -0,0 +1,88 @@
|
||||
import { useState } from 'react';
|
||||
import { Button } from '../ui/button';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { uploadImageFolder } from '@/api/imageApi';
|
||||
import useAuthStore from '@/stores/useAuthStore';
|
||||
|
||||
export default function ImageFolderUploadForm({ projectId, parentId }: { projectId: number; parentId: number }) {
|
||||
const profile = useAuthStore((state) => state.profile);
|
||||
const memberId = profile?.id || 0;
|
||||
|
||||
const [files, setFiles] = useState<File[]>([]);
|
||||
const [isDragging, setIsDragging] = useState<boolean>(false);
|
||||
const [isUploading, setIsUploading] = useState<boolean>(false);
|
||||
|
||||
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const newFiles = event.target.files;
|
||||
|
||||
if (newFiles) {
|
||||
setFiles((prevFiles) => [...prevFiles, ...Array.from(newFiles)]);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDragOver = (event: React.DragEvent<HTMLDivElement>) => {
|
||||
event.preventDefault();
|
||||
setIsDragging(true);
|
||||
};
|
||||
|
||||
const handleDragLeave = (event: React.DragEvent<HTMLDivElement>) => {
|
||||
event.preventDefault();
|
||||
setIsDragging(false);
|
||||
};
|
||||
|
||||
const handleDrop = () => {
|
||||
setIsDragging(false);
|
||||
};
|
||||
|
||||
const handleClick = async () => {
|
||||
setIsUploading(true);
|
||||
await uploadImageFolder(memberId, projectId, files, parentId);
|
||||
setFiles([]);
|
||||
setIsUploading(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-5">
|
||||
<div
|
||||
className={cn(
|
||||
'relative flex h-[200px] w-full cursor-pointer items-center justify-center rounded-lg border-2 text-center',
|
||||
isDragging ? 'border-solid border-primary bg-blue-200' : 'border-dashed border-gray-500 bg-gray-100'
|
||||
)}
|
||||
>
|
||||
<input
|
||||
type="file"
|
||||
webkitdirectory=""
|
||||
multiple
|
||||
className="absolute inset-0 h-full w-full cursor-pointer opacity-0"
|
||||
onChange={handleChange}
|
||||
onDragOver={handleDragOver}
|
||||
onDragLeave={handleDragLeave}
|
||||
onDrop={handleDrop}
|
||||
/>
|
||||
{isDragging ? (
|
||||
<p className="text-primary">드래그한 파일을 여기에 놓으세요</p>
|
||||
) : (
|
||||
<p className="text-gray-500">
|
||||
파일을 업로드하려면 여기를 클릭하거나
|
||||
<br />
|
||||
파일을 드래그하여 여기에 놓으세요
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
{files.length > 0 && (
|
||||
<ul>
|
||||
{files.map((file, index) => (
|
||||
<li key={index}>{file.webkitRelativePath}</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
<Button
|
||||
onClick={handleClick}
|
||||
variant="outlinePrimary"
|
||||
disabled={files.length === 0 || isDragging || isUploading}
|
||||
>
|
||||
{isUploading ? `업로드 중... 0%` : '업로드'}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
34
frontend/src/components/ImageFolderUploadModal/index.tsx
Normal file
34
frontend/src/components/ImageFolderUploadModal/index.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
import React from 'react';
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTrigger } from '../ui/dialogCustom';
|
||||
import { Plus } from 'lucide-react';
|
||||
import ImageFolderUploadForm from './ImageFolderUploadForm';
|
||||
|
||||
export default function WorkSpaceCreateModal({ projectId, parentId = 0 }: { projectId: number; parentId: number }) {
|
||||
const [isOpen, setIsOpen] = React.useState(false);
|
||||
|
||||
const handleOpen = () => setIsOpen(true);
|
||||
// const handleClose = () => setIsOpen(false);
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={isOpen}
|
||||
onOpenChange={setIsOpen}
|
||||
>
|
||||
<DialogTrigger asChild>
|
||||
<button
|
||||
className="flex items-center justify-center p-2"
|
||||
onClick={handleOpen}
|
||||
>
|
||||
<Plus size={20} />
|
||||
</button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-w-2xl">
|
||||
<DialogHeader title="폴더 업로드" />
|
||||
<ImageFolderUploadForm
|
||||
projectId={projectId}
|
||||
parentId={parentId}
|
||||
/>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
@ -261,3 +261,10 @@ export interface ErrorResponse {
|
||||
message: string;
|
||||
isSuccess: boolean;
|
||||
}
|
||||
|
||||
export interface ImageFolderRequest {
|
||||
memberId: number;
|
||||
projectId: number;
|
||||
parentId: number;
|
||||
files: File[];
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user