[as] feat: useTus > handleError 수정
This commit is contained in:
@@ -1 +1 @@
|
||||
export { handleTusUpload, type TusUploadOptions } from "./lib/utils";
|
||||
export { handleTusUpload, type TusErrorResponse, type TusUploadOptions } from "./lib/utils";
|
||||
|
||||
@@ -1,15 +1,29 @@
|
||||
import { Upload } from "tus-js-client";
|
||||
import { type DetailedError, Upload } from "tus-js-client";
|
||||
|
||||
import { ENDPOINT, PROXY_HOST } from "@/shared/config";
|
||||
import { AUTH_USER_ID, CLAIM_NAME } from "@/shared/config/env";
|
||||
import { getCookie } from "@/shared/lib";
|
||||
|
||||
interface TusFieldError {
|
||||
message: string;
|
||||
field: string;
|
||||
rejectedValue: string;
|
||||
}
|
||||
|
||||
interface TusErrorResponse {
|
||||
timestamp: number[];
|
||||
message: string;
|
||||
status: number;
|
||||
code: string;
|
||||
errors: TusFieldError[];
|
||||
}
|
||||
|
||||
interface TusUploadOptions {
|
||||
metadata?: Record<string, string>;
|
||||
handleUploadStart?: (upload: Upload) => void;
|
||||
handleProgress?: (percentage: number) => void;
|
||||
handleSuccess?: (upload: Upload, atflCd: string, atflId: string) => void;
|
||||
handleError?: (error: Error) => void;
|
||||
handleError?: (error: Error, response: TusErrorResponse | null) => void;
|
||||
}
|
||||
|
||||
function handleTusUpload(file: File, options?: TusUploadOptions) {
|
||||
@@ -32,7 +46,7 @@ function handleTusUpload(file: File, options?: TusUploadOptions) {
|
||||
metadata,
|
||||
onError(error) {
|
||||
console.error("TUS upload failed:", error);
|
||||
options?.handleError?.(error);
|
||||
options?.handleError?.(error, parseTusErrorResponse(error));
|
||||
},
|
||||
onProgress(bytesUploaded, bytesTotal) {
|
||||
const percentage = (bytesUploaded / bytesTotal) * 100;
|
||||
@@ -57,5 +71,22 @@ function handleTusUpload(file: File, options?: TusUploadOptions) {
|
||||
return upload;
|
||||
}
|
||||
|
||||
function parseTusErrorResponse(error: Error | DetailedError): TusErrorResponse | null {
|
||||
if (!("originalResponse" in error)) return null;
|
||||
|
||||
const body = error.originalResponse?.getBody();
|
||||
if (!body) return null;
|
||||
|
||||
try {
|
||||
const parsed: unknown = JSON.parse(body);
|
||||
if (typeof parsed !== "object" || parsed === null) return null;
|
||||
if (typeof (parsed as TusErrorResponse).message !== "string") return null;
|
||||
|
||||
return parsed as TusErrorResponse;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export { handleTusUpload };
|
||||
export type { TusUploadOptions };
|
||||
export type { TusErrorResponse, TusUploadOptions };
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useCallback, useState } from "react";
|
||||
|
||||
import { type Upload } from "tus-js-client";
|
||||
|
||||
import { handleTusUpload } from "@/entities/tus";
|
||||
import { handleTusUpload, type TusErrorResponse } from "@/entities/tus";
|
||||
|
||||
import { useAlertStore } from "./use-alert-store";
|
||||
|
||||
@@ -15,7 +15,12 @@ interface UploadFileOptions {
|
||||
|
||||
interface UseTusOptions {
|
||||
onSuccess?: (atflCd: string, atflId: string, file: File, fileKey: string) => void;
|
||||
onError?: (error: Error, file: File, fileKey: string) => void;
|
||||
onError?: (
|
||||
error: Error,
|
||||
file: File,
|
||||
fileKey: string,
|
||||
response: TusErrorResponse | null,
|
||||
) => void;
|
||||
accept?: string;
|
||||
}
|
||||
|
||||
@@ -80,10 +85,10 @@ function useTus(options: UseTusOptions = {}): UseTusReturn {
|
||||
options.onSuccess?.(atflCd, atflId, file, fileKey);
|
||||
resolve(atflCd);
|
||||
},
|
||||
handleError: (error) => {
|
||||
handleError: (error, response) => {
|
||||
setIsUploading((prev) => ({ ...prev, [fileKey]: false }));
|
||||
alert("파일 업로드 중 오류가 발생했습니다.");
|
||||
options.onError?.(error, file, fileKey);
|
||||
alert(response?.message ?? "파일 업로드 중 오류가 발생했습니다.");
|
||||
options.onError?.(error, file, fileKey, response);
|
||||
reject(error);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -40,7 +40,6 @@ function FileAddButton({
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
variant="outline"
|
||||
disabled={disabled}
|
||||
className={cn(
|
||||
"peer-focus-visible:ring-2 peer-focus-visible:ring-ring peer-focus-visible:ring-offset-2",
|
||||
|
||||
@@ -49,7 +49,7 @@ function HangulGiangiToolbar({
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
color="white"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={isBusy}
|
||||
className={cn(
|
||||
@@ -58,7 +58,7 @@ function HangulGiangiToolbar({
|
||||
)}
|
||||
asChild
|
||||
>
|
||||
<span>
|
||||
<span className="text-[#666]">
|
||||
<FolderOpen className="!size-5" />
|
||||
열기
|
||||
</span>
|
||||
|
||||
Reference in New Issue
Block a user