배너 detailGrid 적용
배너 수정 및 삭제
This commit is contained in:
@@ -1,38 +1,19 @@
|
||||
import React, { useState, useEffect, Fragment } from 'react';
|
||||
import styled, { css, keyframes } from 'styled-components';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import {
|
||||
Title,
|
||||
SelectInput,
|
||||
BtnWrapper,
|
||||
TextInput,
|
||||
Label,
|
||||
InputLabel,
|
||||
Textarea,
|
||||
SearchBarAlert,
|
||||
ButtonGroupWrapper,
|
||||
} from '../../styles/Components';
|
||||
import Button from '../common/button/Button';
|
||||
import { Title, ButtonGroupWrapper, } from '../../styles/Components';
|
||||
import Modal from '../common/modal/Modal';
|
||||
import { EventIsItem, EventModify, MenuBannerModify } from '../../apis';
|
||||
import { 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 { authType, commonStatus } from '../../assets/data';
|
||||
import { convertKTCDate } from '../../utils';
|
||||
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';
|
||||
import { alertTypes, languageNames } from '../../assets/data/types';
|
||||
import { Image as AntImage } from 'antd';
|
||||
import { AntButton, DetailLayout } from '../common';
|
||||
|
||||
function renderImageContent(imageData) {
|
||||
if (!imageData) {
|
||||
@@ -77,7 +58,6 @@ function renderImageContent(imageData) {
|
||||
|
||||
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();
|
||||
@@ -94,17 +74,12 @@ const MenuBannerDetailModal = ({ detailView, handleDetailView, content, setDetai
|
||||
|
||||
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);
|
||||
// console.log(content);
|
||||
const start_dt_KTC = convertKTCDate(content.start_dt);
|
||||
const end_dt_KTC = convertKTCDate(content.end_dt);
|
||||
|
||||
@@ -131,13 +106,6 @@ const MenuBannerDetailModal = ({ detailView, handleDetailView, content, setDetai
|
||||
|
||||
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) {
|
||||
@@ -156,105 +124,9 @@ const MenuBannerDetailModal = ({ detailView, handleDetailView, content, setDetai
|
||||
})) : [];
|
||||
|
||||
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 = () => {
|
||||
@@ -279,6 +151,7 @@ const MenuBannerDetailModal = ({ detailView, handleDetailView, content, setDetai
|
||||
case "submit":
|
||||
if (!checkCondition()) return;
|
||||
|
||||
// console.log(resultData);
|
||||
showModal('MENU_BANNER_UPDATE_SAVE', {
|
||||
type: alertTypes.confirm,
|
||||
onConfirm: () => handleSubmit('updateConfirm')
|
||||
@@ -287,50 +160,43 @@ const MenuBannerDetailModal = ({ detailView, handleDetailView, content, setDetai
|
||||
case "updateConfirm":
|
||||
withLoading( async () => {
|
||||
return await MenuBannerModify(token, id, resultData);
|
||||
}).then(result => {
|
||||
if(result.result === 'ERROR'){
|
||||
showToast(result.data.message, {
|
||||
type: alertTypes.error
|
||||
});
|
||||
}else if(result.result === 'SUCCESS'){
|
||||
showToast('UPDATE_COMPLETED', {type: alertTypes.success, duration: 4000});
|
||||
}
|
||||
}).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 <DetailState>대기</DetailState>;
|
||||
case commonStatus.running:
|
||||
return <DetailState>진행중</DetailState>;
|
||||
case commonStatus.finish:
|
||||
return <DetailState result={commonStatus.finish}>만료</DetailState>;
|
||||
case commonStatus.fail:
|
||||
return <DetailState result={commonStatus.fail}>실패</DetailState>;
|
||||
case commonStatus.delete:
|
||||
return <DetailState result={commonStatus.delete}>삭제</DetailState>;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
//true 수정불가, false 수정가능
|
||||
const isView = (fieldName) => {
|
||||
if (!updateAuth) return false;
|
||||
|
||||
if (fieldName === 'editButton') {
|
||||
// updateAuth가 없거나 FINISH 상태면 수정 버튼 숨김 (false 반환)
|
||||
// updateAuth가 없거나 FINISH 상태면 수정 버튼 숨김
|
||||
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;
|
||||
if (!updateAuth) return false;
|
||||
|
||||
if(content.status === commonStatus.wait){
|
||||
return true;
|
||||
}else if(content.status === commonStatus.running){
|
||||
switch(fieldName){
|
||||
case 'order_id':
|
||||
case 'end_dt':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,12 +237,35 @@ const MenuBannerDetailModal = ({ detailView, handleDetailView, content, setDetai
|
||||
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'
|
||||
type: 'date',
|
||||
key: 'start_dt',
|
||||
label: '시작일',
|
||||
disabled: !isView('start_dt'),
|
||||
format: 'YYYY-MM-DD HH:mm',
|
||||
width: '250px',
|
||||
showTime: true
|
||||
},
|
||||
{
|
||||
row: 2,
|
||||
col: 2,
|
||||
colSpan: 2,
|
||||
type: 'date',
|
||||
key: 'end_dt',
|
||||
label: '종료일',
|
||||
disabled: !isView('end_dt'),
|
||||
format: 'YYYY-MM-DD HH:mm',
|
||||
width: '250px',
|
||||
showTime: true
|
||||
},
|
||||
{
|
||||
row: 3,
|
||||
col: 0,
|
||||
colSpan: 4,
|
||||
type: 'tab',
|
||||
key: 'languageTabs',
|
||||
tabItems: tabItems,
|
||||
activeKey: activeLanguage,
|
||||
onTabChange: handleTabChange
|
||||
},
|
||||
]
|
||||
}
|
||||
@@ -393,76 +282,6 @@ const MenuBannerDetailModal = ({ detailView, handleDetailView, content, setDetai
|
||||
disabled={!updateAuth}
|
||||
columnCount={4}
|
||||
/>
|
||||
{/*<DetailModalWrapper>*/}
|
||||
{/* {content &&*/}
|
||||
{/* <RegistGroup>*/}
|
||||
{/* <FormRowGroup>*/}
|
||||
{/* <DetailInputItem>*/}
|
||||
{/* <FormLabel>제목</FormLabel>*/}
|
||||
{/* <FormInput*/}
|
||||
{/* type="text"*/}
|
||||
{/* value={content.title}*/}
|
||||
{/* disabled={isView('title')}*/}
|
||||
{/* onChange={e => setResultData({ ...resultData, title: e.target.value })}*/}
|
||||
{/* width="300px"*/}
|
||||
{/* />*/}
|
||||
{/* </DetailInputItem>*/}
|
||||
{/* <DetailInputItem>*/}
|
||||
{/* <FormLabel>순서</FormLabel>*/}
|
||||
{/* <FormInput*/}
|
||||
{/* placeholder="순서번호"*/}
|
||||
{/* type="number"*/}
|
||||
{/* value={content.order_id}*/}
|
||||
{/* disabled={isView('order_id')}*/}
|
||||
{/* onChange={e => setResultData({ ...resultData, order_id: e.target.value })}*/}
|
||||
{/* width="200px"*/}
|
||||
{/* />*/}
|
||||
{/* </DetailInputItem>*/}
|
||||
{/* </FormRowGroup>*/}
|
||||
{/* <FormRowGroup>*/}
|
||||
{/* <DateTimeRangePicker*/}
|
||||
{/* label="예약기간"*/}
|
||||
{/* startDate={resultData.start_dt}*/}
|
||||
{/* endDate={resultData.end_dt}*/}
|
||||
{/* onStartDateChange={handleDateChange.start}*/}
|
||||
{/* onEndDateChange={handleDateChange.end}*/}
|
||||
{/* pastDate={new Date()}*/}
|
||||
{/* disabled={isView('date')}*/}
|
||||
{/* startLabel="시작 일자"*/}
|
||||
{/* endLabel="종료 일자"*/}
|
||||
{/* // reset={resetDateTime}*/}
|
||||
{/* />*/}
|
||||
{/* </FormRowGroup>*/}
|
||||
{/* <FormRowGroup>*/}
|
||||
{/* <DetailInputItem>*/}
|
||||
{/* <FormLabel>상태</FormLabel>*/}
|
||||
{/* <div>{detailState(content.status)}</div>*/}
|
||||
{/* </DetailInputItem>*/}
|
||||
{/* </FormRowGroup>*/}
|
||||
{/* {content.image_list && content.image_list.length > 0 && (*/}
|
||||
{/* <FormRowGroup style={{display: 'flex', justifyContent: 'center', width: '100%'}}>*/}
|
||||
{/* <DetailInputItem style={{width: '100%'}}>*/}
|
||||
{/* {!showTabContent ? (*/}
|
||||
{/* <LoadingContainer>*/}
|
||||
{/* <Spin size="large" tip="이미지 로딩 중..." />*/}
|
||||
{/* </LoadingContainer>*/}
|
||||
{/* ) : (*/}
|
||||
{/* <ContentWrapper $isLoaded={showTabContent}>*/}
|
||||
{/* <AnimatedTabs*/}
|
||||
{/* items={tabItems}*/}
|
||||
{/* activeKey={activeLanguage}*/}
|
||||
{/* onChange={handleTabChange}*/}
|
||||
{/* />*/}
|
||||
{/* </ContentWrapper>*/}
|
||||
{/* )}*/}
|
||||
|
||||
{/* </DetailInputItem>*/}
|
||||
{/* </FormRowGroup>*/}
|
||||
{/* )}*/}
|
||||
|
||||
{/* </RegistGroup>*/}
|
||||
{/* }*/}
|
||||
{/*</DetailModalWrapper>*/}
|
||||
<ButtonGroupWrapper $justify="flex-end" $gap="10px" $paddingTop="20px">
|
||||
<AntButton
|
||||
text="확인"
|
||||
@@ -503,43 +322,6 @@ const initData = {
|
||||
]
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -590,22 +372,3 @@ const NoImagePlaceholder = styled.div`
|
||||
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;
|
||||
`;
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user