diff --git a/package.json b/package.json index ca249cd..413fd3d 100644 --- a/package.json +++ b/package.json @@ -3,13 +3,17 @@ "version": "0.1.0", "private": true, "dependencies": { + "@ant-design/icons": "^5.6.1", "@hookform/resolvers": "^3.2.0", "@testing-library/jest-dom": "^5.14.1", "@testing-library/react": "^13.0.0", "@testing-library/user-event": "^13.2.1", + "antd": "^5.26.1", "axios": "^1.4.0", "date-fns": "^2.30.0", + "dayjs": "^1.11.13", "dotenv-cli": "^7.4.2", + "framer-motion": "^12.19.1", "i18next": "^23.15.1", "lodash": "^4.17.21", "react": "^18.2.0", diff --git a/src/components/modal/MenuBannerDetailModal.js b/src/components/modal/MenuBannerDetailModal.js new file mode 100644 index 0000000..8b8e5c6 --- /dev/null +++ b/src/components/modal/MenuBannerDetailModal.js @@ -0,0 +1,611 @@ +import React, { useState, useEffect, Fragment } from 'react'; +import styled, { css, keyframes } from 'styled-components'; + +import { + Title, + SelectInput, + BtnWrapper, + TextInput, + Label, + InputLabel, + Textarea, + SearchBarAlert, + ButtonGroupWrapper, +} from '../../styles/Components'; +import Button from '../common/button/Button'; +import Modal from '../common/modal/Modal'; +import { EventIsItem, EventModify, MenuBannerModify } from '../../apis'; + +import { authList } from '../../store/authList'; +import { useRecoilValue } from 'recoil'; +import { useTranslation } from 'react-i18next'; +import { authType, benItems, commonStatus, currencyItemCode } from '../../assets/data'; +import { + DetailInputItem, DetailInputRow, + DetailModalWrapper, RegistGroup, DetailRegistInfo, DetailState, FormRowGroup, FormLabel, FormInput, +} from '../../styles/ModuleComponents'; +import { convertKTC, combineDateTime, timeDiffMinute, convertKTCDate } from '../../utils'; +import DateTimeInput from '../common/input/DateTimeInput'; +import { useLoading } from '../../context/LoadingProvider'; +import { useAlert } from '../../context/AlertProvider'; +import { alertTypes, battleEventStatusType, languageNames } from '../../assets/data/types'; +import { Tabs, Image as AntImage, Spin } from 'antd'; +import { TYPE_MODIFY, TYPE_REGISTRY } from '../../assets/data/adminConstants'; +import { AntButton, DateTimeRangePicker, DetailLayout, SingleTimePicker } from '../common'; +import AnimatedTabs from '../common/control/AnimatedTabs'; + +function renderImageContent(imageData) { + if (!imageData) { + return 이미지가 없습니다; + } + + return ( + <> + + + } + // preview={{ + // mask: '미리보기', + // maskClassName: 'custom-mask', + // }} + fallback="data:image/png;base64,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" + /> + + {imageData.content && + + + {imageData.content} + + + } + + ); +} + +const MenuBannerDetailModal = ({ detailView, handleDetailView, content, setDetailData }) => { + const userInfo = useRecoilValue(authList); + const { t } = useTranslation(); + const token = sessionStorage.getItem('token'); + const {withLoading} = useLoading(); + const {showModal, showToast} = useAlert(); + + const id = content && content.id; + const updateAuth = userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === authType.menuBannerUpdate); + + const [time, setTime] = useState({ + start_hour: '00', + start_min: '00', + end_hour: '00', + end_min: '00', + }); //시간 정보 + + const [resultData, setResultData] = useState(initData); + const [activeLanguage, setActiveLanguage] = useState('KO'); + // 이미지 프리로드를 위한 상태 + const [allImagesLoaded, setAllImagesLoaded] = useState(false); + const [showTabContent, setShowTabContent] = useState(false); + const [loadedImages, setLoadedImages] = useState([]); + const [totalImageCount, setTotalImageCount] = useState(0); + + const [tabItems, setTabItems] = useState([]); + + useEffect(() => { + if(content){ + console.log(content); + const start_dt_KTC = convertKTCDate(content.start_dt); + const end_dt_KTC = convertKTCDate(content.end_dt); + + setResultData({ + id: content.id, + title: content.title, + start_dt: start_dt_KTC, + end_dt: end_dt_KTC, + status: content.status, + order_id: content.order_id, + is_link: content.is_link, + image_list: content.image_list, + }); + + setTime({ ...time, + start_hour: String(start_dt_KTC.getHours()).padStart(2, '0'), + start_min: String(start_dt_KTC.getMinutes()).padStart(2, '0'), + end_hour: String(end_dt_KTC.getHours()).padStart(2, '0'), + end_min: String(end_dt_KTC.getMinutes()).padStart(2, '0') + }); + } + + }, [content]); + + useEffect(() => { + if (content && content.image_list) { + // 초기화 + setAllImagesLoaded(false); + setShowTabContent(false); + setLoadedImages([]); + + // 이미지 개수 설정 + setTotalImageCount(content.image_list ? content.image_list.length : 0); + + // 첫 번째 언어를 활성 언어로 설정 + if (content.image_list && content.image_list.length > 0) { + setActiveLanguage(content.image_list[0].language); + } + + // 동적으로 탭 아이템 생성 + const newTabItems = content.image_list ? content.image_list.map(imageData => ({ + key: imageData.language, + label: languageNames[imageData.language] || imageData.language, + children: ( + + {renderImageContent(imageData)} + + ) + })) : []; + + setTabItems(newTabItems); + + // 모든 이미지 프리로딩 시작 + setTimeout(() => { + preloadAllImages(); + }, 100); + } + }, [content]); + + const preloadAllImages = () => { + if (!content || !content.image_list || content.image_list.length === 0) { + // 이미지가 없는 경우 바로 로딩 완료 처리 + // console.log('이미지가 없습니다. 로딩 완료 처리합니다.'); + setAllImagesLoaded(true); + setShowTabContent(true); + return; + } + + // console.log(`총 ${content.image_list.length}개의 이미지 로딩을 시작합니다.`); + + // 이미지 개수가 0이면 로딩 완료 처리 + if (content.image_list.length === 0) { + setAllImagesLoaded(true); + setShowTabContent(true); + return; + } + + let loadedCount = 0; + + // 이미지 로드 완료 이벤트 핸들러 + const handleImageLoad = (url) => { + loadedCount++; + // console.log(`이미지 로드 완료 (${loadedCount}/${content.image_list.length}): ${url}`); + + // 모든 이미지가 로드되었는지 확인 + if (loadedCount >= content.image_list.length) { + // console.log('모든 이미지 로딩 완료!'); + setAllImagesLoaded(true); + setShowTabContent(true); + } + }; + + // 각 이미지에 대해 프리로드 객체 생성 + content.image_list.forEach(img => { + if (img.title) { + // console.log(`이미지 로딩 시작: ${img.title}`); + const image = new Image(); + image.onload = () => handleImageLoad(img.title); + image.onerror = () => { + console.log(`이미지 로드 실패: ${img.title}`); + handleImageLoad(img.title); // 오류 시에도 카운트 + }; + image.src = img.title; // src 속성은 onload/onerror 핸들러 설정 후에 설정 + } else { + // console.log('이미지 URL이 없습니다.'); + handleImageLoad('empty'); // URL이 없는 경우에도 카운트 + } + }); + + // 안전장치: 5초 후에도 로딩이 완료되지 않으면 강제로 완료 처리 + setTimeout(() => { + if (!allImagesLoaded) { + // console.log('시간 초과로 로딩 강제 완료'); + setAllImagesLoaded(true); + setShowTabContent(true); + } + }, 5000); + }; + + // 날짜 처리 + // const handleDateChange = (data, type) => { + // const date = new Date(data); + // setResultData({ + // ...resultData, + // [`${type}_dt`]: combineDateTime(date, time[`${type}_hour`], time[`${type}_min`]), + // }); + // }; + + // 시간 처리 + const handleTimeChange = (e, type) => { + const { id, value } = e.target; + const newTime = { ...time, [`${type}_${id}`]: value }; + setTime(newTime); + + const date = resultData[`${type}_dt`] ? new Date(resultData[`${type}_dt`]) : new Date(); + + setResultData({ + ...resultData, + [`${type}_dt`]: combineDateTime(date, newTime[`${type}_hour`], newTime[`${type}_min`]), + }); + }; + + const handleDateChange = { + start: (date) => { + setResultData(prev => ({ ...prev, start_dt: date })); + }, + end: (date) => { + setResultData(prev => ({ ...prev, end_dt: date })); + } + }; + + // 확인 버튼 후 다 초기화 + const handleReset = () => { + }; + + const checkCondition = () => { + return ( + (resultData.start_dt.length !== 0) && + (resultData.end_dt.length !== 0) && + resultData.title !== '' && + resultData.order_id !== '' + ); + }; + + // 탭 변경 핸들러 + const handleTabChange = (key) => { + setActiveLanguage(key); + }; + + const handleSubmit = async (type, param = null) => { + switch (type) { + case "submit": + if (!checkCondition()) return; + + showModal('MENU_BANNER_UPDATE_SAVE', { + type: alertTypes.confirm, + onConfirm: () => handleSubmit('updateConfirm') + }); + break; + case "updateConfirm": + withLoading( async () => { + return await MenuBannerModify(token, id, resultData); + }).catch(error => { + showToast('API_FAIL', {type: alertTypes.error}); + }).finally(() => { + showToast('UPDATE_COMPLETED', {type: alertTypes.success}); + handleDetailView(); + }); + break; + } + } + + const detailState = (status) => { + switch (status) { + case commonStatus.wait: + return 대기; + case commonStatus.running: + return 진행중; + case commonStatus.finish: + return 만료; + case commonStatus.fail: + return 실패; + case commonStatus.delete: + return 삭제; + default: + return null; + } + }; + + //true 수정불가, false 수정가능 + const isView = (fieldName) => { + if (!updateAuth) return false; + + if (fieldName === 'editButton') { + // updateAuth가 없거나 FINISH 상태면 수정 버튼 숨김 (false 반환) + return !updateAuth || content?.status === commonStatus.finish; + } + + switch (content?.status) { + case commonStatus.running: + // RUNNING 상태일 때는 end_dt와 order_id만 수정 가능 + return fieldName !== 'date' && fieldName !== 'order_id'; + case commonStatus.wait: + return true; + default: + return false; + } + } + + const itemGroups = [ + { + items: [ + { + row: 0, + col: 0, + colSpan: 2, + type: 'text', + key: 'title', + label: '제목', + disabled: !isView('title'), + width: '250px', + }, + { + row: 0, + col: 2, + colSpan: 2, + type: 'number', + key: 'order_id', + label: '순서', + disabled: !isView('order_id'), + width: '100px', + min: 0, + }, + { + row: 1, + col: 0, + colSpan: 2, + type: 'status', + key: 'status', + label: '상태', + value: resultData.status, + }, + { + row: 2, + col: 0, + colSpan: 2, + type: 'dateRange', + key: 'dateRange', + keys: {start: 'start_dt', end: 'end_dt'}, + label: '기간', + disabled: !isView('date'), + format: 'YYYY-MM-DD HH:mm' + }, + ] + } + ]; + + return ( + <> + + 배너 상세 정보 + + {/**/} + {/* {content &&*/} + {/* */} + {/* */} + {/* */} + {/* 제목*/} + {/* setResultData({ ...resultData, title: e.target.value })}*/} + {/* width="300px"*/} + {/* />*/} + {/* */} + {/* */} + {/* 순서*/} + {/* setResultData({ ...resultData, order_id: e.target.value })}*/} + {/* width="200px"*/} + {/* />*/} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* 상태*/} + {/*
{detailState(content.status)}
*/} + {/*
*/} + {/*
*/} + {/* {content.image_list && content.image_list.length > 0 && (*/} + {/* */} + {/* */} + {/* {!showTabContent ? (*/} + {/* */} + {/* */} + {/* */} + {/* ) : (*/} + {/* */} + {/* */} + {/* */} + {/* )}*/} + + {/* */} + {/* */} + {/* )}*/} + + {/*
*/} + {/* }*/} + {/*
*/} + + { + handleDetailView(); + handleReset(); + setDetailData(''); + }} + /> + {!isView('editButton') && ( + handleSubmit('submit')} + /> + )} + +
+ + ); +}; + +export default MenuBannerDetailModal; + +const initData = { + title: '', + is_link: false, + start_dt: '', + end_dt: '', + image_list: [ + { language: 'KO', content: '', title: '' }, + { language: 'EN', content: '', title: '' }, + { language: 'JA', content: '', title: '' }, + ] +} + +const StyledTabs = styled(Tabs)` + margin-top: 20px; + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + + .ant-tabs-nav { + margin-bottom: 16px; + width: 80%; + } + + .ant-tabs-nav-wrap { + justify-content: center; + } + + .ant-tabs-tab { + padding: 8px 16px; + font-size: 14px; + font-weight: 500; + transition: all 0.3s; + } + + .ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn { + color: #1890ff; + font-weight: 600; + } + + .ant-tabs-ink-bar { + background-color: #1890ff; + } + + .ant-tabs-content-holder { + width: 100%; + } +`; + +const ImageContainer = styled.div` + padding: 16px; + display: flex; + flex-direction: column; + align-items: center; + gap: 16px; + width: 100%; + max-width: 700px; + margin: 0 auto; +`; + +const ImageWrapper = styled.div` + position: relative; + border-radius: 8px; + overflow: hidden; + border: 1px solid #f0f0f0; + width: 100%; + text-align: center; +`; + +const ImageUrlInfo = styled.div` + margin-top: 16px; + padding: 12px; + background-color: #f5f5f5; + border-radius: 6px; + font-size: 14px; + word-break: break-all; + width: 100%; +`; + +const UrlLink = styled.a` + color: #1890ff; + text-decoration: underline; + cursor: pointer; + &:hover { + opacity: 0.8; + } +`; + +const NoImagePlaceholder = styled.div` + width: 100%; + height: 200px; + display: flex; + align-items: center; + justify-content: center; + background-color: #f0f2f5; + color: #8c8c8c; + border-radius: 8px; +`; + +// 로딩 인디케이터를 위한 컨테이너 +const LoadingContainer = styled.div` + display: flex; + justify-content: center; + align-items: center; + height: 300px; + width: 100%; +`; + +// 컨텐츠 래퍼 - 로딩 상태에 따라 가시성 설정 +const ContentWrapper = styled.div` + width: 100%; + opacity: ${props => props.$isLoaded ? 1 : 0}; + transition: opacity 0.3s ease-in-out; + height: ${props => props.$isLoaded ? 'auto' : '0'}; + overflow: hidden; +`; + + diff --git a/src/components/modal/MenuBannerModal.js b/src/components/modal/MenuBannerModal.js deleted file mode 100644 index 8bf43bf..0000000 --- a/src/components/modal/MenuBannerModal.js +++ /dev/null @@ -1,473 +0,0 @@ -import React, { useState, Fragment, useEffect } from 'react'; -import { useTranslation } from 'react-i18next'; -import Button from '../common/button/Button'; -import Loading from '../common/Loading'; - -import { - Title, - BtnWrapper, - SearchBarAlert, SelectInput, -} from '../../styles/Components'; - -import { - FormInput, - FormLabel, - MessageWrapper, - FormRowGroup, - FormStatusBar, - FormStatusLabel, - FormStatusWarning, - FormButtonContainer, -} from '../../styles/ModuleComponents'; -import { modalTypes } from '../../assets/data'; -import { DynamicModal, Modal, SingleDatePicker, SingleTimePicker } from '../common'; -import { NONE, TYPE_MODIFY, TYPE_REGISTRY } from '../../assets/data/adminConstants'; -import { useModal } from '../../hooks/hook'; -import { convertKTCDate } from '../../utils'; -import { - battleEventHotTime, - battleEventRoundCount, - battleEventStatus, - battleRepeatType, -} from '../../assets/data/options'; -import { BattleEventModify, BattleEventSingleRegist } from '../../apis/Battle'; -import { battleEventStatusType } from '../../assets/data/types'; -import { isValidDayRange } from '../../utils/date'; - -const MenuBannerModal = ({ modalType, detailView, handleDetailView, content, setDetailData, configData, rewardData }) => { - const { t } = useTranslation(); - const token = sessionStorage.getItem('token'); - - const [loading, setLoading] = useState(false); // 로딩 창 - const { - modalState, - handleModalView, - handleModalClose - } = useModal({ - cancel: 'hidden', - registConfirm: 'hidden', - registComplete: 'hidden' - }); - - const [isNullValue, setIsNullValue] = useState(false); // 데이터 값 체크 - const [alertMsg, setAlertMsg] = useState(''); - const [resultData, setResultData] = useState(initData); //데이터 정보 - - useEffect(() => { - if(modalType === TYPE_MODIFY && content && Object.keys(content).length > 0){ - setResultData({ - group_id: content.group_id, - event_id: content.event_id, - event_name: content.event_name, - repeat_type: content.repeat_type, - config_id: content.config_id, - reward_group_id: content.reward_group_id, - round_count: content.round_count, - hot_time: content.hot_time, - round_time: content.round_time, - status: content.status, - event_start_dt: convertKTCDate(content.event_start_dt), - event_end_dt: content.event_end_dt, - event_operation_time: content.event_operation_time, - }); - } - }, [modalType, content]); - - useEffect(() => { - if(modalType === TYPE_REGISTRY && configData?.length > 0){ - setResultData(prev => ({ - ...prev, - round_count: configData[0].default_round_count - })); - } - }, [modalType, configData]); - - useEffect(() => { - if (checkCondition()) { - setIsNullValue(false); - } else { - setIsNullValue(true); - } - }, [resultData]); - - // 시작 날짜 변경 핸들러 - const handleStartDateChange = (date) => { - if (!date) return; - - const newDate = new Date(date); - - if(resultData.repeat_type !== NONE && resultData.event_end_dt){ - const endDate = new Date(resultData.event_end_dt); - const startDay = new Date(newDate.getFullYear(), newDate.getMonth(), newDate.getDate()); - const endDay = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate()); - - if (endDay <= startDay) { - setAlertMsg(t('DATE_START_DIFF_END_WARNING')); - return; - } - } - - setResultData(prev => ({ - ...prev, - event_start_dt: newDate - })); - }; - - // 시작 시간 변경 핸들러 - const handleStartTimeChange = (time) => { - if (!time) return; - - const newDateTime = resultData.event_start_dt - ? new Date(resultData.event_start_dt) - : new Date(); - - newDateTime.setHours( - time.getHours(), - time.getMinutes(), - 0, - 0 - ); - - setResultData(prev => ({ - ...prev, - event_start_dt: newDateTime - })); - }; - - // 종료 날짜 변경 핸들러 - const handleEndDateChange = (date) => { - if (!date || !resultData.event_start_dt) return; - - const startDate = new Date(resultData.event_start_dt); - const endDate = new Date(date); - - // 일자만 비교하기 위해 년/월/일만 추출 - const startDay = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate()); - const endDay = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate()); - - if (endDay <= startDay) { - setAlertMsg(t('DATE_START_DIFF_END_WARNING')); - return; - } - - setResultData(prev => ({ - ...prev, - event_end_dt: endDate - })); - }; - - const handleConfigChange = (e) => { - const config = configData.find(data => String(data.id) === String(e.target.value)); - if (config) { - setResultData({ - ...resultData, - config_id: config.id, - round_time: config.round_time - }); - } else { - console.warn('Config not found for value:', e.target.value); - } - } - - const handleReset = () => { - setDetailData({}); - setResultData(initData); - handleDetailView(); - } - - const handleSubmit = async (type, param = null) => { - switch (type) { - case "submit": - if (!checkCondition()) return; - - const minAllowedTime = new Date(new Date().getTime() + 10 * 60000); - const startDt = resultData.event_start_dt; - const endDt = resultData.event_end_dt; - if (modalType === TYPE_REGISTRY && startDt < minAllowedTime) { - setAlertMsg(t('BATTLE_EVENT_MODAL_START_DT_WARNING')); - return; - } - if(resultData.repeat_type !== 'NONE' && !isValidDayRange(startDt, endDt)) { - setAlertMsg(t('DATE_START_DIFF_END_WARNING')) - return; - } - - //화면에 머물면서 상태는 안바꼈을 경우가 있기에 시작시간 지났을경우 차단 - if (modalType === TYPE_REGISTRY && startDt < new Date()) { - setAlertMsg(t('BATTLE_EVENT_MODAL_START_DT_WARNING')); - return; - } - - if(resultData.round_time === 0){ - const config = configData.find(data => data.id === resultData.config_id); - setResultData({ ...resultData, round_time: config.round_time }); - } - - handleModalView('registConfirm'); - break; - case "cancel": - handleModalView('cancel'); - break; - case "cancelConfirm": - handleModalClose('cancel'); - handleReset(); - break; - case "registConfirm": - setLoading(true); - - if(isView('modify')){ - await BattleEventModify(token, content?.id, resultData).then(data => { - setLoading(false); - handleModalClose('registConfirm'); - if(data.result === "SUCCESS") { - handleModalView('registComplete'); - }else if(data.result === "ERROR_BATTLE_EVENT_TIME_OVER"){ - setAlertMsg(t('BATTLE_EVENT_MODAL_TIME_CHECK_WARNING')); - }else{ - setAlertMsg(t('UPDATE_FAIL')); - } - }).catch(reason => { - setAlertMsg(t('API_FAIL')); - }); - } - else{ - await BattleEventSingleRegist(token, resultData).then(data => { - setLoading(false); - handleModalClose('registConfirm'); - if(data.result === "SUCCESS") { - handleModalView('registComplete'); - }else if(data.result === "ERROR_BATTLE_EVENT_TIME_OVER"){ - setAlertMsg(t('BATTLE_EVENT_MODAL_TIME_CHECK_WARNING')); - }else{ - setAlertMsg(t('REGIST_FAIL')); - } - }).catch(reason => { - setAlertMsg(t('API_FAIL')); - }); - } - break; - case "registComplete": - handleModalClose('registComplete'); - handleReset(); - window.location.reload(); - break; - case "warning": - setAlertMsg(''); - break; - } - } - - const checkCondition = () => { - return ( - resultData.event_start_dt !== '' - && resultData.group_id !== '' - && resultData.event_name !== '' - && (resultData.repeat_type === 'NONE' || (resultData.repeat_type !== 'NONE' && resultData.event_end_dt !== '')) - ); - }; - - const isView = (label) => { - switch (label) { - case "modify": - return modalType === TYPE_MODIFY && (content?.status === battleEventStatusType.stop); - case "start_dt": - case "repeat": - case "registry": - return modalType === TYPE_REGISTRY - case "end_dt": - case "group": - case "name": - case "config": - case "reward": - case "round": - case "hot": - return modalType === TYPE_REGISTRY || (modalType === TYPE_MODIFY &&(content?.status === battleEventStatusType.stop)); - default: - return modalType === TYPE_MODIFY && (content?.status !== battleEventStatusType.stop); - } - } - - return ( - <> - - {isView('registry') ? "전투시스템 이벤트 등록" : isView('modify') ? "전투시스템 이벤트 수정" : "전투시스템 이벤트 상세"} - - - 그룹 ID - setResultData({ ...resultData, group_id: e.target.value })} - /> - 이벤트명 - setResultData({ ...resultData, event_name: e.target.value })} - /> - - - - - - - 반복 - setResultData({ ...resultData, repeat_type: e.target.value })} disabled={!isView('repeat')} width="150px"> - {battleRepeatType.map((data, index) => ( - - ))} - - {resultData?.repeat_type !== 'NONE' && - - } - - - 라운드 시간 - - {configData && configData?.map((data, index) => ( - - ))} - - 라운드 수 - setResultData({ ...resultData, round_count: e.target.value })} disabled={!isView('round')} width="100px"> - {battleEventRoundCount.map((data, index) => ( - - ))} - - - - 배정 포드 - setResultData({ ...resultData, reward_group_id: e.target.value })} disabled={!isView('reward')} width="200px"> - {rewardData && rewardData?.map((data, index) => ( - - ))} - - 핫타임 - setResultData({ ...resultData, hot_time: e.target.value })} disabled={!isView('hot')} width="100px"> - {battleEventHotTime.map((data, index) => ( - - ))} - - - - {!isView() && isNullValue && {t('REQUIRED_VALUE_CHECK')}} - - - - - - 현재상태: {battleEventStatus.find(data => data.value === content?.status)?.name || "등록"} - - - {isView('registry') ? '' : t('BATTLE_EVENT_MODAL_STATUS_WARNING')} - - - - {isView() ? -