135 lines
4.2 KiB
TypeScript
135 lines
4.2 KiB
TypeScript
"use client";
|
|
|
|
import React from "react";
|
|
import { AutoRegisteringComponentRenderer } from "../../AutoRegisteringComponentRenderer";
|
|
import { V2MediaDefinition } from "./index";
|
|
import { V2Media } from "@/components/v2/V2Media";
|
|
|
|
/**
|
|
* V2Media 렌더러
|
|
* 파일, 이미지, 비디오, 오디오 등 다양한 미디어 타입을 지원
|
|
* 자동 등록 시스템을 사용하여 컴포넌트를 레지스트리에 등록
|
|
*/
|
|
export class V2MediaRenderer extends AutoRegisteringComponentRenderer {
|
|
static componentDefinition = V2MediaDefinition;
|
|
|
|
render(): React.ReactElement {
|
|
const { component, formData, onFormDataChange, isDesignMode, isSelected, isInteractive, ...restProps } = this.props;
|
|
|
|
// 컴포넌트 설정 추출
|
|
const config = component.componentConfig || component.config || {};
|
|
const columnName = component.columnName;
|
|
const tableName = component.tableName || this.props.tableName;
|
|
|
|
// formData에서 현재 값 가져오기
|
|
const rawValue = formData?.[columnName] ?? component.value ?? "";
|
|
|
|
// objid를 미리보기 URL로 변환하는 함수 (number/string 모두 처리)
|
|
const convertToPreviewUrl = (val: any): string => {
|
|
if (val === null || val === undefined || val === "") return "";
|
|
|
|
// number면 string으로 변환
|
|
const strVal = String(val);
|
|
|
|
// 이미 URL 형태면 그대로 반환
|
|
if (strVal.startsWith("/") || strVal.startsWith("http")) return strVal;
|
|
|
|
// 숫자로만 이루어진 문자열이면 objid로 간주하고 미리보기 URL 생성
|
|
if (/^\d+$/.test(strVal)) {
|
|
return `/api/files/preview/${strVal}`;
|
|
}
|
|
|
|
return strVal;
|
|
};
|
|
|
|
// 배열 또는 단일 값 처리
|
|
const currentValue = Array.isArray(rawValue)
|
|
? rawValue.map(convertToPreviewUrl)
|
|
: convertToPreviewUrl(rawValue);
|
|
|
|
console.log("[V2Media] rawValue:", rawValue, "-> currentValue:", currentValue);
|
|
|
|
// 값 변경 핸들러
|
|
const handleChange = (value: any) => {
|
|
if (isInteractive && onFormDataChange && columnName) {
|
|
onFormDataChange(columnName, value);
|
|
}
|
|
};
|
|
|
|
// V1 file-upload, image-widget에서 넘어온 설정 매핑
|
|
const mediaType = config.mediaType || config.type || this.getMediaTypeFromWebType(component.webType);
|
|
|
|
// maxSize: MB → bytes 변환 (V1은 bytes, V2는 MB 단위 사용)
|
|
const maxSizeBytes = config.maxSize
|
|
? (config.maxSize > 1000 ? config.maxSize : config.maxSize * 1024 * 1024)
|
|
: 10 * 1024 * 1024; // 기본 10MB
|
|
|
|
return (
|
|
<V2Media
|
|
id={component.id}
|
|
label={component.label}
|
|
required={component.required}
|
|
readonly={config.readonly || component.readonly}
|
|
disabled={config.disabled || component.disabled}
|
|
value={currentValue}
|
|
onChange={handleChange}
|
|
config={{
|
|
type: mediaType,
|
|
multiple: config.multiple ?? false,
|
|
preview: config.preview ?? true,
|
|
maxSize: maxSizeBytes,
|
|
accept: config.accept || this.getDefaultAccept(mediaType),
|
|
uploadEndpoint: config.uploadEndpoint || "/files/upload",
|
|
}}
|
|
style={component.style}
|
|
size={component.size}
|
|
formData={formData}
|
|
columnName={columnName}
|
|
tableName={tableName}
|
|
{...restProps}
|
|
/>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* webType에서 미디어 타입 추출
|
|
*/
|
|
private getMediaTypeFromWebType(webType?: string): "file" | "image" | "video" | "audio" {
|
|
switch (webType) {
|
|
case "image":
|
|
return "image";
|
|
case "video":
|
|
return "video";
|
|
case "audio":
|
|
return "audio";
|
|
case "file":
|
|
default:
|
|
return "file";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 미디어 타입에 따른 기본 accept 값
|
|
*/
|
|
private getDefaultAccept(mediaType: string): string {
|
|
switch (mediaType) {
|
|
case "image":
|
|
return "image/*";
|
|
case "video":
|
|
return "video/*";
|
|
case "audio":
|
|
return "audio/*";
|
|
default:
|
|
return "*/*";
|
|
}
|
|
}
|
|
}
|
|
|
|
// 자동 등록 실행
|
|
V2MediaRenderer.registerSelf();
|
|
|
|
// Hot Reload 지원 (개발 모드)
|
|
if (process.env.NODE_ENV === "development") {
|
|
V2MediaRenderer.enableHotReload();
|
|
}
|