component 정리

currencyLogSearchBar 생성
currencyLogCOntent 생성
excelExportButton api호출 방식 수정
This commit is contained in:
2025-06-12 14:08:11 +09:00
parent dc7934d906
commit 6f9f0307ac
52 changed files with 791 additions and 1143 deletions

View File

@@ -0,0 +1,429 @@
import React, { useState, Fragment, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import Button from '../common/button/Button';
import {
Title,
BtnWrapper,
SearchBarAlert, SelectInput,
} from '../../styles/Components';
import {
FormInput,
FormLabel,
MessageWrapper,
FormRowGroup,
FormStatusBar,
FormStatusLabel,
FormStatusWarning,
FormButtonContainer,
} from '../../styles/ModuleComponents';
import { Modal, SingleDatePicker, SingleTimePicker } from '../common';
import { NONE, TYPE_MODIFY, TYPE_REGISTRY } from '../../assets/data/adminConstants';
import { convertKTCDate } from '../../utils';
import {
battleEventHotTime,
battleEventRoundCount,
battleEventStatus,
battleRepeatType,
} from '../../assets/data/options';
import { BattleEventModify, BattleEventSingleRegist } from '../../apis/Battle';
import { alertTypes, battleEventStatusType } from '../../assets/data/types';
import { isValidDayRange } from '../../utils/date';
import { useAlert } from '../../context/AlertProvider';
import { useLoading } from '../../context/LoadingProvider';
const BattleEventModal = ({ modalType, detailView, handleDetailView, content, setDetailData, configData, rewardData }) => {
const { t } = useTranslation();
const token = sessionStorage.getItem('token');
const { showToast, showModal } = useAlert();
const {withLoading} = useLoading();
const [isNullValue, setIsNullValue] = useState(false);
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,
round_time: configData[0].round_time
}));
}
}, [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) {
showToast('DATE_START_DIFF_END_WARNING', {type: alertTypes.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) {
showToast('DATE_START_DIFF_END_WARNING', {type: alertTypes.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 {
showToast('Config not found for value:', e.target.value, {type: alertTypes.warning});
}
}
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) {
showToast('BATTLE_EVENT_MODAL_START_DT_WARNING', {type: alertTypes.warning});
return;
}
if(resultData.repeat_type !== 'NONE' && !isValidDayRange(startDt, endDt)) {
showToast('BATTLE_EVENT_MODAL_START_DT_WARNING', {type: alertTypes.warning});
return;
}
//화면에 머물면서 상태는 안바꼈을 경우가 있기에 시작시간 지났을경우 차단
if (modalType === TYPE_REGISTRY && startDt < new Date()) {
showToast('BATTLE_EVENT_MODAL_START_DT_WARNING', {type: alertTypes.warning});
return;
}
// if(resultData.round_time === 0){
// const config = configData.find(data => data.id === resultData.config_id);
// setResultData({ ...resultData, round_time: config.round_time });
// }
showModal(isView('modify') ? 'BATTLE_EVENT_UPDATE_CONFIRM' : 'BATTLE_EVENT_REGIST_CONFIRM', {
type: alertTypes.confirm,
onConfirm: () => handleSubmit('registConfirm')
});
break;
case "registConfirm":
if(isView('modify')){
await withLoading( async () => {
return await BattleEventModify(token, content?.id, resultData);
}).then(data => {
if(data.result === "SUCCESS") {
showToast('UPDATE_COMPLETED', {type: alertTypes.success});
}else if(data.result === "ERROR_BATTLE_EVENT_TIME_OVER"){
showToast('BATTLE_EVENT_MODAL_TIME_CHECK_WARNING', {type: alertTypes.error});
}else{
showToast('UPDATE_FAIL', {type: alertTypes.error});
}
}).catch(reason => {
showToast('API_FAIL', {type: alertTypes.error});
}).finally(() => {
handleReset();
});
}
else{
await withLoading( async () => {
return await BattleEventSingleRegist(token, resultData);
}).then(data => {
if(data.result === "SUCCESS") {
showToast('REGIST_COMPLTE', {type: alertTypes.success});
}else if(data.result === "ERROR_BATTLE_EVENT_TIME_OVER"){
showToast('BATTLE_EVENT_MODAL_TIME_CHECK_WARNING', {type: alertTypes.error});
}else{
showToast('REGIST_FAIL', {type: alertTypes.error});
}
}).catch(reason => {
showToast('API_FAIL', {type: alertTypes.error});
}).finally(() => {
handleReset();
});
}
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 (
<>
<Modal min="760px" $view={detailView}>
<Title $align="center">{isView('registry') ? "전투시스템 이벤트 등록" : isView('modify') ? "전투시스템 이벤트 수정" : "전투시스템 이벤트 상세"}</Title>
<MessageWrapper>
<FormRowGroup>
<FormLabel>그룹 ID</FormLabel>
<FormInput
type="text"
disabled={!isView('group')}
width='150px'
value={resultData?.group_id}
onChange={e => setResultData({ ...resultData, group_id: e.target.value })}
/>
<FormLabel>이벤트명</FormLabel>
<FormInput
type="text"
disabled={!isView('name')}
width='300px'
value={resultData?.event_name}
onChange={e => setResultData({ ...resultData, event_name: e.target.value })}
/>
</FormRowGroup>
<FormRowGroup>
<SingleDatePicker
label="시작일자"
disabled={!isView('start_dt')}
dateLabel="시작 일자"
onDateChange={handleStartDateChange}
selectedDate={resultData?.event_start_dt}
/>
<SingleTimePicker
label="시작시간"
disabled={!isView('start_dt')}
selectedTime={resultData?.event_start_dt}
onTimeChange={handleStartTimeChange}
/>
</FormRowGroup>
<FormRowGroup>
<FormLabel>반복</FormLabel>
<SelectInput value={resultData?.repeat_type} onChange={e => setResultData({ ...resultData, repeat_type: e.target.value })} disabled={!isView('repeat')} width="150px">
{battleRepeatType.map((data, index) => (
<option key={index} value={data.value}>
{data.name}
</option>
))}
</SelectInput>
{resultData?.repeat_type !== 'NONE' &&
<SingleDatePicker
label="종료일자"
disabled={!isView('end_dt')}
dateLabel="종료 일자"
onDateChange={handleEndDateChange}
selectedDate={resultData?.event_end_dt}
/>
}
</FormRowGroup>
<FormRowGroup>
<FormLabel>라운드 시간</FormLabel>
<SelectInput value={resultData.config_id} onChange={handleConfigChange} disabled={!isView('config')} width="200px">
{configData && configData?.map((data, index) => (
<option key={index} value={data.id}>
{data.desc}({data.id})
</option>
))}
</SelectInput>
<FormLabel>라운드 </FormLabel>
<SelectInput value={resultData.round_count} onChange={e => setResultData({ ...resultData, round_count: e.target.value })} disabled={!isView('round')} width="100px">
{battleEventRoundCount.map((data, index) => (
<option key={index} value={data}>
{data}
</option>
))}
</SelectInput>
</FormRowGroup>
<FormRowGroup>
<FormLabel>배정 포드</FormLabel>
<SelectInput value={resultData.reward_group_id} onChange={e => setResultData({ ...resultData, reward_group_id: e.target.value })} disabled={!isView('reward')} width="200px">
{rewardData && rewardData?.map((data, index) => (
<option key={index} value={data.group_id}>
{data.desc}({data.group_id})
</option>
))}
</SelectInput>
<FormLabel>핫타임</FormLabel>
<SelectInput value={resultData.hot_time} onChange={e => setResultData({ ...resultData, hot_time: e.target.value })} disabled={!isView('hot')} width="100px">
{battleEventHotTime.map((data, index) => (
<option key={index} value={data}>
{data}
</option>
))}
</SelectInput>
</FormRowGroup>
{!isView() && isNullValue && <SearchBarAlert $marginTop="25px" $align="right">{t('REQUIRED_VALUE_CHECK')}</SearchBarAlert>}
</MessageWrapper>
<BtnWrapper $gap="10px" $marginTop="10px">
<FormStatusBar>
<FormStatusLabel>
현재상태: {battleEventStatus.find(data => data.value === content?.status)?.name || "등록"}
</FormStatusLabel>
<FormStatusWarning>
{isView('registry') ? '' : t('BATTLE_EVENT_MODAL_STATUS_WARNING')}
</FormStatusWarning>
</FormStatusBar>
<FormButtonContainer $gap="5px">
{isView() ?
<Button
text="확인"
name="확인버튼"
theme="line"
handleClick={() => handleReset()}
/>
:
<>
<Button
text="취소"
theme="line"
handleClick={() => showModal('CANCEL_CONFIRM', {
type: alertTypes.confirm,
onConfirm: () => handleReset()
})}
/>
<Button
type="submit"
text={isView('modify') ? "수정" : "등록"}
name="등록버튼"
theme={
checkCondition()
? 'primary'
: 'disable'
}
handleClick={() => handleSubmit('submit')}
/>
</>
}
</FormButtonContainer>
</BtnWrapper>
</Modal>
</>
);
};
export const initData = {
group_id: '',
event_name: '',
repeat_type: 'NONE',
config_id: 1,
round_time: 0,
reward_group_id: 1,
round_count: 1,
hot_time: 1,
event_start_dt: '',
event_end_dt: ''
}
export default BattleEventModal;