refactor: tus 업로드 커스텀 훅 생성
This commit is contained in:
@@ -1,61 +0,0 @@
|
||||
import { Upload, type HttpResponse } from "tus-js-client";
|
||||
import { getCookie, setCookie } from "@/shared/lib";
|
||||
import { AUTH_USER_ID, CLAIM_NAME, ENDPOINT } from "@/shared/config";
|
||||
|
||||
type UploadOptions = {
|
||||
handleUploadStart?: (upload: Upload) => void;
|
||||
handleProgress?: (percentage: string) => void;
|
||||
handleSuccess?: (upload: Upload) => void;
|
||||
handleResponse?: (res: HttpResponse) => void;
|
||||
};
|
||||
|
||||
export const handleUpload = (files: FileList, options?: UploadOptions) => {
|
||||
let metadata = {};
|
||||
|
||||
const file = files.item(0);
|
||||
if (!file) return;
|
||||
metadata = {
|
||||
filename: file.name,
|
||||
filetype: file.type,
|
||||
};
|
||||
|
||||
const atflCd = getCookie("atfl-cd-key");
|
||||
if (atflCd) {
|
||||
metadata = {
|
||||
...metadata,
|
||||
atflCd,
|
||||
};
|
||||
}
|
||||
|
||||
const upload = new Upload(file, {
|
||||
endpoint: `${ENDPOINT.ATTACH_SERVICE.TUS_UPLOAD}`,
|
||||
chunkSize: 10 * 1024 * 1024,
|
||||
headers: {
|
||||
[CLAIM_NAME]: getCookie(CLAIM_NAME) ?? "",
|
||||
[AUTH_USER_ID]: getCookie(AUTH_USER_ID) ?? "",
|
||||
},
|
||||
metadata,
|
||||
onError(error) {
|
||||
console.error(`Failed because: ${error}`);
|
||||
},
|
||||
onProgress(bytesUploaded, bytesTotal) {
|
||||
const percentage = ((bytesUploaded / bytesTotal) * 100).toFixed(2);
|
||||
options?.handleProgress?.(percentage);
|
||||
},
|
||||
onAfterResponse(req, res) {
|
||||
const fileInfo = res.getHeader("X-File-Info");
|
||||
if (fileInfo === undefined || fileInfo === null) return;
|
||||
|
||||
setCookie("atfl-cd-key", JSON.parse(fileInfo)?.atflCd ?? "");
|
||||
options?.handleResponse?.(res);
|
||||
},
|
||||
onSuccess() {
|
||||
options?.handleSuccess?.(upload);
|
||||
},
|
||||
});
|
||||
|
||||
upload.start();
|
||||
options?.handleUploadStart?.(upload);
|
||||
|
||||
console.log("upload start >>>>>", upload);
|
||||
};
|
||||
@@ -4,7 +4,7 @@ import Image from "next/image";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { UseFormReturn } from "react-hook-form";
|
||||
import type { HttpResponse, Upload } from "tus-js-client";
|
||||
import type { HttpResponse } from "tus-js-client";
|
||||
import {
|
||||
FileUploader,
|
||||
Input,
|
||||
@@ -22,10 +22,9 @@ import { FormWrapper } from "@/widgets/form-wrapper";
|
||||
import { CodeSelect } from "@/entities/code";
|
||||
import { AttachmentApi } from "@/entities/attachment";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import { setCookie } from "@/shared/lib/cookie";
|
||||
import { useTus } from "@/shared/lib/use-tus";
|
||||
import { FormControl, FormField, FormItem } from "@/shared/ui/form";
|
||||
import type { ImageFormData } from "../model/image-interface";
|
||||
import { handleUpload } from "../lib/utils";
|
||||
|
||||
type ImageFormProps = {
|
||||
form: UseFormReturn<ImageFormData>;
|
||||
@@ -38,9 +37,13 @@ function ImageForm({ form, imgSn, ...props }: ImageFormProps) {
|
||||
const atflYn = form.watch("atflYn");
|
||||
const atflCd = form.watch("atflCd");
|
||||
|
||||
const {
|
||||
file: uploadFile,
|
||||
response: uploadResponse,
|
||||
progress,
|
||||
setFile,
|
||||
} = useTus();
|
||||
const [imageUrl, setImageUrl] = useState("");
|
||||
const [upload, setUpload] = useState<Upload | null>(null);
|
||||
const [progress, setProgress] = useState(0);
|
||||
|
||||
const { data: attachmentData } = useQuery({
|
||||
queryKey: [ENDPOINT.ATTACH_SERVICE.ATTACHMENTS, atflCd],
|
||||
@@ -49,10 +52,6 @@ function ImageForm({ form, imgSn, ...props }: ImageFormProps) {
|
||||
enabled: !!atflCd,
|
||||
});
|
||||
|
||||
const handleProgress = (percentage: string) => {
|
||||
setProgress(Number(percentage));
|
||||
};
|
||||
|
||||
const handleUploadResponse = async (res: HttpResponse) => {
|
||||
const fileInfo = res.getHeader("X-File-Info");
|
||||
if (fileInfo === undefined || fileInfo === null) return;
|
||||
@@ -64,6 +63,11 @@ function ImageForm({ form, imgSn, ...props }: ImageFormProps) {
|
||||
await AttachmentApi.deleteAttachmentByAtflCd(attachmentData.atflCd);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!uploadResponse) return;
|
||||
handleUploadResponse(uploadResponse);
|
||||
}, [uploadResponse]);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
setImageUrl(
|
||||
@@ -197,13 +201,7 @@ function ImageForm({ form, imgSn, ...props }: ImageFormProps) {
|
||||
onUpload={(e) => {
|
||||
const files = e.target.files;
|
||||
if (!files) return;
|
||||
setCookie("atfl-cd-key", "");
|
||||
handleUpload(files, {
|
||||
handleUploadStart: setUpload,
|
||||
handleProgress,
|
||||
handleSuccess: setUpload,
|
||||
handleResponse: handleUploadResponse,
|
||||
});
|
||||
setFile(files[0] ?? null);
|
||||
}}
|
||||
customPreview={
|
||||
<>
|
||||
@@ -220,7 +218,7 @@ function ImageForm({ form, imgSn, ...props }: ImageFormProps) {
|
||||
)}
|
||||
</div>
|
||||
<p className="absolute bottom-3 left-0 z-10 p-2 text-base leading-none">
|
||||
{(upload?.file as File)?.name}
|
||||
{uploadFile?.name}
|
||||
</p>
|
||||
<Progress
|
||||
value={progress}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { type HttpResponse, Upload } from "tus-js-client";
|
||||
import { AUTH_USER_ID, CLAIM_NAME, ENDPOINT } from "../config";
|
||||
import { useAttachmentStore } from "./use-attachment-store";
|
||||
import { getCookie } from "./cookie";
|
||||
|
||||
export const useTus = () => {
|
||||
const { attachmentFileCode, setAttachmentFileCode } = useAttachmentStore(
|
||||
(state) => state,
|
||||
);
|
||||
|
||||
const [file, setFile] = useState<File | null>(null);
|
||||
const [upload, setUpload] = useState<Upload | null>(null);
|
||||
const [response, setResponse] = useState<HttpResponse | null>(null);
|
||||
const [progress, setProgress] = useState<number>(0);
|
||||
|
||||
const metadata = {
|
||||
filename: file?.name ?? "",
|
||||
filetype: file?.type ?? "",
|
||||
atflCd: attachmentFileCode,
|
||||
};
|
||||
|
||||
const createUpload = () => {
|
||||
return new Upload(file!, {
|
||||
endpoint: `${ENDPOINT.ATTACH_SERVICE.TUS_UPLOAD}`,
|
||||
chunkSize: 10 * 1024 * 1024,
|
||||
headers: {
|
||||
[CLAIM_NAME]: getCookie(CLAIM_NAME) ?? "",
|
||||
[AUTH_USER_ID]: getCookie(AUTH_USER_ID) ?? "",
|
||||
},
|
||||
metadata,
|
||||
onError(error) {
|
||||
throw new Error(`Failed because: ${error}`);
|
||||
},
|
||||
onProgress(bytesUploaded, bytesTotal) {
|
||||
const percentage = ((bytesUploaded / bytesTotal) * 100).toFixed(2);
|
||||
setProgress(Number(percentage));
|
||||
},
|
||||
onAfterResponse(req, res) {
|
||||
const fileInfo = res.getHeader("X-File-Info");
|
||||
if (fileInfo === undefined || fileInfo === null) return;
|
||||
|
||||
setAttachmentFileCode(JSON.parse(fileInfo)?.atflCd ?? "");
|
||||
setResponse(res);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!file) return;
|
||||
|
||||
const upload = createUpload();
|
||||
upload.start();
|
||||
setUpload(upload);
|
||||
}, [file]);
|
||||
|
||||
return {
|
||||
file,
|
||||
upload,
|
||||
response,
|
||||
progress,
|
||||
setFile,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user