init
This commit is contained in:
168
src/pages/Account/AccountEdit.js
Normal file
168
src/pages/Account/AccountEdit.js
Normal file
@@ -0,0 +1,168 @@
|
||||
import { useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
|
||||
import { PasswordValidation } from './PasswordValidation';
|
||||
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { FormBox, AccountTitle, FormWrapper, BtnWrapper, ModalText } from '../../styles/Components';
|
||||
import Button from '../../components/common/button/Button';
|
||||
import Modal from '../../components/common/modal/Modal';
|
||||
import CloseIcon from '../../assets/img/icon/icon-close.png';
|
||||
|
||||
import { AccountEditItem } from '../../components/account';
|
||||
import { AuthEdit } from '../../apis';
|
||||
|
||||
const AccountEdit = () => {
|
||||
const [completeModal, setCompleteModal] = useState('hidden');
|
||||
const navigate = useNavigate();
|
||||
const [confirmText, setConfirmText] = useState('');
|
||||
|
||||
const onSubmitData = async data => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
|
||||
const message = await AuthEdit(data, token);
|
||||
message.data.data.message !== '수정 하였습니다.' ? setConfirmText(message.data.data.message) : setConfirmText('변경이 완료되었습니다.');
|
||||
|
||||
setForm('');
|
||||
handleCompleteModal();
|
||||
};
|
||||
|
||||
const {
|
||||
register,
|
||||
formState: { errors },
|
||||
watch,
|
||||
handleSubmit,
|
||||
} = useForm({
|
||||
resolver: yupResolver(PasswordValidation),
|
||||
mode: 'onChange',
|
||||
});
|
||||
|
||||
const values = watch();
|
||||
|
||||
const [form, setForm] = useState({
|
||||
newPassword: '',
|
||||
passwordConfirm: '',
|
||||
});
|
||||
|
||||
const { newPassword, passwordConfirm } = form;
|
||||
|
||||
const onChange = e => {
|
||||
const nextForm = {
|
||||
...form,
|
||||
[e.target.name]: e.target.value,
|
||||
};
|
||||
setForm(nextForm);
|
||||
};
|
||||
|
||||
// console.log(form);
|
||||
|
||||
const AccountEditData = [
|
||||
{
|
||||
title: '신규 비밀번호',
|
||||
name: 'newPassword',
|
||||
placeholder: '영어/숫자/특수문자 조합 가능(8~20자)',
|
||||
value: newPassword,
|
||||
},
|
||||
{
|
||||
title: '비밀번호 확인',
|
||||
name: 'passwordConfirm',
|
||||
placeholder: '비밀번호 재입력',
|
||||
value: passwordConfirm,
|
||||
},
|
||||
];
|
||||
|
||||
// 완료 모달창
|
||||
const handleCompleteModal = () => {
|
||||
if (completeModal === 'hidden') {
|
||||
setCompleteModal('view');
|
||||
} else {
|
||||
setCompleteModal('hidden');
|
||||
|
||||
if (confirmText === '변경이 완료되었습니다.') {
|
||||
sessionStorage.removeItem('token');
|
||||
navigate('/');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 취소버튼
|
||||
const handleSessionout = e => {
|
||||
e.preventDefault();
|
||||
|
||||
sessionStorage.removeItem('token');
|
||||
navigate('/');
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<FormBox>
|
||||
<AccountTitle>비밀번호 재설정</AccountTitle>
|
||||
<FormWrapper action="" $flow="column" onSubmit={handleSubmit(onSubmitData)}>
|
||||
{/* 비밀번호 만료 안내에서 비밀번호 변경 시 현재 비밀번호 입력 항목이 보입니다. */}
|
||||
|
||||
{AccountEditData.map((data, index) => (
|
||||
<AccountEditItem
|
||||
key={index}
|
||||
title={data.title}
|
||||
name={data.name}
|
||||
placeholder={data.placeholder}
|
||||
alertText={data.alertText}
|
||||
value={data.value}
|
||||
onChange={onChange}
|
||||
register={register}
|
||||
errors={errors}
|
||||
/>
|
||||
))}
|
||||
|
||||
<PwBtnWrap $justify="space-between" $gap="14px">
|
||||
<Button
|
||||
theme="line"
|
||||
size="large"
|
||||
bordercolor="#e4e4e4"
|
||||
text="취소"
|
||||
handleClick={e => {
|
||||
handleSessionout(e);
|
||||
}}
|
||||
width="100%"
|
||||
/>
|
||||
|
||||
<Button
|
||||
size="large"
|
||||
width="100%"
|
||||
text="완료"
|
||||
type="submit"
|
||||
bordercolor="#e4e4e4"
|
||||
theme={!values.passwordConfirm || errors.newPassword || errors.passwordConfirm ? 'disable' : 'primary'}
|
||||
isDisabled={values.password && values.newPassword && values.passwordConfirm ? false : true}
|
||||
/>
|
||||
</PwBtnWrap>
|
||||
</FormWrapper>
|
||||
</FormBox>
|
||||
{/* 완료 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={completeModal}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleCompleteModal} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">{confirmText}</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleCompleteModal} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccountEdit;
|
||||
|
||||
const PwBtnWrap = styled(BtnWrapper)`
|
||||
margin-top: 25px;
|
||||
`;
|
||||
|
||||
const ButtonClose = styled.button`
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: url(${CloseIcon}) 50% 50% no-repeat;
|
||||
`;
|
||||
187
src/pages/Account/AccountRegist.js
Normal file
187
src/pages/Account/AccountRegist.js
Normal file
@@ -0,0 +1,187 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
|
||||
import { RegistValidation } from './RegistValidation';
|
||||
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { FormBox, AccountTitle, FormWrapper, BtnWrapper } from '../../styles/Components';
|
||||
import Button from '../../components/common/button/Button';
|
||||
import { AccountInputItem } from '../../components/account';
|
||||
import Modal from '../../components/common/modal/Modal';
|
||||
import CloseUrl from '../../assets/img/icon/icon-close.png';
|
||||
|
||||
import { AuthRegist } from '../../apis';
|
||||
|
||||
const AccountRegist = () => {
|
||||
const navigate = useNavigate();
|
||||
const [stateModal, setStateModal] = useState('hidden');
|
||||
const [submitText, setSubmitText] = useState('');
|
||||
const [doubleSubmitFlag, setDoubleSubmitFlag] = useState(false);
|
||||
const [isSuccess, setIsSuccess] = useState(false)
|
||||
|
||||
const handleModal = () => {
|
||||
if (stateModal === 'hidden') {
|
||||
setStateModal('view');
|
||||
} else {
|
||||
// submitText === '회원가입이 완료되었습니다. \n 관리자 로그인 권한 승인 까지 \n 대기해주세요.' ? navigate('/') : setStateModal('hidden'); //2024.08.02 승인 제외에 따른 변경
|
||||
isSuccess ? navigate('/') : setStateModal('hidden');
|
||||
setDoubleSubmitFlag(false);
|
||||
}
|
||||
};
|
||||
|
||||
const onSubmitData = async data => {
|
||||
setDoubleSubmitFlag(true);
|
||||
|
||||
const result = await AuthRegist(data);
|
||||
|
||||
setSubmitText(
|
||||
// result.data.access_token && result.data.access_token === '저장 하였습니다.' ? '회원가입이 완료되었습니다. \n 관리자 로그인 권한 승인 까지 \n 대기해주세요.' : result.data.message, //2024.08.02 승인 제외에 따른 메시지 변경
|
||||
result.data.access_token && result.data.access_token === '저장 하였습니다.' ? '회원가입이 완료되었습니다.' : result.data.message,
|
||||
);
|
||||
setIsSuccess(result.data.access_token && result.data.access_token === '저장 하였습니다.' ? true : false);
|
||||
|
||||
handleModal();
|
||||
};
|
||||
|
||||
// console.log(doubleSubmitFlag);
|
||||
|
||||
const {
|
||||
register,
|
||||
formState: { errors },
|
||||
watch,
|
||||
handleSubmit,
|
||||
} = useForm({
|
||||
resolver: yupResolver(RegistValidation),
|
||||
mode: 'onChange',
|
||||
});
|
||||
|
||||
const [form, setForm] = useState({
|
||||
username: '',
|
||||
userid: '',
|
||||
password: '',
|
||||
confirmPassword: '',
|
||||
});
|
||||
|
||||
const { username, userid, password, confirmPassword } = form;
|
||||
|
||||
const values = watch();
|
||||
|
||||
const onChange = e => {
|
||||
const nextForm = {
|
||||
...form,
|
||||
[e.target.name]: e.target.value,
|
||||
};
|
||||
setForm(nextForm);
|
||||
};
|
||||
|
||||
const AccountRegistData = [
|
||||
{
|
||||
title: '이름',
|
||||
type: 'text',
|
||||
name: 'username',
|
||||
placeholder: '한글, 영문 입력 가능',
|
||||
value: username,
|
||||
},
|
||||
{
|
||||
title: 'ID(메일주소)',
|
||||
type: 'text',
|
||||
name: 'userid',
|
||||
placeholder: 'sample@lotte.net',
|
||||
value: userid,
|
||||
},
|
||||
{
|
||||
title: '비밀번호',
|
||||
type: 'password',
|
||||
name: 'password',
|
||||
placeholder: '영어/숫자/특수문자 조합 가능(8~20자)',
|
||||
value: password,
|
||||
length: '20',
|
||||
},
|
||||
{
|
||||
title: '비밀번호 확인',
|
||||
type: 'password',
|
||||
name: 'confirmPassword',
|
||||
placeholder: '비밀번호 확인',
|
||||
value: confirmPassword,
|
||||
length: '20',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<FormBox>
|
||||
<AccountTitle>회원가입</AccountTitle>
|
||||
<FormWrapper $flow="column" onSubmit={doubleSubmitFlag || handleSubmit(onSubmitData)}>
|
||||
{AccountRegistData.map((data, index) => (
|
||||
<AccountInputItem
|
||||
key={index}
|
||||
title={data.title}
|
||||
type={data.type}
|
||||
name={data.name}
|
||||
placeholder={data.placeholder}
|
||||
alertText={data.alertText}
|
||||
value={data.value}
|
||||
onChange={onChange}
|
||||
register={register}
|
||||
errors={errors}
|
||||
length={data.length && data.length}
|
||||
/>
|
||||
))}
|
||||
<JoinBtnWrapper $justify="space-between" $gap="14px">
|
||||
<Button
|
||||
theme="line"
|
||||
size="large"
|
||||
text="취소"
|
||||
width="100%"
|
||||
handleClick={e => {
|
||||
e.preventDefault();
|
||||
navigate('/');
|
||||
}}
|
||||
bordercolor="#e4e4e4"
|
||||
/>
|
||||
|
||||
<Button
|
||||
errorMessage={doubleSubmitFlag === true}
|
||||
size="large"
|
||||
text="가입하기"
|
||||
type="submit"
|
||||
width="100%"
|
||||
theme={!values.confirmPassword || errors.username || errors.userid || errors.password || errors.confirmPassword ? 'disable' : 'primary'}
|
||||
/>
|
||||
</JoinBtnWrapper>
|
||||
</FormWrapper>
|
||||
</FormBox>
|
||||
<Modal $view={stateModal} min="440px" $padding="40px">
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleModal} />
|
||||
</BtnWrapper>
|
||||
<ModalText>{submitText}</ModalText>
|
||||
<Button text="확인" theme="primary" size="large" width="100%" handleClick={handleModal} />
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccountRegist;
|
||||
|
||||
const JoinBtnWrapper = styled(BtnWrapper)`
|
||||
margin-top: 25px;
|
||||
justify-content: space-between;
|
||||
gap: 14px;
|
||||
`;
|
||||
|
||||
const ModalText = styled.div`
|
||||
font-size: 20px;
|
||||
line-height: 30px;
|
||||
font-weight: 600;
|
||||
padding: 10px 0 40px;
|
||||
`;
|
||||
|
||||
const ButtonClose = styled.button`
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: url(${CloseUrl}) 50% 50% no-repeat;
|
||||
`;
|
||||
111
src/pages/Account/PasswordReset.js
Normal file
111
src/pages/Account/PasswordReset.js
Normal file
@@ -0,0 +1,111 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
|
||||
import { RegistValidation } from './RegistValidation';
|
||||
import { FormBox, AccountTitle, FormWrapper, BtnWrapper } from '../../styles/Components';
|
||||
import { AccountInputItem } from '../../components/account';
|
||||
import Button from '../../components/common/button/Button';
|
||||
|
||||
import styled from 'styled-components';
|
||||
|
||||
const PasswordReset = () => {
|
||||
const navigate = useNavigate();
|
||||
const [stateModal, setStateModal] = useState('hidden');
|
||||
const [submitText, setSubmitText] = useState('');
|
||||
const [doubleSubmitFlag, setDoubleSubmitFlag] = useState(false);
|
||||
const [isSuccess, setIsSuccess] = useState(false)
|
||||
|
||||
const {
|
||||
register,
|
||||
formState: { errors },
|
||||
watch,
|
||||
handleSubmit,
|
||||
} = useForm({
|
||||
resolver: yupResolver(RegistValidation),
|
||||
mode: 'onChange',
|
||||
});
|
||||
const [form, setForm] = useState({
|
||||
userid: '',
|
||||
username: ''
|
||||
});
|
||||
const { userid, username } = form;
|
||||
|
||||
const onChange = e => {
|
||||
const nextForm = {
|
||||
...form,
|
||||
[e.target.name]: e.target.value,
|
||||
};
|
||||
setForm(nextForm);
|
||||
};
|
||||
|
||||
const AccountRegistData = [
|
||||
{
|
||||
title: '이름',
|
||||
type: 'text',
|
||||
name: 'username',
|
||||
placeholder: '한글, 영문 입력 가능',
|
||||
value: username,
|
||||
},
|
||||
{
|
||||
title: 'ID(메일주소)',
|
||||
type: 'text',
|
||||
name: 'userid',
|
||||
placeholder: '가입한 메일주소를 입력해주세요.(sample@lotte.net)',
|
||||
value: userid,
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<FormBox>
|
||||
<AccountTitle>비밀번호 찾기</AccountTitle>
|
||||
{AccountRegistData.map((data, index) => (
|
||||
<AccountInputItem
|
||||
key={index}
|
||||
title={data.title}
|
||||
type={data.type}
|
||||
name={data.name}
|
||||
placeholder={data.placeholder}
|
||||
alertText={data.alertText}
|
||||
value={data.value}
|
||||
onChange={onChange}
|
||||
register={register}
|
||||
errors={errors}
|
||||
length={data.length && data.length}
|
||||
/>
|
||||
))}
|
||||
<PwdBtnWrapper $justify="space-between" $gap="14px">
|
||||
<Button
|
||||
theme="line"
|
||||
size="large"
|
||||
text="취소"
|
||||
width="100%"
|
||||
handleClick={e => {
|
||||
e.preventDefault();
|
||||
navigate('/');
|
||||
}}
|
||||
bordercolor="#e4e4e4"
|
||||
/>
|
||||
|
||||
<Button
|
||||
errorMessage={doubleSubmitFlag === true}
|
||||
size="large"
|
||||
text="비밀번호 찾기"
|
||||
type="submit"
|
||||
width="100%"
|
||||
theme={errors.username || errors.userid || errors.password || errors.confirmPassword ? 'disable' : 'primary'}
|
||||
/>
|
||||
</PwdBtnWrapper>
|
||||
</FormBox>
|
||||
</>
|
||||
);
|
||||
}
|
||||
export default PasswordReset;
|
||||
|
||||
const PwdBtnWrapper = styled(BtnWrapper)`
|
||||
margin-top: 25px;
|
||||
justify-content: space-between;
|
||||
gap: 14px;
|
||||
`;
|
||||
11
src/pages/Account/PasswordValidation.js
Normal file
11
src/pages/Account/PasswordValidation.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import * as yup from "yup";
|
||||
|
||||
export const PasswordValidation = yup.object({
|
||||
newPassword: yup.string()
|
||||
.min(8, '8~20자로 입력하십시오.')
|
||||
.max(20, '8~20자로 입력하십시오.')
|
||||
.required('비밀번호를 입력해주세요.'),
|
||||
passwordConfirm: yup.string()
|
||||
.oneOf([yup.ref('newPassword'), null], '비밀번호가 일치하지 않습니다.')
|
||||
.required('비밀번호를 한번 더 입력해주세요.'),
|
||||
});
|
||||
17
src/pages/Account/RegistValidation.js
Normal file
17
src/pages/Account/RegistValidation.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import * as yup from 'yup';
|
||||
|
||||
export const RegistValidation = yup.object({
|
||||
username: yup.string().matches(/^[가-힣a-zA-Z]+$/, '한글, 영문만 입력이 가능합니다.'),
|
||||
userid: yup.string().matches(/^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$/i, '메일주소가 올바르지 않습니다.'),
|
||||
password: yup
|
||||
.string()
|
||||
.min(8, '8~20자로 입력하십시오.')
|
||||
.max(20, '8~20자로 입력하십시오.')
|
||||
.oneOf([yup.ref('password'), null], '현재 비밀번호가 일치하지 않습니다.'),
|
||||
confirmPassword: yup
|
||||
.string()
|
||||
.min(8, '8~20자로 입력하십시오.')
|
||||
.max(20, '8~20자로 입력하십시오.')
|
||||
.oneOf([yup.ref('password'), null], '비밀번호가 일치하지 않습니다.')
|
||||
.required('비밀번호를 한번 더 입력해주세요.'),
|
||||
});
|
||||
3
src/pages/Account/index.js
Normal file
3
src/pages/Account/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
export { default as AccountRegist } from './AccountRegist';
|
||||
export { default as AccountEdit } from './AccountEdit';
|
||||
export { default as PasswordReset } from './PasswordReset';
|
||||
128
src/pages/DataManage/ContentsView.js
Normal file
128
src/pages/DataManage/ContentsView.js
Normal file
@@ -0,0 +1,128 @@
|
||||
import { styled } from 'styled-components';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Fragment, useState } from 'react';
|
||||
|
||||
import { Title, TableStyle, BtnWrapper, ButtonClose, ModalText } from '../../styles/Components';
|
||||
|
||||
import LandSearchBar from '../../components/DataManage/LandSearchBar';
|
||||
import Button from '../../components/common/button/Button';
|
||||
import QuestDetailModal from '../../components/DataManage/QuestDetailModal';
|
||||
import LandDetailModal from '../../components/DataManage/LandDetailModal';
|
||||
import Modal from '../../components/common/modal/Modal';
|
||||
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { authList } from '../../store/authList';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
const ContentsView = () => {
|
||||
const navigate = useNavigate();
|
||||
const userInfo = useRecoilValue(authList);
|
||||
|
||||
const [detailPop, setDetailPop] = useState('hidden');
|
||||
const mokupData = [
|
||||
{
|
||||
landId: '2000515223',
|
||||
ownerNick: '칼리버스F',
|
||||
ownerId: '23d59e868ca342198f6a653d957914a5',
|
||||
lockInDate: '2023-08-11 15:32:07',
|
||||
landUrl: '0x5765eB84ab55369f430DdA0d0C2b443FB9372DB3',
|
||||
},
|
||||
];
|
||||
|
||||
const handleClick = () => {
|
||||
if (detailPop === 'hidden') setDetailPop('view');
|
||||
else setDetailPop('hidden');
|
||||
};
|
||||
return (
|
||||
<>
|
||||
{userInfo.auth_list && !userInfo.auth_list.some(auth => auth.id === 13) ? (
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={'view'}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={() => navigate(-1)} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">
|
||||
해당 메뉴에 대한 조회 권한이 없습니다.
|
||||
<br />
|
||||
권한 등급을 변경 후 다시 이용해주세요.
|
||||
</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={() => navigate(-1)} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
) : (
|
||||
<>
|
||||
<Title>랜드 정보 조회</Title>
|
||||
<LandSearchBar />
|
||||
<TableWrapper>
|
||||
<TableStyle>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="150">랜드 ID</th>
|
||||
<th>소유자 아바타명</th>
|
||||
<th>소유쟈 GUID</th>
|
||||
<th width="200">Lock IN 처리 일자</th>
|
||||
<th>랜드 URL</th>
|
||||
<th width="150">상세보기</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{mokupData.map((data, index) => (
|
||||
<Fragment key={index}>
|
||||
<tr>
|
||||
<td>{data.landId}</td>
|
||||
<td>{data.ownerNick}</td>
|
||||
<td>{data.ownerId}</td>
|
||||
<td>{new Date(data.lockInDate).toLocaleString()}</td>
|
||||
<td>
|
||||
<LandLink to={data.landUrl}>{data.landUrl}</LandLink>
|
||||
</td>
|
||||
<td>
|
||||
<Button theme="line" text="상세보기" handleClick={handleClick} />
|
||||
</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
<LandDetailModal detailPop={detailPop} handleClick={handleClick} />
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContentsView;
|
||||
|
||||
const TableWrapper = styled.div`
|
||||
overflow: auto;
|
||||
border-top: 1px solid #000;
|
||||
&::-webkit-scrollbar {
|
||||
height: 4px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #666666;
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
background: #d9d9d9;
|
||||
}
|
||||
thead {
|
||||
th {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
${TableStyle} {
|
||||
min-width: 1000px;
|
||||
th {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const LandLink = styled(Link)`
|
||||
color: #61a2d0;
|
||||
text-decoration: underline;
|
||||
`;
|
||||
111
src/pages/DataManage/CryptView.js
Normal file
111
src/pages/DataManage/CryptView.js
Normal file
@@ -0,0 +1,111 @@
|
||||
import { styled } from 'styled-components';
|
||||
import { Fragment, useState } from 'react';
|
||||
|
||||
import { Title, TableStyle, ButtonClose, ModalText, BtnWrapper } from '../../styles/Components';
|
||||
|
||||
import UserSearchBar from '../../components/DataManage/UserSearchBar';
|
||||
import Modal from '../../components/common/modal/Modal';
|
||||
import Button from '../../components/common/button/Button';
|
||||
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { authList } from '../../store/authList';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
const CryptView = () => {
|
||||
const navigate = useNavigate();
|
||||
const userInfo = useRecoilValue(authList);
|
||||
const mokupData = [
|
||||
{
|
||||
getDate: '2023-08-06 18:50:03',
|
||||
getLocation: '유저 거래',
|
||||
itemName: '빛나는 가죽 장갑',
|
||||
serialNo: 'Serial_number',
|
||||
itemCode: 'Item_code',
|
||||
tradeKey: 'User_trade_key',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
{userInfo.auth_list && !userInfo.auth_list.some(auth => auth.id === 15) ? (
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={'view'}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={() => navigate(-1)} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">
|
||||
해당 메뉴에 대한 조회 권한이 없습니다.
|
||||
<br />
|
||||
권한 등급을 변경 후 다시 이용해주세요.
|
||||
</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={() => navigate(-1)} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
) : (
|
||||
<>
|
||||
<Title>크립토조회</Title>
|
||||
<UserSearchBar />
|
||||
<TableWrapper>
|
||||
<TableStyle>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="170">획득일자</th>
|
||||
<th width="170">획득처</th>
|
||||
<th width="200">아이템명</th>
|
||||
<th width="250">시리얼 넘버</th>
|
||||
<th width="250">고유 코드</th>
|
||||
<th width="250">거래 key</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{mokupData.map((data, index) => (
|
||||
<Fragment key={index}>
|
||||
<tr>
|
||||
<td>{new Date(data.getDate).toLocaleString()}</td>
|
||||
<td>{data.getLocation}</td>
|
||||
<td>{data.itemName}</td>
|
||||
<td>{data.serialNo}</td>
|
||||
<td>{data.itemCode}</td>
|
||||
<td>{data.tradeKey}</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default CryptView;
|
||||
|
||||
const TableWrapper = styled.div`
|
||||
max-height: calc(100vh - 287px);
|
||||
overflow: auto;
|
||||
border-top: 1px solid #000;
|
||||
&::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #666666;
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
background: #d9d9d9;
|
||||
}
|
||||
thead {
|
||||
th {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
${TableStyle} {
|
||||
th {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
`;
|
||||
389
src/pages/DataManage/GameLogView.js
Normal file
389
src/pages/DataManage/GameLogView.js
Normal file
@@ -0,0 +1,389 @@
|
||||
import { Fragment, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import Button from '../../components/common/button/Button';
|
||||
import Pagination from '../../components/common/Pagination/Pagination';
|
||||
|
||||
import DatePicker, { registerLocale } from 'react-datepicker';
|
||||
import { ko } from 'date-fns/esm/locale';
|
||||
import 'react-datepicker/dist/react-datepicker.css';
|
||||
import { getMonth, getYear } from 'date-fns';
|
||||
import range from 'lodash/range';
|
||||
|
||||
import { Title, SelectInput, BtnWrapper, TableStyle, TableInfo, ListCount, ListOption, ButtonClose, ModalText } from '../../styles/Components';
|
||||
import { styled } from 'styled-components';
|
||||
|
||||
import ItemLogSearchBar from '../../components/DataManage/ItemLogSearchBar';
|
||||
import GoodsLogSearchBar from '../../components/DataManage/CreditLogSearchBar';
|
||||
import TradeLogSerchBar from '../../components/DataManage/TradeLogSearchBar';
|
||||
import Modal from '../../components/common/modal/Modal';
|
||||
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { authList } from '../../store/authList';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
registerLocale('ko', ko);
|
||||
|
||||
const ItemLogContent = () => {
|
||||
const mokupData = [
|
||||
{
|
||||
date: '2023-08-05 12:11:32',
|
||||
name: '칼리버스',
|
||||
id: '16CD2ECD-4798-46CE-9B6B-F952CF11F196',
|
||||
action: '획득',
|
||||
route: '아이템 제작',
|
||||
itemName: 'Item_name',
|
||||
serialNumber: 'Serial_number',
|
||||
itemCode: 'Item_code',
|
||||
count: 1,
|
||||
key: 'User_trade_key',
|
||||
},
|
||||
];
|
||||
return (
|
||||
<>
|
||||
<ItemLogSearchBar />
|
||||
<TableInfo>
|
||||
<ListCount>총 : 117건 / 000 건</ListCount>
|
||||
<ListOption>
|
||||
<SelectInput name="" id="" className="input-select">
|
||||
<option value="up">오름차순</option>
|
||||
<option value="down">내림차순</option>
|
||||
</SelectInput>
|
||||
<SelectInput name="" id="" className="input-select">
|
||||
<option value="up">50개</option>
|
||||
<option value="down">100개</option>
|
||||
</SelectInput>
|
||||
<Button theme="line" text="엑셀 다운로드" />
|
||||
</ListOption>
|
||||
</TableInfo>
|
||||
<TableWrapper>
|
||||
<TableStyle>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="150">일자</th>
|
||||
<th width="200">아바타명</th>
|
||||
<th width="300">GUID</th>
|
||||
<th width="100">액션</th>
|
||||
<th width="150">획득/소진경로</th>
|
||||
<th width="200">아이템명</th>
|
||||
<th width="200">시리얼 넘버</th>
|
||||
<th width="200">고유코드</th>
|
||||
<th width="80">개수</th>
|
||||
<th width="300">거래 key</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{mokupData.map((data, index) => (
|
||||
<Fragment key={index}>
|
||||
<tr>
|
||||
<td>{new Date(data.date).toLocaleString()}</td>
|
||||
<td>{data.name}</td>
|
||||
<td>{data.id}</td>
|
||||
<td>{data.action}</td>
|
||||
<td>{data.route}</td>
|
||||
<td>{data.itemName}e</td>
|
||||
<td>{data.serialNumber}</td>
|
||||
<td>{data.itemCode}</td>
|
||||
<td>{data.count}</td>
|
||||
<td>{data.key}</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
<Pagination />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const GoodsLogContent = () => {
|
||||
const mokupData = [
|
||||
{
|
||||
date: '2023-08-05 12:11:32',
|
||||
name: '홍길동',
|
||||
id: '16CD2ECD-4798-46CE-9B6B-F952CF11F196',
|
||||
gold: '99800',
|
||||
blue: '400',
|
||||
black: '500',
|
||||
red: '500',
|
||||
action: '소진',
|
||||
location: '유저 거래',
|
||||
goldchange: '-',
|
||||
bluechange: '-100',
|
||||
blackchange: '-',
|
||||
redchange: '-',
|
||||
key: 'User_trade_key',
|
||||
},
|
||||
];
|
||||
return (
|
||||
<>
|
||||
<GoodsLogSearchBar />
|
||||
<TableInfo>
|
||||
<ListCount>총 : 117건 / 000 건</ListCount>
|
||||
<ListOption>
|
||||
<SelectInput name="" id="" className="input-select">
|
||||
<option value="up">오름차순</option>
|
||||
<option value="down">내림차순</option>
|
||||
</SelectInput>
|
||||
<SelectInput name="" id="" className="input-select">
|
||||
<option value="up">50개</option>
|
||||
<option value="down">100개</option>
|
||||
</SelectInput>
|
||||
<Button theme="line" text="엑셀 다운로드" />
|
||||
</ListOption>
|
||||
</TableInfo>
|
||||
<TableWrapper>
|
||||
<TableStyle>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="150">일자</th>
|
||||
<th width="200">아바타명</th>
|
||||
<th width="300">GUID</th>
|
||||
<th width="100">
|
||||
(Total)
|
||||
<br />
|
||||
골드
|
||||
</th>
|
||||
<th width="100">
|
||||
(Total)
|
||||
<br />
|
||||
사파이어
|
||||
</th>
|
||||
<th width="100">
|
||||
(Total)
|
||||
<br />
|
||||
칼리움
|
||||
</th>
|
||||
<th width="100">
|
||||
(Total)
|
||||
<br />
|
||||
오닉시움
|
||||
</th>
|
||||
<th width="80">액션</th>
|
||||
<th width="100">획득 / 소진처</th>
|
||||
<th width="100">
|
||||
(변화량)
|
||||
<br />
|
||||
골드
|
||||
</th>
|
||||
<th width="100">
|
||||
(변화량)
|
||||
<br />
|
||||
사파이어
|
||||
</th>
|
||||
<th width="100">
|
||||
(변화량)
|
||||
<br />
|
||||
칼리움
|
||||
</th>
|
||||
<th width="100">
|
||||
(변화량)
|
||||
<br />
|
||||
오닉시움
|
||||
</th>
|
||||
<th width="300">거래 Key</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{mokupData.map((data, index) => (
|
||||
<Fragment key={index}>
|
||||
<tr>
|
||||
<td>{new Date(data.date).toLocaleString()}</td>
|
||||
<td>{data.name}</td>
|
||||
<td>{data.id}</td>
|
||||
<td>{data.gold}</td>
|
||||
<td>{data.blue}</td>
|
||||
<td>{data.black}</td>
|
||||
<td>{data.red}</td>
|
||||
<td>{data.action}</td>
|
||||
<td>{data.location}</td>
|
||||
<td>{data.goldchange}</td>
|
||||
{/* 변화량 0보다 작을 경우 StateDecrease 적용 */}
|
||||
<td>
|
||||
<StateDecrease>{data.bluechange}</StateDecrease>
|
||||
</td>
|
||||
<td>{data.blackchange}</td>
|
||||
<td>{data.redchange}</td>
|
||||
<td>{data.key}</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
<Pagination />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const TradeLogContent = () => {
|
||||
const mokupData = [
|
||||
{
|
||||
date: '2023-08-05 12:11:32',
|
||||
name: '홍길동',
|
||||
trader: '칼리버스',
|
||||
id: '16CD2ECD-4798-46CE-9B6B-F952CF11F196',
|
||||
key: 'User_trade_key',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<TradeLogSerchBar />
|
||||
<TableInfo>
|
||||
<ListCount>
|
||||
총 : 117건 / <span>000</span> 건
|
||||
</ListCount>
|
||||
<ListOption>
|
||||
<SelectInput name="" id="" className="input-select">
|
||||
<option value="up">오름차순</option>
|
||||
<option value="down">내림차순</option>
|
||||
</SelectInput>
|
||||
<SelectInput name="" id="" className="input-select">
|
||||
<option value="up">50개</option>
|
||||
<option value="down">100개</option>
|
||||
</SelectInput>
|
||||
<Button theme="line" text="엑셀 다운로드" />
|
||||
</ListOption>
|
||||
</TableInfo>
|
||||
<TableWrapper>
|
||||
<TableStyle>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="150">일자</th>
|
||||
<th width="150">조회 아바타명</th>
|
||||
<th width="150">거래 대상 아바타명</th>
|
||||
<th width="300">거래 대상 GUID</th>
|
||||
<th width="300">거래 Key</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{mokupData.map((data, index) => (
|
||||
<Fragment key={index}>
|
||||
<tr>
|
||||
<td>{new Date(data.date).toLocaleString()}</td>
|
||||
<td>{data.name}</td>
|
||||
<td>{data.trader}</td>
|
||||
<td>{data.id}</td>
|
||||
<td>{data.key}</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
<Pagination />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const GameLogView = () => {
|
||||
const navigate = useNavigate();
|
||||
const userInfo = useRecoilValue(authList);
|
||||
const [activeTab, setActiveTab] = useState('itemlog');
|
||||
|
||||
const handleTab = (e, content) => {
|
||||
e.preventDefault();
|
||||
setActiveTab(content);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
{userInfo.auth_list && !userInfo.auth_list.some(auth => auth.id === 14) ? (
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={'view'}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={() => navigate(-1)} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">
|
||||
해당 메뉴에 대한 조회 권한이 없습니다.
|
||||
<br />
|
||||
권한 등급을 변경 후 다시 이용해주세요.
|
||||
</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={() => navigate(-1)} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
) : (
|
||||
<>
|
||||
<Title>게임로그조회</Title>
|
||||
<TabWrapper>
|
||||
<li>
|
||||
<TabItem $state={activeTab === 'itemlog' ? 'active' : 'none'} onClick={e => handleTab(e, 'itemlog')}>
|
||||
아이템 로그
|
||||
</TabItem>
|
||||
</li>
|
||||
<li>
|
||||
<TabItem $state={activeTab === 'goodslog' ? 'active' : 'none'} onClick={e => handleTab(e, 'goodslog')}>
|
||||
재화 로그
|
||||
</TabItem>
|
||||
</li>
|
||||
<li>
|
||||
<TabItem $state={activeTab === 'tradelog' ? 'active' : 'none'} onClick={e => handleTab(e, 'tradelog')}>
|
||||
거래 로그
|
||||
</TabItem>
|
||||
</li>
|
||||
</TabWrapper>
|
||||
{activeTab === 'itemlog' && <ItemLogContent />}
|
||||
{activeTab === 'goodslog' && <GoodsLogContent />}
|
||||
{activeTab === 'tradelog' && <TradeLogContent />}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default GameLogView;
|
||||
|
||||
const TabItem = styled(Link)`
|
||||
display: inline-flex;
|
||||
width: 120px;
|
||||
height: 30px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: #f9f9f9;
|
||||
border-left: 1px solid #d9d9d9;
|
||||
&:hover {
|
||||
background: #888;
|
||||
color: #fff;
|
||||
}
|
||||
${props =>
|
||||
props.$state === 'active' &&
|
||||
`
|
||||
background: #888;
|
||||
color: #fff;`}
|
||||
`;
|
||||
|
||||
const TabWrapper = styled.ul`
|
||||
display: flex;
|
||||
li:first-child {
|
||||
${TabItem} {
|
||||
border-left: 0;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const TableWrapper = styled.div`
|
||||
width: 100%;
|
||||
min-width: 680px;
|
||||
overflow: auto;
|
||||
&::-webkit-scrollbar {
|
||||
height: 4px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #666666;
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
background: #d9d9d9;
|
||||
}
|
||||
${TableStyle} {
|
||||
width: 100%;
|
||||
min-width: max-content;
|
||||
}
|
||||
`;
|
||||
|
||||
const StateDecrease = styled.span`
|
||||
color: #d60000;
|
||||
`;
|
||||
238
src/pages/DataManage/LandView.js
Normal file
238
src/pages/DataManage/LandView.js
Normal file
@@ -0,0 +1,238 @@
|
||||
import { styled } from 'styled-components';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Fragment, useRef, useState } from 'react';
|
||||
|
||||
import { Title, TableStyle, BtnWrapper, ButtonClose, ModalText, FormWrapper } from '../../styles/Components';
|
||||
|
||||
import LandSearchBar from '../../components/DataManage/LandSearchBar';
|
||||
import Button from '../../components/common/button/Button';
|
||||
import QuestDetailModal from '../../components/DataManage/QuestDetailModal';
|
||||
import LandDetailModal from '../../components/DataManage/LandDetailModal';
|
||||
import Modal from '../../components/common/modal/Modal';
|
||||
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { authList } from '../../store/authList';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { useDataFetch, useModal, useTable, withAuth } from '../../utils/hook';
|
||||
import { authType, landAuctionStatusType } from '../../assets/data';
|
||||
import { useLandAuctionSearch } from '../../components/ServiceManage/searchBar/LandAuctionSearchBar';
|
||||
import { INITIAL_PAGE_SIZE } from '../../assets/data/adminConstants';
|
||||
import { LandAuctionDelete, LandAuctionDetailView } from '../../apis';
|
||||
import { convertKTC, timeDiffMinute } from '../../utils';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ExcelDownButton, ViewTableInfo } from '../../components/common';
|
||||
import { LandAuctionSearchBar } from '../../components/ServiceManage';
|
||||
|
||||
const LandView = () => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
const navigate = useNavigate();
|
||||
const userInfo = useRecoilValue(authList);
|
||||
const { t } = useTranslation();
|
||||
const tableRef = useRef(null);
|
||||
|
||||
const [detailData, setDetailData] = useState({});
|
||||
|
||||
const {
|
||||
modalState,
|
||||
handleModalView,
|
||||
handleModalClose
|
||||
} = useModal({
|
||||
detail: 'hidden',
|
||||
deleteConfirm: 'hidden',
|
||||
deleteComplete: 'hidden'
|
||||
});
|
||||
const [alertMsg, setAlertMsg] = useState('');
|
||||
const [modalType, setModalType] = useState('regist');
|
||||
|
||||
const {
|
||||
searchParams,
|
||||
data: dataList,
|
||||
handleSearch,
|
||||
handleReset,
|
||||
handlePageChange,
|
||||
handlePageSizeChange,
|
||||
handleOrderByChange,
|
||||
updateSearchParams
|
||||
} = useLandAuctionSearch(token, INITIAL_PAGE_SIZE);
|
||||
|
||||
const {
|
||||
selectedRows,
|
||||
handleSelectRow,
|
||||
isRowSelected
|
||||
} = useTable(dataList?.auction_list || [], {mode: 'single'});
|
||||
|
||||
const {
|
||||
data: landData
|
||||
} = useDataFetch(() => LandView(token), [token]);
|
||||
|
||||
const handleModalSubmit = async (type, param = null) => {
|
||||
switch (type) {
|
||||
// case "regist":
|
||||
// setModalType('regist');
|
||||
// handleModalView('detail');
|
||||
// break;
|
||||
// case "detail":
|
||||
// await LandAuctionDetailView(token, param).then(data => {
|
||||
// setDetailData(data.auction_detail);
|
||||
// setModalType('modify');
|
||||
// handleModalView('detail');
|
||||
// });
|
||||
// break;
|
||||
// case "delete":
|
||||
// const date_check = selectedRows.every(row => {
|
||||
// const timeDiff = timeDiffMinute(convertKTC(row.auction_start_dt), (new Date));
|
||||
// return timeDiff < 3;
|
||||
// });
|
||||
// if(date_check){
|
||||
// setAlertMsg(t('LAND_AUCTION_DELETE_DATE_WARNING'));
|
||||
// return;
|
||||
// }
|
||||
// if(selectedRows[0].status === landAuctionStatusType.auction_start || selectedRows[0].status === landAuctionStatusType.stl_end){
|
||||
// setAlertMsg(t('LAND_AUCTION_DELETE_STATUS_WARNING'));
|
||||
// return;
|
||||
// }
|
||||
// handleModalView('deleteConfirm');
|
||||
// break;
|
||||
// case "deleteConfirm":
|
||||
// let list = [];
|
||||
// let isChecked = false;
|
||||
//
|
||||
// selectedRows.map(data => {
|
||||
// // const row = dataList.list.find(row => row.id === Number(data.id));
|
||||
// // if(row.status !== commonStatus.wait) isChecked = true;
|
||||
// list.push({
|
||||
// id: data.id,
|
||||
// });
|
||||
// });
|
||||
//
|
||||
// if(isChecked) {
|
||||
// setAlertMsg(t('LAND_AUCTION_WARNING_DELETE'))
|
||||
// handleModalClose('deleteConfirm');
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// await LandAuctionDelete(token, list).then(data => {
|
||||
// handleModalClose('deleteConfirm');
|
||||
// if(data.result === "SUCCESS") {
|
||||
// handleModalView('deleteComplete');
|
||||
// }else{
|
||||
// setAlertMsg(t('DELETE_FAIL'));
|
||||
// }
|
||||
// }).catch(reason => {
|
||||
// setAlertMsg(t('API_FAIL'));
|
||||
// });
|
||||
//
|
||||
// break;
|
||||
// case "deleteComplete":
|
||||
// handleModalClose('deleteComplete');
|
||||
// // fetchData(option);
|
||||
// window.location.reload();
|
||||
// break;
|
||||
// case "warning":
|
||||
// setAlertMsg('')
|
||||
// break;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Title>랜드 조회</Title>
|
||||
<FormWrapper>
|
||||
<LandAuctionSearchBar
|
||||
searchParams={searchParams}
|
||||
onSearch={(newParams, executeSearch = true) => {
|
||||
if (executeSearch) {
|
||||
handleSearch(newParams);
|
||||
} else {
|
||||
updateSearchParams(newParams);
|
||||
}
|
||||
}}
|
||||
onReset={handleReset}
|
||||
/>
|
||||
</FormWrapper>
|
||||
<ViewTableInfo total={dataList?.total} total_all={dataList?.total_all} handleOrderBy={handleOrderByChange} handlePageSize={handlePageSizeChange}>
|
||||
<ExcelDownButton tableRef={tableRef} fileName={t('FILE_LAND_AUCTION')} />
|
||||
{userInfo.auth_list?.some(auth => auth.id === authType.landDelete) && (
|
||||
<Button theme={selectedRows.length === 0 ? 'disable' : 'line'} text="선택 삭제" handleClick={() => handleModalSubmit('delete')} />
|
||||
)}
|
||||
{userInfo.auth_list?.some(auth => auth.id === authType.landUpdate) && (
|
||||
<Button
|
||||
theme={selectedRows.length === 0 ? 'disable' : 'line'}
|
||||
text="소유권 변경"
|
||||
type="button"
|
||||
handleClick={e => handleModalSubmit('regist')}
|
||||
/>
|
||||
)}
|
||||
</ViewTableInfo>
|
||||
<TableWrapper>
|
||||
<TableStyle ref={tableRef}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="150">랜드 ID</th>
|
||||
<th>랜드 이름</th>
|
||||
<th>랜드 상태</th>
|
||||
<th>카테고리</th>
|
||||
<th>랜드 크기</th>
|
||||
<th>보유시작일</th>
|
||||
<th width="150">상세보기</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList.map((data, index) => (
|
||||
<Fragment key={index}>
|
||||
<tr>
|
||||
<td>{data.landId}</td>
|
||||
<td>{data.ownerNick}</td>
|
||||
<td>{data.ownerId}</td>
|
||||
<td>{new Date(data.lockInDate).toLocaleString()}</td>
|
||||
<td>
|
||||
<LandLink to={data.landUrl}>{data.landUrl}</LandLink>
|
||||
</td>
|
||||
<td>
|
||||
{/*<Button theme="line" text="상세보기" handleClick={handleClick} />*/}
|
||||
</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
{/*<LandDetailModal detailPop={detailPop} handleClick={handleClick} />*/}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default withAuth(authType.landRead)(LandView);
|
||||
|
||||
const TableWrapper = styled.div`
|
||||
overflow: auto;
|
||||
border-top: 1px solid #000;
|
||||
&::-webkit-scrollbar {
|
||||
height: 4px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #666666;
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
background: #d9d9d9;
|
||||
}
|
||||
thead {
|
||||
th {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
${TableStyle} {
|
||||
min-width: 1000px;
|
||||
th {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const LandLink = styled(Link)`
|
||||
color: #61a2d0;
|
||||
text-decoration: underline;
|
||||
`;
|
||||
162
src/pages/DataManage/UserView.js
Normal file
162
src/pages/DataManage/UserView.js
Normal file
@@ -0,0 +1,162 @@
|
||||
import { useState, Fragment } from 'react';
|
||||
|
||||
import { Title, BtnWrapper, ButtonClose, ModalText } from '../../styles/Components';
|
||||
|
||||
import styled from 'styled-components';
|
||||
|
||||
import UserViewSearchBar from '../../components/DataManage/UserViewSearchBar';
|
||||
import UserDefaultInfo from '../../components/DataManage/UserDefaultInfo';
|
||||
import UserAvatarInfo from '../../components/DataManage/UserAvatarInfo';
|
||||
import UserDressInfo from '../../components/DataManage/UserDressInfo';
|
||||
import UserToolInfo from '../../components/DataManage/UserToolInfo';
|
||||
import UserInventoryInfo from '../../components/DataManage/UserInventoryInfo';
|
||||
import UserMailInfo from '../../components/DataManage/UserMailInfo';
|
||||
import UserMyHomeInfo from '../../components/DataManage/UserMyHomeInfo';
|
||||
import UserFriendInfo from '../../components/DataManage/UserFriendInfo';
|
||||
import UserTatttooInfo from '../../components/DataManage/UserTattooInfo';
|
||||
import UserQuestInfo from '../../components/DataManage/UserQuestInfo';
|
||||
import UserClaimInfo from '../../components/DataManage/UserClaimInfo';
|
||||
import Modal from '../../components/common/modal/Modal';
|
||||
import Button from '../../components/common/button/Button';
|
||||
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { authList } from '../../store/authList';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import AuthModal from '../../components/common/modal/AuthModal';
|
||||
import { authType, TabList } from '../../assets/data';
|
||||
|
||||
const UserView = () => {
|
||||
const navigate = useNavigate();
|
||||
const userInfo = useRecoilValue(authList);
|
||||
|
||||
const [infoView, setInfoView] = useState('none');
|
||||
const [activeContent, setActiveContent] = useState('기본정보');
|
||||
const [resultData, setResultData] = useState([]);
|
||||
|
||||
const handleTab = title => {
|
||||
setActiveContent(title);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{userInfo.auth_list && !userInfo.auth_list.some(auth => auth.id === authType.userSearchRead) ? (
|
||||
<AuthModal />
|
||||
) : (
|
||||
<>
|
||||
<Title>유저조회</Title>
|
||||
<UserViewSearchBar setInfoView={setInfoView} resultData={resultData} handleTab={handleTab} setResultData={setResultData} />
|
||||
<UserWrapper display={infoView}>
|
||||
<TabScroll>
|
||||
<UserTabWrapper>
|
||||
{TabList.map((el, idx) => {
|
||||
return (
|
||||
<UserTab key={idx} $state={el.title === activeContent ? 'active' : 'unactive'} onClick={() => handleTab(el.title)}>
|
||||
{el.title}
|
||||
</UserTab>
|
||||
);
|
||||
})}
|
||||
</UserTabWrapper>
|
||||
</TabScroll>
|
||||
<UserTabInfo>
|
||||
{activeContent === '기본정보' && <UserDefaultInfo userInfo={resultData && resultData} />}
|
||||
{activeContent === '아바타' && <UserAvatarInfo userInfo={resultData && resultData} />}
|
||||
{activeContent === '의상' && <UserDressInfo userInfo={resultData && resultData} />}
|
||||
{activeContent === '도구' && <UserToolInfo userInfo={resultData && resultData} />}
|
||||
{activeContent === '인벤토리' && <UserInventoryInfo userInfo={resultData && resultData} />}
|
||||
{activeContent === '우편' && <UserMailInfo userInfo={resultData && resultData} />}
|
||||
{activeContent === '마이홈' && <UserMyHomeInfo userInfo={resultData && resultData} />}
|
||||
{activeContent === '친구목록' && <UserFriendInfo userInfo={resultData && resultData} />}
|
||||
{activeContent === '타투' && <UserTatttooInfo userInfo={resultData && resultData} />}
|
||||
{activeContent === '퀘스트' && <UserQuestInfo userInfo={resultData && resultData} />}
|
||||
{activeContent === '클레임' && <UserClaimInfo userInfo={resultData && resultData} />}
|
||||
</UserTabInfo>
|
||||
</UserWrapper>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserView;
|
||||
|
||||
const UserTab = styled.li`
|
||||
display: flex;
|
||||
width: 100%;
|
||||
max-width: 120px;
|
||||
height: 35px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-top-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
color: #888;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
background: #888;
|
||||
}
|
||||
${props =>
|
||||
props.$state === 'active' &&
|
||||
`font-weight: 700;
|
||||
color: #fff;
|
||||
background: #888;`}
|
||||
`;
|
||||
const TabScroll = styled.div`
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
`;
|
||||
const UserTabWrapper = styled.ul`
|
||||
border-bottom: 1px solid #888888;
|
||||
display: flex;
|
||||
background: #fff;
|
||||
`;
|
||||
const UserWrapper = styled.div`
|
||||
display: ${props => props.display};
|
||||
${props => props.display && `flex-flow:column;`}
|
||||
min-height: calc(100vh - 345px);
|
||||
overflow: hidden;
|
||||
background: #f9f9f9;
|
||||
`;
|
||||
|
||||
const UserTabInfo = styled.div`
|
||||
padding: 50px;
|
||||
|
||||
overflow: auto;
|
||||
&::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #666666;
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
background: #d9d9d9;
|
||||
}
|
||||
`;
|
||||
|
||||
const UserDefaultTable = styled.table`
|
||||
border: 1px solid #e8eaec;
|
||||
border-top: 1px solid #000;
|
||||
font-size: 14px;
|
||||
margin-bottom: 40px;
|
||||
th {
|
||||
background: #efefef;
|
||||
font-weight: 700;
|
||||
}
|
||||
th,
|
||||
td {
|
||||
padding: 12px;
|
||||
text-align: center;
|
||||
border-left: 1px solid #e8eaec;
|
||||
vertical-align: middle;
|
||||
}
|
||||
td {
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #e8eaec;
|
||||
word-break: break-all;
|
||||
}
|
||||
button {
|
||||
height: 24px;
|
||||
font-size: 13px;
|
||||
}
|
||||
`;
|
||||
4
src/pages/DataManage/index.js
Normal file
4
src/pages/DataManage/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
export { default as UserView } from './UserView';
|
||||
export { default as LandView } from './LandView';
|
||||
export { default as GameLogView } from './GameLogView';
|
||||
export { default as CryptView } from './CryptView';
|
||||
114
src/pages/IndexManage/EconomicIndex.js
Normal file
114
src/pages/IndexManage/EconomicIndex.js
Normal file
@@ -0,0 +1,114 @@
|
||||
import { useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import Button from '../../components/common/button/Button';
|
||||
|
||||
import { Title, BtnWrapper, ButtonClose, ModalText } from '../../styles/Components';
|
||||
import { styled } from 'styled-components';
|
||||
|
||||
import Modal from '../../components/common/modal/Modal';
|
||||
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { authList } from '../../store/authList';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import CreditContent from '../../components/IndexManage/CreditContent';
|
||||
import VBPContent from '../../components/IndexManage/VBPContent';
|
||||
import ItemContent from '../../components/IndexManage/ItemContent';
|
||||
import InstanceContent from '../../components/IndexManage/InstanceContent';
|
||||
import DecoContent from '../../components/IndexManage/DecoContent';
|
||||
|
||||
const EconomicIndex = () => {
|
||||
const navigate = useNavigate();
|
||||
const userInfo = useRecoilValue(authList);
|
||||
const [activeTab, setActiveTab] = useState('credit');
|
||||
|
||||
const handleTab = (e, content) => {
|
||||
e.preventDefault();
|
||||
setActiveTab(content);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
{userInfo.auth_list && !userInfo.auth_list.some(auth => auth.id === 10) ? (
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={'view'}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={() => navigate(-1)} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">
|
||||
해당 메뉴에 대한 조회 권한이 없습니다.
|
||||
<br />
|
||||
권한 등급을 변경 후 다시 이용해주세요.
|
||||
</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={() => navigate(-1)} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
) : (
|
||||
<>
|
||||
<Title>경제 지표</Title>
|
||||
<TabWrapper>
|
||||
<li>
|
||||
<TabItem $state={activeTab === 'credit' ? 'active' : 'none'} onClick={e => handleTab(e, 'credit')}>
|
||||
재화
|
||||
</TabItem>
|
||||
</li>
|
||||
<li>
|
||||
<TabItem $state={activeTab === 'vbp' ? 'active' : 'none'} onClick={e => handleTab(e, 'vbp')}>
|
||||
VBP
|
||||
</TabItem>
|
||||
</li>
|
||||
<li>
|
||||
<TabItem $state={activeTab === 'item' ? 'active' : 'none'} onClick={e => handleTab(e, 'item')}>
|
||||
아이템
|
||||
</TabItem>
|
||||
</li>
|
||||
<li>
|
||||
<TabItem $state={activeTab === 'instance' ? 'active' : 'none'} onClick={e => handleTab(e, 'instance')}>
|
||||
인스턴스
|
||||
</TabItem>
|
||||
</li>
|
||||
<li>
|
||||
<TabItem $state={activeTab === 'deco' ? 'active' : 'none'} onClick={e => handleTab(e, 'deco')}>
|
||||
의상 / 타투
|
||||
</TabItem>
|
||||
</li>
|
||||
</TabWrapper>
|
||||
{activeTab === 'credit' && <CreditContent />}
|
||||
{activeTab === 'vbp' && <VBPContent />}
|
||||
{activeTab === 'item' && <ItemContent />}
|
||||
{activeTab === 'instance' && <InstanceContent />}
|
||||
{activeTab === 'deco' && <DecoContent />}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default EconomicIndex;
|
||||
|
||||
const TabItem = styled(Link)`
|
||||
display: inline-flex;
|
||||
width: 120px;
|
||||
height: 30px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: #f9f9f9;
|
||||
border-left: 1px solid #d9d9d9;
|
||||
&:hover {
|
||||
background: #888;
|
||||
color: #fff;
|
||||
}
|
||||
${props =>
|
||||
props.$state === 'active' &&
|
||||
`background: #888;
|
||||
color: #fff;`}
|
||||
`;
|
||||
|
||||
const TabWrapper = styled.ul`
|
||||
display: flex;
|
||||
li:first-child {
|
||||
${TabItem} {
|
||||
border-left: 0;
|
||||
}
|
||||
}
|
||||
`;
|
||||
103
src/pages/IndexManage/UserIndex.js
Normal file
103
src/pages/IndexManage/UserIndex.js
Normal file
@@ -0,0 +1,103 @@
|
||||
import { Fragment, useEffect, useState } from 'react';
|
||||
import { styled } from 'styled-components';
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import Modal from '../../components/common/modal/Modal';
|
||||
import Button from '../../components/common/button/Button';
|
||||
|
||||
import { Title, BtnWrapper, ButtonClose, ModalText } from '../../styles/Components';
|
||||
|
||||
import { authList } from '../../store/authList';
|
||||
import { userIndexView, userTotalIndex } from '../../apis';
|
||||
|
||||
import { UserContent, SegmentContent, PlayTimeContent, RetentionContent, DailyActiveUserContent, DailyMedalContent } from '../../components/IndexManage/index';
|
||||
import AuthModal from '../../components/common/modal/AuthModal';
|
||||
import { authType } from '../../assets/data';
|
||||
|
||||
const UserIndex = () => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
const navigate = useNavigate();
|
||||
|
||||
const userInfo = useRecoilValue(authList);
|
||||
const [activeTab, setActiveTab] = useState('이용자 지표');
|
||||
|
||||
const handleTab = (e, content) => {
|
||||
// e.preventDefault();
|
||||
setActiveTab(content);
|
||||
};
|
||||
|
||||
const TabList = [
|
||||
{ title: '이용자 지표' },
|
||||
// { title: 'Retention' },
|
||||
// { title: 'Segment' },
|
||||
// { title: '플레이타임' },
|
||||
// { title: 'DAU' },
|
||||
// { title: '메달' },
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
{userInfo.auth_list && !userInfo.auth_list.some(auth => auth.id === authType.userIndicatorsRead) ? (
|
||||
<AuthModal/>
|
||||
) : (
|
||||
<>
|
||||
<Title>유저 지표</Title>
|
||||
<TabWrapper>
|
||||
{TabList.map((el, idx) => {
|
||||
return (
|
||||
<TabItem
|
||||
key={idx}
|
||||
$state={el.title === activeTab ? 'active' : 'unactive'}
|
||||
onClick={(e) => handleTab(e, el.title)}
|
||||
>
|
||||
{el.title}
|
||||
</TabItem>
|
||||
);
|
||||
})}
|
||||
</TabWrapper>
|
||||
|
||||
{/*{activeTab === 'DAU' && <DailyActiveUserContent />}*/}
|
||||
{activeTab === '이용자 지표' && <UserContent />}
|
||||
{activeTab === 'Retention' && <RetentionContent />}
|
||||
{activeTab === 'Segment' && <SegmentContent />}
|
||||
{activeTab === '플레이타임' && <PlayTimeContent />}
|
||||
{/*{activeTab === '메달' && <DailyMedalContent />}*/}
|
||||
|
||||
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserIndex;
|
||||
|
||||
const TabItem = styled(Link)`
|
||||
display: inline-flex;
|
||||
width: 120px;
|
||||
height: 30px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: #f9f9f9;
|
||||
border-left: 1px solid #d9d9d9;
|
||||
&:hover {
|
||||
background: #888;
|
||||
color: #fff;
|
||||
}
|
||||
${props =>
|
||||
props.$state === 'active' &&
|
||||
`
|
||||
background: #888;
|
||||
color: #fff;`}
|
||||
`;
|
||||
|
||||
const TabWrapper = styled.ul`
|
||||
display: flex;
|
||||
li:first-child {
|
||||
${TabItem} {
|
||||
border-left: 0;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
2
src/pages/IndexManage/index.js
Normal file
2
src/pages/IndexManage/index.js
Normal file
@@ -0,0 +1,2 @@
|
||||
export { default as UserIndex } from './UserIndex';
|
||||
export { default as EconomicIndex } from './EconomicIndex';
|
||||
77
src/pages/Login/Login.js
Normal file
77
src/pages/Login/Login.js
Normal file
@@ -0,0 +1,77 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { Link, Navigate } from 'react-router-dom';
|
||||
import { LoginForm, LoginInfo } from '../../components/login';
|
||||
|
||||
import LogoUrl from '../../assets/img/logo.png';
|
||||
|
||||
const Login = () => {
|
||||
const isToken = sessionStorage.getItem('token') ? true : false;
|
||||
|
||||
return (
|
||||
<>
|
||||
{isToken ? (
|
||||
<Navigate to="/main" replace={true} />
|
||||
) : (
|
||||
<FormBox>
|
||||
<Logo src={LogoUrl} alt="caliverse" />
|
||||
<LoginTitle>ADMIN LOGIN</LoginTitle>
|
||||
<LoginForm />
|
||||
<JoinButton to="/account/regist">회원가입</JoinButton>
|
||||
{/* <Divider>|</Divider>
|
||||
<PwdButton to="/account/pwdreset">비밀번호 찾기</PwdButton> */}
|
||||
<LoginInfo />
|
||||
</FormBox>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Login;
|
||||
|
||||
const Divider = styled.span`
|
||||
margin: 0 8px;
|
||||
color: RGB(217,217,217);
|
||||
padding: 4px 0;
|
||||
`;
|
||||
|
||||
const PwdButton = styled(Link)`
|
||||
text-decoration: underline;
|
||||
font-size: 14px;
|
||||
margin: 28px 0;
|
||||
border-radius: 0;
|
||||
color: #8d8d8d;
|
||||
`;
|
||||
|
||||
const JoinButton = styled(Link)`
|
||||
text-decoration: underline;
|
||||
font-size: 14px;
|
||||
margin: 28px 0;
|
||||
border-radius: 0;
|
||||
color: #8d8d8d;
|
||||
`;
|
||||
|
||||
const FormBox = styled.div`
|
||||
background: #fff;
|
||||
width: 486px;
|
||||
padding: 75px 45px;
|
||||
text-align: center;
|
||||
border-radius: 30px;
|
||||
`;
|
||||
|
||||
const Logo = styled.img`
|
||||
display: block;
|
||||
margin: auto;
|
||||
`;
|
||||
|
||||
const LoginTitle = styled.span`
|
||||
background: #ececec;
|
||||
border-radius: 50px;
|
||||
color: #adadad;
|
||||
margin-top: 40px;
|
||||
font-size: 12px;
|
||||
display: inline-block;
|
||||
width: 110px;
|
||||
padding: 5px 10px;
|
||||
letter-spacing: 1px;
|
||||
`;
|
||||
1
src/pages/Login/index.js
Normal file
1
src/pages/Login/index.js
Normal file
@@ -0,0 +1 @@
|
||||
export { default as Login } from './Login';
|
||||
182
src/pages/LoginFail.js
Normal file
182
src/pages/LoginFail.js
Normal file
@@ -0,0 +1,182 @@
|
||||
import { useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Button from '../components/common/button/Button';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { TextInput, BtnWrapper, ButtonClose, Title } from '../styles/Components';
|
||||
import LogoUrl from '../assets/img/logo.png';
|
||||
|
||||
import Modal from '../components/common/modal/Modal';
|
||||
|
||||
const LoginFail = () => {
|
||||
const [userId, setUserId] = useState('');
|
||||
const [userPw, setUserPw] = useState('');
|
||||
const [stateModal, setStateModal] = useState('hidden');
|
||||
const handleModal = () => {
|
||||
if (stateModal === 'hidden') {
|
||||
setStateModal('view');
|
||||
} else {
|
||||
setStateModal('hidden');
|
||||
}
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<FormBox>
|
||||
<Logo src={LogoUrl} alt="caliverse" />
|
||||
<LoginTitle>ADMIN LOGIN</LoginTitle>
|
||||
<FormWrapper action="" $flow="column">
|
||||
<InputWrapper>
|
||||
<TextInput fontSize="15px" $padding="16px 20px" name="userid" placeholder="ID를 입력하세요(test@test.co.kr)" value={userId} onChange={e => setUserId(e.target.value)} />
|
||||
<TextInput fontSize="15px" $padding="16px 20px" name="password" id="userpw" placeholder="비밀번호를 입력하세요" value={userPw} onChange={e => setUserPw(e.target.value)} />
|
||||
</InputWrapper>
|
||||
<Button
|
||||
type="submit"
|
||||
theme="primary"
|
||||
size="large"
|
||||
text="로그인"
|
||||
width="100%"
|
||||
handleClick={e => {
|
||||
e.preventDefault();
|
||||
//window.location.href = '/account/edit';
|
||||
handleModal();
|
||||
}}
|
||||
/>
|
||||
</FormWrapper>
|
||||
<JoinButton to="/account/regist">회원가입</JoinButton>
|
||||
<LoginInfo>
|
||||
<LoginInfoItem>- 관리자 승인된 계정으로 접속하실 수 있습니다.</LoginInfoItem>
|
||||
<LoginInfoItem>
|
||||
- 로그인 오류 및 비밀번호 재설정은 <Link to="mailto:admin@caliverse.co.kr">admin@caliverse.co.kr</Link>로 문의바랍니다.
|
||||
</LoginInfoItem>
|
||||
</LoginInfo>
|
||||
</FormBox>
|
||||
<Modal $view={stateModal} min="440px" $padding="40px">
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleModal} />
|
||||
</BtnWrapper>
|
||||
<Title $align="center">로그인 실패</Title>
|
||||
<NoticeSummary $maxwidth="400px">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>사유</th>
|
||||
<td>비밀번호 기간 만료</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>만료일</th>
|
||||
<td>2023-07-24</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</NoticeSummary>
|
||||
<NoticeDetail $align="center">
|
||||
비밀번호 기간 갱신은 관리자 메일을 통해
|
||||
<br />
|
||||
문의해주시기 바랍니다.
|
||||
<br />
|
||||
<br />
|
||||
관리자 문의 : caliverse@caliverse.com
|
||||
</NoticeDetail>
|
||||
<Button
|
||||
text="확인"
|
||||
theme="line"
|
||||
handleClick={e => {
|
||||
e.preventDefault();
|
||||
window.location.href = '/account/edit';
|
||||
}}
|
||||
/>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginFail;
|
||||
|
||||
const JoinButton = styled(Link)`
|
||||
text-decoration: underline;
|
||||
font-size: 14px;
|
||||
margin: 28px 0;
|
||||
border-radius: 0;
|
||||
`;
|
||||
|
||||
const FormBox = styled.div`
|
||||
background: #fff;
|
||||
width: 486px;
|
||||
padding: 75px 45px;
|
||||
text-align: center;
|
||||
border-radius: 30px;
|
||||
color: #8d8d8d;
|
||||
`;
|
||||
|
||||
const Logo = styled.img`
|
||||
display: block;
|
||||
margin: auto;
|
||||
`;
|
||||
|
||||
const LoginTitle = styled.span`
|
||||
background: #ececec;
|
||||
border-radius: 50px;
|
||||
color: #adadad;
|
||||
margin-top: 40px;
|
||||
font-size: 12px;
|
||||
display: inline-block;
|
||||
width: 110px;
|
||||
padding: 5px 10px;
|
||||
letter-spacing: 1px;
|
||||
`;
|
||||
|
||||
const FormWrapper = styled.form`
|
||||
margin-top: 40px;
|
||||
`;
|
||||
|
||||
const InputWrapper = styled.div`
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
gap: 6px;
|
||||
margin-bottom: 20px;
|
||||
`;
|
||||
|
||||
const LoginInfo = styled.ul`
|
||||
text-align: left;
|
||||
`;
|
||||
const LoginInfoItem = styled.li`
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
word-break: keep-all;
|
||||
padding-left: 10px;
|
||||
text-indent: -10px;
|
||||
a {
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
display: inline-block;
|
||||
word-break: break-all;
|
||||
border-radius: 0;
|
||||
text-indent: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
const NoticeSummary = styled.div`
|
||||
border-top: 1px solid #000;
|
||||
border-bottom: 1px solid #000;
|
||||
padding: 20px 40px;
|
||||
margin-bottom: 20px;
|
||||
max-width: ${props => props.$maxwidth || 'auto'};
|
||||
table {
|
||||
th {
|
||||
text-align: left;
|
||||
font-weight: 600;
|
||||
}
|
||||
th,
|
||||
td {
|
||||
padding: 8px 0;
|
||||
}
|
||||
}
|
||||
`;
|
||||
const NoticeDetail = styled.div`
|
||||
background: #f6f6f6;
|
||||
padding: 30px 20px;
|
||||
margin-bottom: 20px;
|
||||
line-height: 2;
|
||||
text-align: ${props => props.$align || 'left'};
|
||||
`;
|
||||
100
src/pages/Main.js
Normal file
100
src/pages/Main.js
Normal file
@@ -0,0 +1,100 @@
|
||||
import { styled } from 'styled-components';
|
||||
import { useState, useEffect } from 'react';
|
||||
import MainLogo from '../assets/img/logo-main.png';
|
||||
import PasswordAlertModal from '../components/account/PasswordAlertModal';
|
||||
import { AuthInfo } from '../apis/Auth';
|
||||
import { Navigate } from 'react-router-dom';
|
||||
|
||||
const Main = () => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
|
||||
const [passwordModal, setPasswordModal] = useState('hidden');
|
||||
const homeVisited = localStorage.getItem('homeVisited');
|
||||
|
||||
useEffect(() => {
|
||||
if (homeVisited) {
|
||||
new Date(homeVisited) < new Date() && handleExpiredPassword();
|
||||
} else {
|
||||
handleExpiredPassword();
|
||||
}
|
||||
}, []); // 비밀번호 만료 알림 모달 날짜 계산
|
||||
|
||||
const handleExpiredPassword = async () => {
|
||||
const today = new Date();
|
||||
const guideDate = new Date(today);
|
||||
guideDate.setDate(today.getDate() + 30);
|
||||
|
||||
const userInfo = await AuthInfo(token);
|
||||
|
||||
userInfo && new Date(userInfo.expiredDt) < new Date(guideDate) && handlePasswordModal();
|
||||
};
|
||||
|
||||
// 비밀번호 재설정 모달창
|
||||
const handlePasswordModal = () => {
|
||||
if (passwordModal === 'hidden') {
|
||||
setPasswordModal('view');
|
||||
} else {
|
||||
setPasswordModal('hidden');
|
||||
}
|
||||
};
|
||||
return (
|
||||
<>
|
||||
{token ? (
|
||||
<>
|
||||
<MainWrapper>
|
||||
<IntroBox>
|
||||
<span>Welcome To</span>
|
||||
<img src={MainLogo} alt="" />
|
||||
<div>운영툴 관리 메뉴를 선택해주세요</div>
|
||||
</IntroBox>
|
||||
</MainWrapper>
|
||||
{/* 비빌번호 만료 안내 */}
|
||||
<PasswordAlertModal stateModal={passwordModal} handleModal={handlePasswordModal} />
|
||||
</>
|
||||
) : (
|
||||
<Navigate to="/" replace={true} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Main;
|
||||
|
||||
const MainWrapper = styled.div`
|
||||
width: 100%;
|
||||
height: calc(100vh - 58px);
|
||||
background: rgba(246, 246, 246, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
&:before {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 400px;
|
||||
height: 510px;
|
||||
/* background: #fff; */
|
||||
position: absolute;
|
||||
}
|
||||
`;
|
||||
|
||||
const IntroBox = styled.div`
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
align-items: center;
|
||||
font-weight: 600;
|
||||
font-size: 18px;
|
||||
color: #666;
|
||||
span {
|
||||
font-size: 30px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 10px;
|
||||
color: #d9d9d9;
|
||||
display: inline-block;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
img {
|
||||
margin-bottom: 80px;
|
||||
}
|
||||
`;
|
||||
281
src/pages/ServiceManage/BattleEvent.js
Normal file
281
src/pages/ServiceManage/BattleEvent.js
Normal file
@@ -0,0 +1,281 @@
|
||||
import { useState, Fragment, useRef } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import 'react-datepicker/dist/react-datepicker.css';
|
||||
|
||||
import {
|
||||
BattleConfigView,
|
||||
BattleEventDelete,
|
||||
BattleEventDetailView,
|
||||
BattleEventView,
|
||||
BattleRewardView,
|
||||
} from '../../apis/Battle';
|
||||
|
||||
import { authList } from '../../store/authList';
|
||||
import {
|
||||
authType,
|
||||
modalTypes,
|
||||
landAuctionStatusType,
|
||||
landAuctionStatus,
|
||||
landSize,
|
||||
caliumStatus, commonStatus,
|
||||
} from '../../assets/data';
|
||||
import { Title, FormWrapper, TableStyle, TableWrapper} from '../../styles/Components';
|
||||
import {
|
||||
CheckBox,
|
||||
Button,
|
||||
DynamicModal,
|
||||
Pagination,
|
||||
ViewTableInfo, ExcelDownButton,
|
||||
} from '../../components/common';
|
||||
import { convertKTC, timeDiffMinute } from '../../utils';
|
||||
import { BattleEventModal, LandAuctionModal, LandAuctionSearchBar } from '../../components/ServiceManage';
|
||||
import { INITIAL_PAGE_SIZE, INITIAL_PAGE_LIMIT } from '../../assets/data/adminConstants';
|
||||
import { useDataFetch, useModal, useTable, withAuth } from '../../utils/hook';
|
||||
import { useLandAuctionSearch } from '../../components/ServiceManage/searchBar/LandAuctionSearchBar';
|
||||
import { StatusWapper, StatusLabel } from '../../styles/ModuleComponents';
|
||||
import { battleEventStatus, battleRepeatType } from '../../assets/data/options';
|
||||
import BattleEventSearchBar, {
|
||||
useBattleEventSearch,
|
||||
} from '../../components/ServiceManage/searchBar/BattleEventSearchBar';
|
||||
import { getTimeOnly } from '../../utils/date';
|
||||
|
||||
const BattleEvent = () => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
const userInfo = useRecoilValue(authList);
|
||||
const { t } = useTranslation();
|
||||
const tableRef = useRef(null);
|
||||
|
||||
const [detailData, setDetailData] = useState({});
|
||||
|
||||
const {
|
||||
modalState,
|
||||
handleModalView,
|
||||
handleModalClose
|
||||
} = useModal({
|
||||
detail: 'hidden',
|
||||
deleteConfirm: 'hidden',
|
||||
deleteComplete: 'hidden'
|
||||
});
|
||||
const [alertMsg, setAlertMsg] = useState('');
|
||||
const [modalType, setModalType] = useState('regist');
|
||||
|
||||
const {
|
||||
searchParams,
|
||||
data: dataList,
|
||||
handleSearch,
|
||||
handleReset,
|
||||
handlePageChange,
|
||||
handlePageSizeChange,
|
||||
handleOrderByChange,
|
||||
updateSearchParams
|
||||
} = useBattleEventSearch(token, INITIAL_PAGE_SIZE);
|
||||
|
||||
const {
|
||||
selectedRows,
|
||||
handleSelectRow,
|
||||
isRowSelected
|
||||
} = useTable(dataList?.event_list || [], {mode: 'single'});
|
||||
|
||||
const {
|
||||
data: battleConfigData
|
||||
} = useDataFetch(() => BattleConfigView(token), [token]);
|
||||
|
||||
const {
|
||||
data: battleRewardData
|
||||
} = useDataFetch(() => BattleRewardView(token), [token]);
|
||||
|
||||
const handleModalSubmit = async (type, param = null) => {
|
||||
switch (type) {
|
||||
case "regist":
|
||||
setModalType('regist');
|
||||
handleModalView('detail');
|
||||
break;
|
||||
case "detail":
|
||||
await BattleEventDetailView(token, param).then(data => {
|
||||
setDetailData(data.event_detail);
|
||||
setModalType('modify');
|
||||
handleModalView('detail');
|
||||
});
|
||||
break;
|
||||
case "delete":
|
||||
const date_check = selectedRows.every(row => {
|
||||
const timeDiff = timeDiffMinute(convertKTC(row.auction_start_dt), (new Date));
|
||||
return timeDiff < 3;
|
||||
});
|
||||
if(date_check){
|
||||
setAlertMsg(t('LAND_AUCTION_DELETE_DATE_WARNING'));
|
||||
return;
|
||||
}
|
||||
if(selectedRows[0].status === landAuctionStatusType.auction_start || selectedRows[0].status === landAuctionStatusType.stl_end){
|
||||
setAlertMsg(t('LAND_AUCTION_DELETE_STATUS_WARNING'));
|
||||
return;
|
||||
}
|
||||
handleModalView('deleteConfirm');
|
||||
break;
|
||||
case "deleteConfirm":
|
||||
let list = [];
|
||||
let isChecked = false;
|
||||
|
||||
selectedRows.map(data => {
|
||||
// const row = dataList.list.find(row => row.id === Number(data.id));
|
||||
// if(row.status !== commonStatus.wait) isChecked = true;
|
||||
list.push({
|
||||
id: data.id,
|
||||
});
|
||||
});
|
||||
|
||||
if(isChecked) {
|
||||
setAlertMsg(t('LAND_AUCTION_WARNING_DELETE'))
|
||||
handleModalClose('deleteConfirm');
|
||||
return;
|
||||
}
|
||||
|
||||
await BattleEventDelete(token, list).then(data => {
|
||||
handleModalClose('deleteConfirm');
|
||||
if(data.result === "SUCCESS") {
|
||||
handleModalView('deleteComplete');
|
||||
}else if(data.result === "ERROR_AUCTION_STATUS_IMPOSSIBLE"){
|
||||
setAlertMsg(t('LAND_AUCTION_ERROR_DELETE_STATUS'));
|
||||
}else{
|
||||
setAlertMsg(t('DELETE_FAIL'));
|
||||
}
|
||||
}).catch(reason => {
|
||||
setAlertMsg(t('API_FAIL'));
|
||||
});
|
||||
|
||||
break;
|
||||
case "deleteComplete":
|
||||
handleModalClose('deleteComplete');
|
||||
// fetchData(option);
|
||||
window.location.reload();
|
||||
break;
|
||||
case "warning":
|
||||
setAlertMsg('')
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Title>전투시스템 타임 스케줄러</Title>
|
||||
<FormWrapper>
|
||||
<BattleEventSearchBar
|
||||
searchParams={searchParams}
|
||||
onSearch={(newParams, executeSearch = true) => {
|
||||
if (executeSearch) {
|
||||
handleSearch(newParams);
|
||||
} else {
|
||||
updateSearchParams(newParams);
|
||||
}
|
||||
}}
|
||||
onReset={handleReset}
|
||||
/>
|
||||
</FormWrapper>
|
||||
<ViewTableInfo total={dataList?.total} total_all={dataList?.total_all} handleOrderBy={handleOrderByChange} handlePageSize={handlePageSizeChange}>
|
||||
<ExcelDownButton tableRef={tableRef} fileName={t('FILE_BATTLE_EVENT')} />
|
||||
{userInfo.auth_list?.some(auth => auth.id === authType.battleEventDelete) && (
|
||||
<Button theme={selectedRows.length === 0 ? 'disable' : 'line'} text="이벤트 중단" handleClick={() => handleModalSubmit('delete')} />
|
||||
)}
|
||||
{userInfo.auth_list?.some(auth => auth.id === authType.battleEventUpdate) && (
|
||||
<Button
|
||||
theme="primary"
|
||||
text="이벤트 등록"
|
||||
type="button"
|
||||
handleClick={e => handleModalSubmit('regist')}
|
||||
/>
|
||||
)}
|
||||
</ViewTableInfo>
|
||||
<TableWrapper>
|
||||
<TableStyle ref={tableRef}>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="40"></th>
|
||||
<th width="90">그룹</th>
|
||||
<th width="60">이벤트 ID</th>
|
||||
<th width="150">이벤트명</th>
|
||||
<th width="80">반복</th>
|
||||
<th width="120">이벤트 시작시간</th>
|
||||
<th width="120">이벤트 종료시간</th>
|
||||
<th width="90">이벤트 상태</th>
|
||||
<th width="90">라운드 시간</th>
|
||||
<th width="80">라운드 수</th>
|
||||
<th width="80">핫타임</th>
|
||||
<th width="200">기간 시작일</th>
|
||||
<th width="200">기간 종료일</th>
|
||||
<th width="100">확인 / 수정</th>
|
||||
<th width="150">히스토리</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList?.event_list?.map(battle => (
|
||||
<tr key={battle.row_num}>
|
||||
<td>
|
||||
<CheckBox name={'select'} id={battle.id}
|
||||
setData={(e) => handleSelectRow(e, battle)}
|
||||
checked={isRowSelected(battle.id)} />
|
||||
</td>
|
||||
<td>{battle.group_id}</td>
|
||||
<td>{battle.id}</td>
|
||||
<td>{battle.event_name}</td>
|
||||
<StatusWapper>
|
||||
<StatusLabel $status={battle.repeat_type}>
|
||||
{battleRepeatType.find(data => data.value === battle.repeat_type).name}
|
||||
</StatusLabel>
|
||||
</StatusWapper>
|
||||
<td>{getTimeOnly(battle.event_start_dt)}</td>
|
||||
<td>{battle.end_time}</td>
|
||||
<StatusWapper>
|
||||
<StatusLabel $status={battle.status}>
|
||||
{battleEventStatus.find(data => data.value === battle.status).name}
|
||||
</StatusLabel>
|
||||
</StatusWapper>
|
||||
<td>{battle.round_time}</td>
|
||||
<td>{battle.round_count}</td>
|
||||
<td>{battle.hot_time}</td>
|
||||
<td>{convertKTC(battle.event_start_dt)}</td>
|
||||
<td>{convertKTC(battle.event_end_dt)}</td>
|
||||
<td>
|
||||
<Button theme="line" text="상세보기"
|
||||
handleClick={e => handleModalSubmit('detail', battle.id)} />
|
||||
</td>
|
||||
<td>{battle.update_by}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
|
||||
<Pagination postsPerPage={searchParams.pageSize} totalPosts={dataList?.total_all} setCurrentPage={handlePageChange} currentPage={searchParams.currentPage} pageLimit={INITIAL_PAGE_LIMIT} />
|
||||
|
||||
{/*상세*/}
|
||||
<BattleEventModal modalType={modalType} detailView={modalState.detailModal} handleDetailView={() => handleModalClose('detail')} content={detailData} setDetailData={setDetailData} configData={battleConfigData} rewardData={battleRewardData} />
|
||||
|
||||
{/*삭제 확인*/}
|
||||
<DynamicModal
|
||||
modalType={modalTypes.confirmOkCancel}
|
||||
view={modalState.deleteConfirmModal}
|
||||
handleCancel={() => handleModalClose('deleteConfirm')}
|
||||
handleSubmit={() => handleModalSubmit('deleteConfirm')}
|
||||
modalText={t('LAND_AUCTION_SELECT_DELETE')}
|
||||
/>
|
||||
{/*삭제 완료*/}
|
||||
<DynamicModal
|
||||
modalType={modalTypes.completed}
|
||||
view={modalState.deleteCompleteModal}
|
||||
handleSubmit={() => handleModalSubmit('deleteComplete')}
|
||||
modalText={t('DEL_COMPLETE')}
|
||||
/>
|
||||
{/* 경고 모달 */}
|
||||
<DynamicModal
|
||||
modalType={modalTypes.completed}
|
||||
view={alertMsg ? 'view' : 'hidden'}
|
||||
modalText={alertMsg}
|
||||
handleSubmit={() => handleModalSubmit('warning')}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
};
|
||||
|
||||
export default withAuth(authType.battleEventRead)(BattleEvent);
|
||||
265
src/pages/ServiceManage/Board.js
Normal file
265
src/pages/ServiceManage/Board.js
Normal file
@@ -0,0 +1,265 @@
|
||||
import { Fragment, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import Button from '../../components/common/button/Button';
|
||||
import CheckBox from '../../components/common/input/CheckBox';
|
||||
import Modal from '../../components/common/modal/Modal';
|
||||
|
||||
import styled from 'styled-components';
|
||||
import {
|
||||
Title,
|
||||
TableWrapper,
|
||||
BtnWrapper,
|
||||
TableInfo,
|
||||
ListOption,
|
||||
TableStyle,
|
||||
ButtonClose,
|
||||
ModalText,
|
||||
DetailMessage,
|
||||
} from '../../styles/Components';
|
||||
|
||||
import { NoticeDelete, NoticeDetailView, NoticeListView } from '../../apis/Notice';
|
||||
import { BoardInfoModal, BoardRegistModal } from '../../components/ServiceManage';
|
||||
import { authList } from '../../store/authList';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { convertKTC } from '../../utils';
|
||||
import AuthModal from '../../components/common/modal/AuthModal';
|
||||
import { authType } from '../../assets/data';
|
||||
|
||||
const Board = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const token = sessionStorage.getItem('token');
|
||||
const userInfo = useRecoilValue(authList);
|
||||
|
||||
const [isCopyData, setIsCopyData] = useState(false);
|
||||
|
||||
const [dataList, setDataList] = useState([]);
|
||||
const [detailView, setDetailView] = useState('hidden');
|
||||
const [registView, setRegistView] = useState('hidden');
|
||||
const [detailData, setDetailData] = useState('');
|
||||
const [detailId, setDetailId] = useState('');
|
||||
const [selectedRow, setSelectedRow] = useState([]);
|
||||
const [deleteModalClose, setDeleteModalClose] = useState('hidden');
|
||||
const [confirmModalClose, setConfirmModalClose] = useState('hidden');
|
||||
|
||||
const message_type = [
|
||||
{ value: 'CHATTING', name: '채팅 타입' },
|
||||
{ value: 'CHATTING_TOAST', name: '채팅 + 토스트' },
|
||||
];
|
||||
|
||||
const sendStatus = [
|
||||
{ value: 'WAIT', name: '대기' },
|
||||
{ value: 'RUNNING', name: '송출중' },
|
||||
{ value: 'FINISH', name: '완료' },
|
||||
{ value: 'FAIL', name: '실패' },
|
||||
];
|
||||
|
||||
const fetchData = async () => {
|
||||
setDataList(await NoticeListView(token));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
// 체크박스 선택 리스트
|
||||
const handleSelectCheckBox = e => {
|
||||
let list = [...selectedRow];
|
||||
if (e.target.checked) {
|
||||
list.push(e.target.id);
|
||||
setSelectedRow(list);
|
||||
} else {
|
||||
const filterList = list.filter(data => e.target.id !== data);
|
||||
setSelectedRow(filterList);
|
||||
}
|
||||
};
|
||||
|
||||
// 전체 선택 구현
|
||||
const handleAllSelect = () => {
|
||||
let list = [];
|
||||
if (document.getElementById('check-all').checked === true) {
|
||||
dataList.map((data, index) => {
|
||||
document.getElementsByName('select')[index].checked = true;
|
||||
list.push(String(data.id));
|
||||
});
|
||||
} else if (document.getElementById('check-all').checked === false) {
|
||||
for (let i = 0; i < dataList.length; i++) {
|
||||
dataList.map((data, index) => (document.getElementsByName('select')[index].checked = false));
|
||||
list = [];
|
||||
}
|
||||
}
|
||||
setSelectedRow(list);
|
||||
};
|
||||
|
||||
// 선택 삭제 함수
|
||||
const handleSelectedDelete = () => {
|
||||
let list = [];
|
||||
|
||||
selectedRow.map(data =>
|
||||
list.push({
|
||||
message_id: data,
|
||||
}),
|
||||
);
|
||||
NoticeDelete(token, list);
|
||||
|
||||
handleDeleteModalClose();
|
||||
handleConfirmeModalClose();
|
||||
};
|
||||
|
||||
// 선택 삭제 모달
|
||||
const handleDeleteModalClose = () => {
|
||||
if (selectedRow.length !== 0 && deleteModalClose === 'hidden') {
|
||||
setDeleteModalClose('view');
|
||||
} else {
|
||||
setDeleteModalClose('hidden');
|
||||
}
|
||||
};
|
||||
|
||||
// 삭제, 승인, 저장 확인 모달창
|
||||
const handleConfirmeModalClose = () => {
|
||||
if (confirmModalClose === 'hidden') {
|
||||
setConfirmModalClose('view');
|
||||
} else {
|
||||
setConfirmModalClose('hidden');
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
const handleDetailModal = async (e, id) => {
|
||||
setDetailData(await NoticeDetailView(token, id));
|
||||
setDetailId(id);
|
||||
|
||||
e.preventDefault();
|
||||
setDetailView('view');
|
||||
};
|
||||
|
||||
const handleCountSelectedRow = () => {
|
||||
return dataList && document.querySelectorAll('input[name="select"]:checked').length === dataList.length;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{userInfo.auth_list && !userInfo.auth_list.some(auth => auth.id === authType.inGameRead) ? (
|
||||
<AuthModal/>
|
||||
) : (
|
||||
<>
|
||||
<Title>인게임 메시지</Title>
|
||||
<TableInfo>
|
||||
<ListOption>
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === authType.inGameDelete) && (
|
||||
<Button theme={selectedRow.length === 0 ? 'disable' : 'line'} text="선택 삭제" handleClick={handleDeleteModalClose} />
|
||||
)}
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === authType.inGameUpdate) && (
|
||||
<Button
|
||||
theme="primary"
|
||||
text="메시지 등록"
|
||||
value="2"
|
||||
handleClick={e => {
|
||||
e.preventDefault();
|
||||
setRegistView('view');
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</ListOption>
|
||||
</TableInfo>
|
||||
<TableWrapper>
|
||||
<TableStyle>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="40">
|
||||
<CheckBox id="check-all" handleCheck={handleAllSelect} checked={handleCountSelectedRow()} />
|
||||
</th>
|
||||
<th width="80">번호</th>
|
||||
<th width="100">채팅 타입</th>
|
||||
<th width="200">송출 일자</th>
|
||||
<th>메시지</th>
|
||||
<th width="80">송출 횟수</th>
|
||||
<th width="100">송출 상태</th>
|
||||
<th width="120">등록자</th>
|
||||
<th width="200">등록자(이메일주소)</th>
|
||||
<th width="200">등록일자</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList &&
|
||||
dataList.map(notice => (
|
||||
<Fragment key={notice.id}>
|
||||
<tr>
|
||||
<td>
|
||||
<CheckBox name={'select'} id={notice.id} setData={e => handleSelectCheckBox(e)} />
|
||||
</td>
|
||||
<td>{notice.row_num}</td>
|
||||
<td>{message_type.map(item => item.value === notice.message_type && item.name)}</td>
|
||||
<td>{convertKTC(notice.send_dt)}</td>
|
||||
<td>
|
||||
<DetailMessage onClick={e => handleDetailModal(e, notice.id)}>
|
||||
{notice.content.length > 20 ? notice.content.slice(0, 20) + '...' : notice.content || ''}
|
||||
</DetailMessage>
|
||||
</td>
|
||||
<td>
|
||||
{/*{notice.send_cnt} / {notice.repeat_cnt}*/}
|
||||
{notice.send_cnt}
|
||||
</td>
|
||||
<td>
|
||||
{sendStatus.map(data => data.value === notice.send_status && data.name)}
|
||||
</td>
|
||||
<td>{notice.create_name}</td>
|
||||
<td>{notice.create_by}</td>
|
||||
<td>{convertKTC(notice.create_dt)}</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
{/* 인게임 메세지 정보 */}
|
||||
<BoardInfoModal
|
||||
detailView={detailView}
|
||||
setDetailView={setDetailView}
|
||||
content={detailData}
|
||||
id={detailId}
|
||||
setIsCopyData={setIsCopyData}
|
||||
openRegistModal={setRegistView}
|
||||
userInfo={userInfo}
|
||||
/>
|
||||
{/* 인게임 메세지 등록 */}
|
||||
<BoardRegistModal registView={registView} setRegistView={setRegistView} copyData={isCopyData ? detailData : ''} setIsCopyData={setIsCopyData} userInfo={userInfo} />
|
||||
</TableWrapper>
|
||||
|
||||
{/* 선택 삭제 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={deleteModalClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleDeleteModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">
|
||||
선택된 인게임 메세지를 삭제하시겠습니까?
|
||||
<br />
|
||||
삭제 시 설정 정보가 제거됩니다.
|
||||
</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="취소" theme="line" size="large" width="100%" handleClick={handleDeleteModalClose} />
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleSelectedDelete} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
{/* 확인 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={confirmModalClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleConfirmeModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">삭제가 완료되었습니다.</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleConfirmeModalClose} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Board;
|
||||
|
||||
|
||||
339
src/pages/ServiceManage/Event.js
Normal file
339
src/pages/ServiceManage/Event.js
Normal file
@@ -0,0 +1,339 @@
|
||||
import { useState, useEffect, Fragment, memo } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import {
|
||||
EventDelete,
|
||||
EventDetailView,
|
||||
EventView,
|
||||
} from '../../apis';
|
||||
|
||||
import { authList } from '../../store/authList';
|
||||
import { authType, commonStatus, modalTypes, eventStatus } from '../../assets/data';
|
||||
import { Title, FormWrapper, TableStyle, MailTitle, TableWrapper, TextInput, InputItem } from '../../styles/Components';
|
||||
import CheckBox from '../../components/common/input/CheckBox';
|
||||
import Button from '../../components/common/button/Button';
|
||||
import EventDetailModal from '../../components/ServiceManage/modal/EventDetailModal';
|
||||
import Pagination from '../../components/common/Pagination/Pagination';
|
||||
import 'react-datepicker/dist/react-datepicker.css';
|
||||
import DynamicModal from '../../components/common/modal/DynamicModal';
|
||||
import AuthModal from '../../components/common/modal/AuthModal';
|
||||
import ViewTableInfo from '../../components/common/Table/ViewTableInfo';
|
||||
import { convertKTC, timeDiffMinute } from '../../utils';
|
||||
import EventListSearchBar from '../../components/ServiceManage/searchBar/EventListSearchBar';
|
||||
import CustomConfirmModal from '../../components/common/modal/CustomConfirmModal';
|
||||
import { ModalInputItem, ModalSubText, RegistInputItem, RegistNotice, SubText } from '../../styles/ModuleComponents';
|
||||
|
||||
const Event = () => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
const userInfo = useRecoilValue(authList);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [pageSize, setPageSize] = useState(50);
|
||||
|
||||
const [dataList, setDataList] = useState([]);
|
||||
const [detailData, setDetailData] = useState('');
|
||||
|
||||
const [selectedRow, setSelectedRow] = useState([]);
|
||||
const [searchData, setSearchData] = useState({
|
||||
title: '',
|
||||
content: '',
|
||||
status: 'ALL',
|
||||
startDate: '',
|
||||
endDate: '',
|
||||
});
|
||||
const [orderBy, setOrderBy] = useState('DESC');
|
||||
const [modalState, setModalState] = useState({
|
||||
detailModal: 'hidden',
|
||||
deleteConfirmModal: 'hidden',
|
||||
deleteCompleteModal: 'hidden',
|
||||
});
|
||||
const [alertMsg, setAlertMsg] = useState('');
|
||||
const [deleteDesc, setDeleteDesc] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
fetchData('', '', 'ALL', '', '');
|
||||
setSelectedRow([]);
|
||||
}, [currentPage]);
|
||||
|
||||
// 리스트 조회
|
||||
const fetchData = async (title, content, status, startDate, endDate, order, size) => {
|
||||
setDataList(
|
||||
await EventView(
|
||||
token,
|
||||
title,
|
||||
content,
|
||||
status,
|
||||
startDate && new Date(startDate).toISOString(),
|
||||
endDate && new Date(endDate).toISOString(),
|
||||
order ? order : orderBy,
|
||||
size ? size : pageSize,
|
||||
currentPage,
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
// 검색 함수
|
||||
const handleSearch = (title, content, status, startDate, endDate) => {
|
||||
fetchData(title, content, status, startDate && new Date(startDate).toISOString(), endDate && new Date(endDate).toISOString());
|
||||
};
|
||||
|
||||
// 오름차순 내림차순
|
||||
const handleOrderBy = e => {
|
||||
const order = e.target.value;
|
||||
|
||||
setOrderBy(order);
|
||||
fetchData(
|
||||
searchData.title,
|
||||
searchData.content,
|
||||
searchData.status,
|
||||
searchData.startDate && new Date(searchData.startDate).toISOString(),
|
||||
searchData.endDate && new Date(searchData.endDate).toISOString(),
|
||||
order,
|
||||
pageSize,
|
||||
);
|
||||
};
|
||||
|
||||
const handlePageSize = e => {
|
||||
const size = e.target.value;
|
||||
setPageSize(size);
|
||||
setCurrentPage(1);
|
||||
|
||||
fetchData(
|
||||
searchData.title,
|
||||
searchData.content,
|
||||
searchData.status,
|
||||
searchData.startDate && new Date(searchData.startDate).toISOString(),
|
||||
searchData.endDate && new Date(searchData.endDate).toISOString(),
|
||||
orderBy,
|
||||
size,
|
||||
1,
|
||||
);
|
||||
};
|
||||
|
||||
// 상세보기 호출
|
||||
const handleDetailModal = async (e, id) => {
|
||||
await EventDetailView(token, id).then(data => {
|
||||
setDetailData(data);
|
||||
});
|
||||
|
||||
e.preventDefault();
|
||||
handleModalView('detail');
|
||||
};
|
||||
|
||||
// 체크박스 선택 리스트
|
||||
const handleSelectCheckBox = (e, event) => {
|
||||
let list = [...selectedRow];
|
||||
if (e.target.checked) {
|
||||
list.push(event);
|
||||
setSelectedRow(list);
|
||||
} else {
|
||||
const filterList = list.filter(data => e.target.id !== data);
|
||||
setSelectedRow(filterList);
|
||||
}
|
||||
};
|
||||
|
||||
// 전체 선택 구현
|
||||
const handleAllSelect = () => {
|
||||
let list = [];
|
||||
if (document.getElementById('check-all').checked === true) {
|
||||
dataList.list.map((data, index) => {
|
||||
document.getElementsByName('select')[index].checked = true;
|
||||
list.push(String(data.id));
|
||||
});
|
||||
} else if (document.getElementById('check-all').checked === false) {
|
||||
for (let i = 0; i < dataList.list.length; i++) {
|
||||
dataList.list.map((data, index) => (document.getElementsByName('select')[index].checked = false));
|
||||
list = [];
|
||||
}
|
||||
}
|
||||
setSelectedRow(list);
|
||||
};
|
||||
|
||||
const handleModalView = (type) => {
|
||||
setModalState((prevState) => ({
|
||||
...prevState,
|
||||
[`${type}Modal`]: 'view',
|
||||
}));
|
||||
}
|
||||
|
||||
const handleModalClose = (type) => {
|
||||
setModalState((prevState) => ({
|
||||
...prevState,
|
||||
[`${type}Modal`]: 'hidden',
|
||||
}));
|
||||
}
|
||||
|
||||
const handleModalSubmit = async (type, param = null) => {
|
||||
switch (type) {
|
||||
case "delete":
|
||||
const delete_check = selectedRow.every(row => {
|
||||
const timeDiff = timeDiffMinute(convertKTC(row.start_dt), (new Date));
|
||||
return row.add_flag || (timeDiff < 30);
|
||||
});
|
||||
if(delete_check){
|
||||
setAlertMsg(t('EVENT_TIME_LIMIT_UPDATE'));
|
||||
return;
|
||||
}
|
||||
handleModalView('deleteConfirm');
|
||||
break;
|
||||
case "deleteConfirm":
|
||||
let list = [];
|
||||
|
||||
let isChecked = false;
|
||||
|
||||
selectedRow.map(data => {
|
||||
const row = dataList.list.find(row => row.id === Number(data.id));
|
||||
if(row.status !== commonStatus.wait) isChecked = true;
|
||||
list.push({
|
||||
id: data.id,
|
||||
delete_desc: deleteDesc
|
||||
});
|
||||
});
|
||||
|
||||
if(isChecked) {
|
||||
setAlertMsg(t('EVENT_WARNING_DELETE'))
|
||||
handleModalClose('deleteConfirm');
|
||||
return;
|
||||
}
|
||||
|
||||
EventDelete(token, list);
|
||||
|
||||
handleModalClose('deleteConfirm');
|
||||
handleModalView('deleteComplete');
|
||||
break;
|
||||
case "deleteComplete":
|
||||
handleModalClose('deleteComplete');
|
||||
// fetchData(option);
|
||||
window.location.reload();
|
||||
break;
|
||||
case "warning":
|
||||
setAlertMsg('')
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const handleCountSelectedRow = () => {
|
||||
return currentPage > (dataList && dataList.total) / pageSize ? selectedRow.length === dataList.total % pageSize : selectedRow.length === Number(pageSize);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{userInfo.auth_list && !userInfo.auth_list.some(auth => auth.id === authType.eventRead) ? (
|
||||
<AuthModal />
|
||||
) : (
|
||||
<>
|
||||
<Title>출석 보상 이벤트 관리</Title>
|
||||
<FormWrapper>
|
||||
<EventListSearchBar handleSearch={handleSearch} setResultData={setSearchData} />
|
||||
</FormWrapper>
|
||||
<ViewTableInfo total={dataList.total} total_all={dataList.total_all} handleOrderBy={handleOrderBy} handlePageSize={handlePageSize}>
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === authType.eventDelete) && (
|
||||
<Button theme={selectedRow.length === 0 ? 'disable' : 'line'} text="선택 삭제" handleClick={() => handleModalSubmit('delete')} />
|
||||
)}
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === authType.eventUpdate) && (
|
||||
<Button
|
||||
theme="primary"
|
||||
text="이벤트 등록"
|
||||
type="button"
|
||||
handleClick={e => {
|
||||
e.preventDefault();
|
||||
navigate('/servicemanage/event/eventregist');
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</ViewTableInfo>
|
||||
<TableWrapper>
|
||||
<TableStyle>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="40">
|
||||
<CheckBox id="check-all" handleCheck={handleAllSelect} checked={handleCountSelectedRow()} />
|
||||
</th>
|
||||
<th width="80">번호</th>
|
||||
<th width="100">이벤트 상태</th>
|
||||
<th width="210">시작 일시</th>
|
||||
<th width="210">종료 일시</th>
|
||||
<th>우편 제목</th>
|
||||
<th width="110">확인 / 수정</th>
|
||||
<th width="200">등록자(처리자)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList.list &&
|
||||
dataList.list.map(event => (
|
||||
<Fragment key={event.row_num}>
|
||||
<tr>
|
||||
<td>
|
||||
<CheckBox name={'select'} id={event.id} setData={e => handleSelectCheckBox(e, event)} />
|
||||
</td>
|
||||
<td>{event.row_num}</td>
|
||||
<td>{eventStatus.map(data => data.value === event.status && data.name)}</td>
|
||||
<td>{convertKTC(event.start_dt)}</td>
|
||||
<td>{convertKTC(event.end_dt)}</td>
|
||||
<MailTitle>{event.title}</MailTitle>
|
||||
<td>
|
||||
<Button theme="line" text="상세보기" handleClick={e => handleDetailModal(e, event.id)} />
|
||||
</td>
|
||||
<td>{event.create_by}</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
|
||||
<Pagination postsPerPage={pageSize} totalPosts={dataList && dataList.total_all} setCurrentPage={setCurrentPage} currentPage={currentPage} pageLimit={10} />
|
||||
|
||||
{/*상세*/}
|
||||
<EventDetailModal detailView={modalState.detailModal} handleDetailView={() => handleModalClose('detail')} content={detailData} setDetailData={setDetailData}/>
|
||||
|
||||
{/*삭제 확인*/}
|
||||
<DynamicModal
|
||||
modalType={modalTypes.childOkCancel}
|
||||
view={modalState.deleteConfirmModal}
|
||||
handleCancel={() => handleModalClose('deleteConfirm')}
|
||||
handleSubmit={() => handleModalSubmit('deleteConfirm')}
|
||||
>
|
||||
<ModalInputItem>
|
||||
{t('EVENT_SELECT_DELETE')}
|
||||
<RegistInputItem>
|
||||
<TextInput
|
||||
placeholder="사유 입력"
|
||||
maxLength="30"
|
||||
value={deleteDesc}
|
||||
onChange={e => {
|
||||
if (e.target.value.length > 30) return;
|
||||
setDeleteDesc(e.target.value.trimStart())
|
||||
}}
|
||||
/>
|
||||
</RegistInputItem>
|
||||
<ModalSubText $color={deleteDesc.length > 29 ? 'red' : '#666'}>* 최대 등록 가능 글자수 ({deleteDesc.length}/30자)</ModalSubText>
|
||||
</ModalInputItem>
|
||||
</DynamicModal>
|
||||
{/*삭제 완료*/}
|
||||
<DynamicModal
|
||||
modalType={modalTypes.completed}
|
||||
view={modalState.deleteCompleteModal}
|
||||
handleSubmit={() => handleModalSubmit('deleteComplete')}
|
||||
modalText={t('DEL_COMPLETE')}
|
||||
/>
|
||||
{/* 경고 모달 */}
|
||||
<DynamicModal
|
||||
modalType={modalTypes.completed}
|
||||
view={alertMsg ? 'view' : 'hidden'}
|
||||
modalText={alertMsg}
|
||||
handleSubmit={() => handleModalSubmit('warning')}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Event;
|
||||
519
src/pages/ServiceManage/EventRegist.js
Normal file
519
src/pages/ServiceManage/EventRegist.js
Normal file
@@ -0,0 +1,519 @@
|
||||
import { useState, Fragment, useEffect } from 'react';
|
||||
import Button from '../../components/common/button/Button';
|
||||
import Loading from '../../components/common/Loading';
|
||||
|
||||
import {
|
||||
Title,
|
||||
BtnWrapper,
|
||||
TextInput,
|
||||
SelectInput,
|
||||
Label,
|
||||
InputLabel,
|
||||
Textarea,
|
||||
SearchBarAlert,
|
||||
} from '../../styles/Components';
|
||||
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { EventIsItem, EventSingleRegist } from '../../apis';
|
||||
|
||||
import { authList } from '../../store/authList';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
AppendRegistBox, AppendRegistTable, AreaBtnClose,
|
||||
BtnDelete,
|
||||
Item,
|
||||
ItemList, LangArea, ModalInputItem, ModalItem, ModalItemList, ModalSubText, RegistGroup,
|
||||
RegistInputItem,
|
||||
RegistInputRow, RegistNotice, RegistTable,
|
||||
} from '../../styles/ModuleComponents';
|
||||
import AuthModal from '../../components/common/modal/AuthModal';
|
||||
import { authType, benItems, modalTypes, wellType } from '../../assets/data';
|
||||
import DynamicModal from '../../components/common/modal/DynamicModal';
|
||||
import DateTimeInput from '../../components/common/input/DateTimeInput';
|
||||
import { timeDiffMinute } from '../../utils';
|
||||
|
||||
const EventRegist = () => {
|
||||
const navigate = useNavigate();
|
||||
const userInfo = useRecoilValue(authList);
|
||||
const { t } = useTranslation();
|
||||
const token = sessionStorage.getItem('token');
|
||||
|
||||
const [loading, setLoading] = useState(false); // 로딩 창
|
||||
const [modalState, setModalState] = useState({
|
||||
cancelModal: 'hidden',
|
||||
registConfirmModal: 'hidden',
|
||||
registCompleteModal: 'hidden',
|
||||
}); // 모달 관리
|
||||
|
||||
const [item, setItem] = useState(''); // 아이템 값
|
||||
const [itemCount, setItemCount] = useState(''); // 아이템 개수
|
||||
const [resource, setResource] = useState('19010001'); // 자원 값
|
||||
const [resourceCount, setResourceCount] = useState(''); // 자원 개수
|
||||
|
||||
const [isNullValue, setIsNullValue] = useState(false); // 데이터 값 체크
|
||||
const [btnValidation, setBtnValidation] = useState(false); // 입력창 버튼
|
||||
const [itemCheckMsg, setItemCheckMsg] = useState('');
|
||||
const [alertMsg, setAlertMsg] = useState('');
|
||||
|
||||
const [time, setTime] = useState({
|
||||
start_hour: '00',
|
||||
start_min: '00',
|
||||
end_hour: '00',
|
||||
end_min: '00',
|
||||
}); //시간 정보
|
||||
|
||||
const [resultData, setResultData] = useState({
|
||||
is_reserve: false,
|
||||
start_dt: '',
|
||||
end_dt: '',
|
||||
event_type: 'ATTD',
|
||||
mail_list: [
|
||||
{
|
||||
title: '',
|
||||
content: '',
|
||||
language: 'KO',
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
content: '',
|
||||
language: 'EN',
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
content: '',
|
||||
language: 'JA',
|
||||
}
|
||||
],
|
||||
item_list: [],
|
||||
guid: '',
|
||||
}); //데이터 정보
|
||||
|
||||
useEffect(() => {
|
||||
if (checkCondition()) {
|
||||
setIsNullValue(false);
|
||||
} else {
|
||||
setIsNullValue(true);
|
||||
}
|
||||
}, [resultData]);
|
||||
|
||||
useEffect(() => {
|
||||
setItemCheckMsg('');
|
||||
}, [item]);
|
||||
|
||||
const combineDateTime = (date, hour, min) => {
|
||||
if (!date) return null;
|
||||
return new Date(date.getFullYear(), date.getMonth(), date.getDate(), hour, min);
|
||||
};
|
||||
|
||||
// 날짜 처리
|
||||
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`] ? resultData[`${type}_dt`] : new Date();
|
||||
|
||||
setResultData({
|
||||
...resultData,
|
||||
[`${type}_dt`]: combineDateTime(date, newTime[`${type}_hour`], newTime[`${type}_min`]),
|
||||
});
|
||||
};
|
||||
|
||||
// 아이템 수량 숫자 체크
|
||||
const handleItemCount = e => {
|
||||
if (e.target.value === '0' || e.target.value === '-0') {
|
||||
setItemCount('1');
|
||||
e.target.value = '1';
|
||||
} else if (e.target.value < 0) {
|
||||
let plusNum = Math.abs(e.target.value);
|
||||
setItemCount(plusNum);
|
||||
} else {
|
||||
setItemCount(e.target.value);
|
||||
}
|
||||
};
|
||||
|
||||
// 아이템 추가
|
||||
const handleItemList = async () => {
|
||||
if(benItems.includes(item)){
|
||||
setAlertMsg(t('MAIL_ITEM_ADD_BEN'))
|
||||
return;
|
||||
}
|
||||
if(item.length === 0 || itemCount.length === 0) return;
|
||||
|
||||
const token = sessionStorage.getItem('token');
|
||||
const result = await EventIsItem(token, {item: item});
|
||||
|
||||
if(result.data.result === "ERROR"){
|
||||
setItemCheckMsg(t('NOT_ITEM'));
|
||||
return;
|
||||
}
|
||||
|
||||
const itemIndex = resultData.item_list.findIndex((data) => data.item === item);
|
||||
if (itemIndex !== -1) {
|
||||
setItemCheckMsg(t('MAIL_ITEM_ADD_DUPL'));
|
||||
return;
|
||||
}
|
||||
const newItem = { item: item, item_cnt: itemCount, item_name: result.data.data.item_info.item_name };
|
||||
|
||||
resultData.item_list.push(newItem);
|
||||
setItem('');
|
||||
setItemCount('');
|
||||
};
|
||||
|
||||
// 추가된 아이템 삭제
|
||||
const onItemRemove = id => {
|
||||
let filterList = resultData.item_list && resultData.item_list.filter(item => item !== resultData.item_list[id]);
|
||||
setResultData({ ...resultData, item_list: filterList });
|
||||
};
|
||||
|
||||
// 입력창 삭제
|
||||
const onLangDelete = language => {
|
||||
let filterList = resultData.mail_list && resultData.mail_list.filter(el => el.language !== language);
|
||||
|
||||
if (filterList.length === 1) {
|
||||
setBtnValidation(true);
|
||||
} else {
|
||||
setBtnValidation(false);
|
||||
}
|
||||
|
||||
setResultData({ ...resultData, mail_list: filterList });
|
||||
};
|
||||
|
||||
// 자원 수량 숫자 체크
|
||||
const handleResourceCount = e => {
|
||||
if (e.target.value === '0' || e.target.value === '-0') {
|
||||
setResourceCount('1');
|
||||
e.target.value = '1';
|
||||
} else if (e.target.value < 0) {
|
||||
let plusNum = Math.abs(e.target.value);
|
||||
setResourceCount(plusNum);
|
||||
} else {
|
||||
setResourceCount(e.target.value);
|
||||
}
|
||||
};
|
||||
|
||||
// 자원 추가
|
||||
const handleResourceList = (e) => {
|
||||
if(resource.length === 0 || resourceCount.length === 0) return;
|
||||
|
||||
const itemIndex = resultData.item_list.findIndex(
|
||||
(item) => item.item === resource
|
||||
);
|
||||
|
||||
if (itemIndex !== -1) {
|
||||
const item_cnt = resultData.item_list[itemIndex].item_cnt;
|
||||
resultData.item_list[itemIndex].item_cnt = Number(item_cnt) + Number(resourceCount);
|
||||
} else {
|
||||
const name = wellType.find(well => well.value === resource).name;
|
||||
const newItem = { item: resource, item_cnt: resourceCount, item_name: name };
|
||||
resultData.item_list.push(newItem);
|
||||
}
|
||||
setResourceCount('');
|
||||
};
|
||||
|
||||
const handleModalView = (type) => {
|
||||
setModalState((prevState) => ({
|
||||
...prevState,
|
||||
[`${type}Modal`]: 'view',
|
||||
}));
|
||||
}
|
||||
|
||||
const handleModalClose = (type) => {
|
||||
setModalState((prevState) => ({
|
||||
...prevState,
|
||||
[`${type}Modal`]: 'hidden',
|
||||
}));
|
||||
}
|
||||
|
||||
const handleSubmit = async (type, param = null) => {
|
||||
switch (type) {
|
||||
case "submit":
|
||||
if (!checkCondition()) return;
|
||||
const timeDiff = timeDiffMinute(resultData.start_dt, (new Date))
|
||||
if(timeDiff < 60) {
|
||||
setAlertMsg(t('EVENT_TIME_LIMIT_ADD'));
|
||||
return;
|
||||
}
|
||||
|
||||
handleModalView('registConfirm');
|
||||
break;
|
||||
case "cancel":
|
||||
|
||||
handleModalView('deleteSubmit');
|
||||
break;
|
||||
case "registConfirm":
|
||||
setLoading(true);
|
||||
|
||||
const result = await EventSingleRegist(token, resultData);
|
||||
|
||||
setLoading(false);
|
||||
handleModalClose('registConfirm');
|
||||
handleModalView('registComplete');
|
||||
break;
|
||||
case "registComplete":
|
||||
handleModalClose('registComplete');
|
||||
|
||||
navigate('/servicemanage/event');
|
||||
break;
|
||||
case "warning":
|
||||
setAlertMsg('');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const checkCondition = () => {
|
||||
return (
|
||||
resultData.mail_list.every(data => data.content !== '' && data.title !== '') &&
|
||||
(resultData.start_dt.length !== 0) &&
|
||||
(resultData.end_dt.length !== 0)
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{userInfo.auth_list && !userInfo.auth_list.some(auth => auth.id === authType.eventUpdate) ? (
|
||||
<AuthModal/>
|
||||
) : (
|
||||
<>
|
||||
<Title>이벤트 등록</Title>
|
||||
<RegistGroup>
|
||||
<RegistInputRow>
|
||||
<RegistInputItem>
|
||||
<InputLabel>이벤트 타입</InputLabel>
|
||||
<SelectInput onChange={e => setResultData({ ...resultData, event_type: e.target.value })} value={resultData.event_type}>
|
||||
<option value="ATTD">출석 이벤트</option>
|
||||
</SelectInput>
|
||||
</RegistInputItem>
|
||||
<DateTimeInput
|
||||
title="시작 시간"
|
||||
dateName="시작 일자"
|
||||
selectedDate={resultData.start_dt}
|
||||
handleSelectedDate={data => handleDateChange(data, 'start')}
|
||||
onChange={e => handleTimeChange(e, 'start')}
|
||||
/>
|
||||
<DateTimeInput
|
||||
title="종료 시간"
|
||||
dateName="종료 일자"
|
||||
selectedDate={resultData.end_dt}
|
||||
handleSelectedDate={data => handleDateChange(data, 'end')}
|
||||
onChange={e => handleTimeChange(e, 'end')}
|
||||
/>
|
||||
</RegistInputRow>
|
||||
</RegistGroup>
|
||||
{resultData.mail_list.map((data, idx) => {
|
||||
return (
|
||||
<Fragment key={idx}>
|
||||
<AppendRegistBox>
|
||||
<LangArea>
|
||||
언어 : {data.language}
|
||||
{btnValidation === false ? (
|
||||
<AreaBtnClose
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
onLangDelete(data.language);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<AreaBtnClose opacity="10%" />
|
||||
)}
|
||||
</LangArea>
|
||||
<RegistTable>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th width="120">
|
||||
<Label>제목</Label>
|
||||
</th>
|
||||
<td>
|
||||
<RegistInputItem>
|
||||
<TextInput
|
||||
placeholder="우편 제목 입력"
|
||||
maxLength="30"
|
||||
id={data.language}
|
||||
value={data.title}
|
||||
onChange={e => {
|
||||
if (e.target.value.length > 30) {
|
||||
return;
|
||||
}
|
||||
let list = [...resultData.mail_list];
|
||||
let findIndex = resultData.mail_list && resultData.mail_list.findIndex(item => item.language === e.target.id);
|
||||
list[findIndex].title = e.target.value.trimStart();
|
||||
|
||||
setResultData({ ...resultData, mail_list: list });
|
||||
}}
|
||||
/>
|
||||
</RegistInputItem>
|
||||
<RegistNotice $color={data.title.length > 29 ? 'red' : '#666'}>* 최대 등록 가능 글자수 ({data.title.length}/30자)</RegistNotice>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
<Label>내용</Label>
|
||||
</th>
|
||||
<td>
|
||||
<Textarea
|
||||
maxLength="2000"
|
||||
value={data.content}
|
||||
id={data.language}
|
||||
onChange={e => {
|
||||
if (e.target.value.length > 2000) {
|
||||
return;
|
||||
}
|
||||
let list = [...resultData.mail_list];
|
||||
let findIndex = resultData.mail_list && resultData.mail_list.findIndex(item => item.language === e.target.id);
|
||||
list[findIndex].content = e.target.value.trimStart();
|
||||
|
||||
setResultData({ ...resultData, mail_list: list });
|
||||
}}
|
||||
/>
|
||||
<RegistNotice $color={data.content.length > 1999 ? 'red' : '#666'}>* 최대 등록 가능 글자수 ({data.content.length}/2000자)</RegistNotice>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</RegistTable>
|
||||
</AppendRegistBox>
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
|
||||
<AppendRegistBox>
|
||||
<AppendRegistTable>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th width="120">
|
||||
<Label>아이템 첨부</Label>
|
||||
</th>
|
||||
<td>
|
||||
<RegistInputItem>
|
||||
<TextInput placeholder="Item Meta id 입력" value={item} onChange={e => setItem(e.target.value.trimStart())} />
|
||||
<TextInput placeholder="수량" type="number" value={itemCount} onChange={e => handleItemCount(e)} width="100px" />
|
||||
<Button text="추가" theme={itemCount.length === 0 || item.length === 0 ? 'disable' : 'search'} handleClick={handleItemList} width="100px" height="35px" />
|
||||
{itemCheckMsg && <SearchBarAlert>{itemCheckMsg}</SearchBarAlert>}
|
||||
</RegistInputItem>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th width="120">
|
||||
<Label>자원 첨부</Label>
|
||||
</th>
|
||||
<td>
|
||||
<RegistInputItem>
|
||||
<SelectInput onChange={e => setResource(e.target.value)} value={resource}>
|
||||
{wellType.map((data, index) => (
|
||||
<option key={index} value={data.value}>
|
||||
{data.name}
|
||||
</option>
|
||||
))}
|
||||
</SelectInput>
|
||||
<TextInput placeholder="수량" type="number" value={resourceCount} onChange={e => handleResourceCount(e)} width="200px" />
|
||||
<Button text="추가" theme={resourceCount.length === 0 || resource.length === 0 ? 'disable' : 'search'} handleClick={handleResourceList} width="100px" height="35px" />
|
||||
</RegistInputItem>
|
||||
|
||||
<div>
|
||||
{resultData.item_list && (
|
||||
<ItemList>
|
||||
{resultData.item_list.map((data, index) => {
|
||||
return (
|
||||
<Item key={index}>
|
||||
<span>
|
||||
{data.item_name}[{data.item}] ({data.item_cnt})
|
||||
</span>
|
||||
<BtnDelete onClick={() => onItemRemove(index)}></BtnDelete>
|
||||
</Item>
|
||||
);
|
||||
})}
|
||||
</ItemList>
|
||||
)}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</AppendRegistTable>
|
||||
</AppendRegistBox>
|
||||
{isNullValue && (
|
||||
<SearchBarAlert $align="right" $padding="0 0 15px">
|
||||
{t('NULL_MSG')}
|
||||
</SearchBarAlert>
|
||||
)}
|
||||
|
||||
<BtnWrapper $justify="flex-end" $gap="10px">
|
||||
<Button text="취소" theme="line" handleClick={() => handleModalView('cancel')} />
|
||||
<Button
|
||||
type="submit"
|
||||
text="등록"
|
||||
theme={checkCondition() ? 'primary' : 'disable'}
|
||||
handleClick={() => handleSubmit('submit')}
|
||||
/>
|
||||
</BtnWrapper>
|
||||
|
||||
{/* 등록 모달 */}
|
||||
<DynamicModal
|
||||
modalType={modalTypes.confirmOkCancel}
|
||||
view={modalState.registConfirmModal}
|
||||
modalText={t('EVENT_REGIST_CONFIRM')}
|
||||
handleSubmit={() => handleSubmit('registConfirm')}
|
||||
handleCancel={() => handleModalClose('registConfirm')}
|
||||
/>
|
||||
<DynamicModal
|
||||
modalType={modalTypes.childOkCancel}
|
||||
view={modalState.registConfirmModal}
|
||||
handleCancel={() => handleModalClose('registConfirm')}
|
||||
handleSubmit={() => handleSubmit('registConfirm')}
|
||||
>
|
||||
<ModalItem>
|
||||
{t('EVENT_REGIST_CONFIRM')}
|
||||
{resultData.item_list && (
|
||||
<ModalItemList>
|
||||
{resultData.item_list.map((data, index) => {
|
||||
return (
|
||||
<Item key={index}>
|
||||
<span>
|
||||
{data.item_name} {data.item_cnt.toLocaleString()}
|
||||
</span>
|
||||
</Item>
|
||||
);
|
||||
})}
|
||||
</ModalItemList>
|
||||
)}
|
||||
</ModalItem>
|
||||
</DynamicModal>
|
||||
{/* 완료 모달 */}
|
||||
<DynamicModal
|
||||
modalType={modalTypes.completed}
|
||||
view={modalState.registCompleteModal}
|
||||
modalText={t('REGIST_COMPLTE')}
|
||||
handleSubmit={() => handleSubmit('registComplete')}
|
||||
/>
|
||||
{/* 취소 모달 */}
|
||||
<DynamicModal
|
||||
modalType={modalTypes.confirmOkCancel}
|
||||
view={modalState.cancelModal}
|
||||
modalText={t('EVENT_REGIST_CANCEL')}
|
||||
handleCancel={() => handleModalClose('cancel')}
|
||||
handleSubmit={() => handleSubmit('cancel')}
|
||||
/>
|
||||
{/* 경고 모달 */}
|
||||
<DynamicModal
|
||||
modalType={modalTypes.completed}
|
||||
view={alertMsg ? 'view' : 'hidden'}
|
||||
modalText={alertMsg}
|
||||
handleSubmit={() => handleSubmit('warning')}
|
||||
/>
|
||||
{loading && <Loading/>}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default EventRegist;
|
||||
|
||||
252
src/pages/ServiceManage/Items.js
Normal file
252
src/pages/ServiceManage/Items.js
Normal file
@@ -0,0 +1,252 @@
|
||||
import { useState, Fragment, useEffect } from 'react';
|
||||
import Modal from '../../components/common/modal/Modal';
|
||||
import Button from '../../components/common/button/Button';
|
||||
import styled from 'styled-components';
|
||||
import { Title, FormWrapper, TableStyle, TableWrapper, BtnWrapper, ButtonClose, ModalText } from '../../styles/Components';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { ItemsSearchBar } from '../../components/ServiceManage';
|
||||
import { ItemListView } from '../../apis';
|
||||
|
||||
import { authList } from '../../store/authList';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import AuthModal from '../../components/common/modal/AuthModal';
|
||||
import { authType } from '../../assets/data';
|
||||
|
||||
const Items = () => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
const userInfo = useRecoilValue(authList);
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
// 데이터 조회 관련
|
||||
const [dataList, setDataList] = useState([]);
|
||||
const [selectedData, setSelectedData] = useState([]);
|
||||
const [requestValue, setRequestValue] = useState([]);
|
||||
|
||||
// 모달 관련 변수
|
||||
const [confirmDelModal, setConfirmDelModal] = useState('hidden');
|
||||
const [completeDelModal, setCompleteDelModal] = useState('hidden');
|
||||
const [confirmRestoreModal, setConfirmRestoreModal] = useState('hidden');
|
||||
const [completeRestoreModal, setCompleteRestoreModal] = useState('hidden');
|
||||
|
||||
// 검색 관련 변수
|
||||
const [searchData, setSearchData] = useState({
|
||||
searchType: 'GUID',
|
||||
searchKey: '',
|
||||
status: 'ALL',
|
||||
sanctions: 'ALL',
|
||||
period: 'ALL',
|
||||
});
|
||||
|
||||
const status = [
|
||||
{ value: 'ALL', name: '상태' },
|
||||
{ value: 'ACTIVE', name: '활성' },
|
||||
{ value: 'DEACTIVE', name: '비활성' },
|
||||
];
|
||||
|
||||
const restore = [
|
||||
{ value: 'ALL', name: '복구' },
|
||||
{ value: 'POSSIBLE', name: '가능' },
|
||||
{ value: 'IMPOSSIBLE', name: '불가능' },
|
||||
];
|
||||
|
||||
const fetchData = async (searchType, data, status, restore) => {
|
||||
setDataList(await ItemListView(token, searchType, data, status, restore));
|
||||
};
|
||||
|
||||
// 검색 기능
|
||||
const handleSearch = (searchType, data, status, restore) => {
|
||||
fetchData(searchType, data, status, restore);
|
||||
};
|
||||
|
||||
// 삭제 여부 모달
|
||||
const handleConfirmeDelModalClose = () => {
|
||||
if (confirmDelModal === 'hidden') {
|
||||
setConfirmDelModal('view');
|
||||
} else {
|
||||
setConfirmDelModal('hidden');
|
||||
setRequestValue([]);
|
||||
}
|
||||
};
|
||||
|
||||
// 복구 여부 모달
|
||||
const handleConfirmeRestoreModalClose = () => {
|
||||
if (confirmRestoreModal === 'hidden') {
|
||||
setConfirmRestoreModal('view');
|
||||
} else {
|
||||
setConfirmRestoreModal('hidden');
|
||||
setRequestValue([]);
|
||||
}
|
||||
};
|
||||
|
||||
// 삭제 모달창
|
||||
const handleConfirmDeleteModal = data => {
|
||||
handleConfirmeDelModalClose();
|
||||
};
|
||||
|
||||
// 복구 모달창
|
||||
const handleConfirmRestoreModal = data => {
|
||||
handleConfirmeRestoreModalClose();
|
||||
};
|
||||
|
||||
// 삭제 완료 확인 모달
|
||||
const handleCompleteDelModal = () => {
|
||||
if (completeDelModal === 'hidden') {
|
||||
setCompleteDelModal('view');
|
||||
} else {
|
||||
setCompleteDelModal('hidden');
|
||||
setRequestValue([]);
|
||||
handleConfirmeDelModalClose();
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
// 복구 완료 확인 모달
|
||||
const handleCompleteRestoreModal = () => {
|
||||
if (completeRestoreModal === 'hidden') {
|
||||
setCompleteRestoreModal('view');
|
||||
} else {
|
||||
setCompleteRestoreModal('hidden');
|
||||
setRequestValue([]);
|
||||
handleConfirmeRestoreModalClose();
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
// 삭제 기능 구현
|
||||
const handleDelete = () => {
|
||||
let list = [];
|
||||
|
||||
list.push({ id: selectedData });
|
||||
|
||||
// BlackListDelete(token, list);
|
||||
handleCompleteDelModal();
|
||||
};
|
||||
|
||||
// 복구 기능
|
||||
const handleRestore = () => {
|
||||
let list = [];
|
||||
|
||||
list.push({ id: selectedData});
|
||||
//api 호출
|
||||
|
||||
handleCompleteRestoreModal();
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{userInfo.auth_list && !userInfo.auth_list.some(auth => auth.id === authType.itemRead) ? (
|
||||
<AuthModal/>
|
||||
) : (
|
||||
<>
|
||||
<Title>아이템 복구 및 삭제</Title>
|
||||
<FormWrapper>
|
||||
<ItemsSearchBar handleSearch={handleSearch} setResultData={setSearchData} />
|
||||
</FormWrapper>
|
||||
<TableWrapper>
|
||||
<TableStyle>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="80">번호</th>
|
||||
<th width="20%">아이템명</th>
|
||||
<th width="20%">아이템 ID</th>
|
||||
<th width="80">상태</th>
|
||||
<th width="100">생성 날짜</th>
|
||||
<th width="80">복구 가능 여부</th>
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === 30) && <th width="100">액션</th>}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList.list &&
|
||||
dataList.list.map(data => (
|
||||
<Fragment key={data.id}>
|
||||
<tr>
|
||||
<td>{data.row_num}</td>
|
||||
<td>{data.item_nm}</td>
|
||||
<td>{data.item_id}</td>
|
||||
<td>{status.map(item => item.value === data.status && item.name)}</td>
|
||||
<td>{new Date(data.create_by).toLocaleString()}</td>
|
||||
<td>{restore.map(item => item.value === data.restore && item.name)}</td>
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === 30) && (
|
||||
<td>
|
||||
<ButtonGroup>
|
||||
<Button theme="line" id={data.id+"restore"} name="single" text="복구" handleClick={() => handleConfirmRestoreModal(data)} />
|
||||
<Divider>/</Divider>
|
||||
<Button theme="line" id={data.id+"delete"} name="single" text="삭제" handleClick={() => handleConfirmDeleteModal(data)} />
|
||||
</ButtonGroup>
|
||||
</td>
|
||||
)}
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
|
||||
{/* 삭제 확인 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={confirmDelModal}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleConfirmeDelModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">
|
||||
아이템을 삭제하시겠습니까?<br />* 한번 삭제한 아이템은 다시 복구할 수 없습니다.
|
||||
</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="취소" theme="line" size="large" width="100%" handleClick={handleConfirmeDelModalClose} />
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleDelete} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
|
||||
{/* 삭제 완료 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={completeDelModal}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleCompleteDelModal} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">삭제가 완료되었습니다.</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleCompleteDelModal} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
|
||||
{/* 복구 확인 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={confirmRestoreModal}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleConfirmeRestoreModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">
|
||||
아이템을 복구하시겠습니까?
|
||||
</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="취소" theme="line" size="large" width="100%" handleClick={handleConfirmeRestoreModalClose} />
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleDelete} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
|
||||
{/* 복구 완료 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={completeRestoreModal}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleCompleteRestoreModal} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">복구가 완료되었습니다.</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleCompleteRestoreModal} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Items;
|
||||
|
||||
const ButtonGroup = styled.div`
|
||||
display: 'flex',
|
||||
alignItems: 'center'
|
||||
`
|
||||
const Divider = styled.span`
|
||||
margin: 0 8px;
|
||||
color: RGB(200,200,200);
|
||||
padding: 4px 0;
|
||||
`;
|
||||
275
src/pages/ServiceManage/LandAuction.js
Normal file
275
src/pages/ServiceManage/LandAuction.js
Normal file
@@ -0,0 +1,275 @@
|
||||
import { useState, Fragment, useRef } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import 'react-datepicker/dist/react-datepicker.css';
|
||||
|
||||
import {
|
||||
BuildingView,
|
||||
LandAuctionDelete,
|
||||
LandAuctionDetailView, LandView,
|
||||
} from '../../apis';
|
||||
|
||||
import { authList } from '../../store/authList';
|
||||
import {
|
||||
authType,
|
||||
modalTypes,
|
||||
landAuctionStatusType,
|
||||
landAuctionStatus,
|
||||
landSize,
|
||||
caliumStatus, commonStatus,
|
||||
} from '../../assets/data';
|
||||
import { Title, FormWrapper, TableStyle, TableWrapper} from '../../styles/Components';
|
||||
import {
|
||||
CheckBox,
|
||||
Button,
|
||||
DynamicModal,
|
||||
Pagination,
|
||||
ViewTableInfo, ExcelDownButton,
|
||||
} from '../../components/common';
|
||||
import { convertKTC, timeDiffMinute } from '../../utils';
|
||||
import { LandAuctionModal, LandAuctionSearchBar } from '../../components/ServiceManage';
|
||||
import { INITIAL_PAGE_SIZE, INITIAL_PAGE_LIMIT } from '../../assets/data/adminConstants';
|
||||
import { useDataFetch, useModal, useTable, withAuth } from '../../utils/hook';
|
||||
import { useLandAuctionSearch } from '../../components/ServiceManage/searchBar/LandAuctionSearchBar';
|
||||
import { StatusWapper, ChargeBtn, StatusLabel } from '../../styles/ModuleComponents';
|
||||
|
||||
const LandAuction = () => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
const userInfo = useRecoilValue(authList);
|
||||
const { t } = useTranslation();
|
||||
const tableRef = useRef(null);
|
||||
|
||||
const [detailData, setDetailData] = useState({});
|
||||
|
||||
const {
|
||||
modalState,
|
||||
handleModalView,
|
||||
handleModalClose
|
||||
} = useModal({
|
||||
detail: 'hidden',
|
||||
deleteConfirm: 'hidden',
|
||||
deleteComplete: 'hidden'
|
||||
});
|
||||
const [alertMsg, setAlertMsg] = useState('');
|
||||
const [modalType, setModalType] = useState('regist');
|
||||
|
||||
const {
|
||||
searchParams,
|
||||
data: dataList,
|
||||
handleSearch,
|
||||
handleReset,
|
||||
handlePageChange,
|
||||
handlePageSizeChange,
|
||||
handleOrderByChange,
|
||||
updateSearchParams
|
||||
} = useLandAuctionSearch(token, INITIAL_PAGE_SIZE);
|
||||
|
||||
const {
|
||||
selectedRows,
|
||||
handleSelectRow,
|
||||
isRowSelected
|
||||
} = useTable(dataList?.auction_list || [], {mode: 'single'});
|
||||
|
||||
const {
|
||||
data: landData
|
||||
} = useDataFetch(() => LandView(token), [token]);
|
||||
|
||||
const {
|
||||
data: buildingData
|
||||
} = useDataFetch(() => BuildingView(token), [token]);
|
||||
|
||||
const handleModalSubmit = async (type, param = null) => {
|
||||
switch (type) {
|
||||
case "regist":
|
||||
setModalType('regist');
|
||||
handleModalView('detail');
|
||||
break;
|
||||
case "detail":
|
||||
await LandAuctionDetailView(token, param).then(data => {
|
||||
setDetailData(data.auction_detail);
|
||||
setModalType('modify');
|
||||
handleModalView('detail');
|
||||
});
|
||||
break;
|
||||
case "delete":
|
||||
const date_check = selectedRows.every(row => {
|
||||
const timeDiff = timeDiffMinute(convertKTC(row.auction_start_dt), (new Date));
|
||||
return timeDiff < 3;
|
||||
});
|
||||
if(date_check){
|
||||
setAlertMsg(t('LAND_AUCTION_DELETE_DATE_WARNING'));
|
||||
return;
|
||||
}
|
||||
if(selectedRows[0].status === landAuctionStatusType.auction_start || selectedRows[0].status === landAuctionStatusType.stl_end){
|
||||
setAlertMsg(t('LAND_AUCTION_DELETE_STATUS_WARNING'));
|
||||
return;
|
||||
}
|
||||
handleModalView('deleteConfirm');
|
||||
break;
|
||||
case "deleteConfirm":
|
||||
let list = [];
|
||||
let isChecked = false;
|
||||
|
||||
selectedRows.map(data => {
|
||||
// const row = dataList.list.find(row => row.id === Number(data.id));
|
||||
// if(row.status !== commonStatus.wait) isChecked = true;
|
||||
list.push({
|
||||
id: data.id,
|
||||
});
|
||||
});
|
||||
|
||||
if(isChecked) {
|
||||
setAlertMsg(t('LAND_AUCTION_WARNING_DELETE'))
|
||||
handleModalClose('deleteConfirm');
|
||||
return;
|
||||
}
|
||||
|
||||
await LandAuctionDelete(token, list).then(data => {
|
||||
handleModalClose('deleteConfirm');
|
||||
if(data.result === "SUCCESS") {
|
||||
handleModalView('deleteComplete');
|
||||
}else if(data.result === "ERROR_AUCTION_STATUS_IMPOSSIBLE"){
|
||||
setAlertMsg(t('LAND_AUCTION_ERROR_DELETE_STATUS'));
|
||||
}else{
|
||||
setAlertMsg(t('DELETE_FAIL'));
|
||||
}
|
||||
}).catch(reason => {
|
||||
setAlertMsg(t('API_FAIL'));
|
||||
});
|
||||
|
||||
break;
|
||||
case "deleteComplete":
|
||||
handleModalClose('deleteComplete');
|
||||
// fetchData(option);
|
||||
window.location.reload();
|
||||
break;
|
||||
case "warning":
|
||||
setAlertMsg('')
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Title>랜드 경매 관리</Title>
|
||||
<FormWrapper>
|
||||
<LandAuctionSearchBar
|
||||
searchParams={searchParams}
|
||||
onSearch={(newParams, executeSearch = true) => {
|
||||
if (executeSearch) {
|
||||
handleSearch(newParams);
|
||||
} else {
|
||||
updateSearchParams(newParams);
|
||||
}
|
||||
}}
|
||||
onReset={handleReset}
|
||||
/>
|
||||
</FormWrapper>
|
||||
<ViewTableInfo total={dataList?.total} total_all={dataList?.total_all} handleOrderBy={handleOrderByChange} handlePageSize={handlePageSizeChange}>
|
||||
<ExcelDownButton tableRef={tableRef} fileName={t('FILE_LAND_AUCTION')} />
|
||||
{userInfo.auth_list?.some(auth => auth.id === authType.landAuctionDelete) && (
|
||||
<Button theme={selectedRows.length === 0 ? 'disable' : 'line'} text="선택 취소" handleClick={() => handleModalSubmit('delete')} />
|
||||
)}
|
||||
{userInfo.auth_list?.some(auth => auth.id === authType.landAuctionUpdate) && (
|
||||
<Button
|
||||
theme="primary"
|
||||
text="경매 등록"
|
||||
type="button"
|
||||
handleClick={e => handleModalSubmit('regist')}
|
||||
/>
|
||||
)}
|
||||
</ViewTableInfo>
|
||||
<TableWrapper>
|
||||
<TableStyle ref={tableRef}>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="40"></th>
|
||||
{/*<th width="80">번호</th>*/}
|
||||
<th width="90">경매 상태</th>
|
||||
<th width="80">랜드 크기</th>
|
||||
<th width="200">랜드 이름</th>
|
||||
<th width="90">인스턴스 수</th>
|
||||
{/*<th width="100">경매 재화</th>*/}
|
||||
<th width="90">경매 시작가</th>
|
||||
<th width="200">예약 시작일</th>
|
||||
<th width="200">예약 종료일</th>
|
||||
<th width="200">경매 시작일</th>
|
||||
<th width="200">경매 종료일</th>
|
||||
<th width="200">낙찰 정산일</th>
|
||||
<th width="90">낙찰 정산가</th>
|
||||
<th width="100">낙찰자</th>
|
||||
<th width="100">확인 / 수정</th>
|
||||
<th width="150">히스토리</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList?.auction_list?.map(auction => (
|
||||
<tr key={auction.row_num}>
|
||||
<td>
|
||||
<CheckBox name={'select'} id={auction.id}
|
||||
setData={(e) => handleSelectRow(e, auction)}
|
||||
checked={isRowSelected(auction.id)} />
|
||||
</td>
|
||||
{/*<td>{event.row_num}</td>*/}
|
||||
<StatusWapper>
|
||||
<StatusLabel $status={auction.status}>
|
||||
{landAuctionStatus.find(data => data.value === auction.status).name}
|
||||
</StatusLabel>
|
||||
</StatusWapper>
|
||||
{/*<td>{landAuctionStatus.find(data => data.value === auction.status)?.name}</td>*/}
|
||||
<td>{auction.land_size}</td>
|
||||
<td>{auction.land_name}</td>
|
||||
<td>{auction.land_socket}</td>
|
||||
{/*<td>{auction.currency_type}</td>*/}
|
||||
<td>{auction.start_price}</td>
|
||||
<td>{convertKTC(auction.resv_start_dt)}</td>
|
||||
<td>{convertKTC(auction.resv_end_dt)}</td>
|
||||
<td>{convertKTC(auction.auction_start_dt)}</td>
|
||||
<td>{convertKTC(auction.auction_end_dt)}</td>
|
||||
<td>{convertKTC(auction.close_end_dt)}</td>
|
||||
<td>{auction.close_price}</td>
|
||||
<td>{auction.bidder_nickname}</td>
|
||||
<td>
|
||||
<Button theme="line" text="상세보기"
|
||||
handleClick={e => handleModalSubmit('detail', auction.id)} />
|
||||
</td>
|
||||
<td>{auction.update_by}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
|
||||
<Pagination postsPerPage={searchParams.pageSize} totalPosts={dataList?.total_all} setCurrentPage={handlePageChange} currentPage={searchParams.currentPage} pageLimit={INITIAL_PAGE_LIMIT} />
|
||||
|
||||
{/*상세*/}
|
||||
<LandAuctionModal modalType={modalType} detailView={modalState.detailModal} handleDetailView={() => handleModalClose('detail')} content={detailData} setDetailData={setDetailData} landData={landData} buildingData={buildingData} />
|
||||
|
||||
{/*삭제 확인*/}
|
||||
<DynamicModal
|
||||
modalType={modalTypes.confirmOkCancel}
|
||||
view={modalState.deleteConfirmModal}
|
||||
handleCancel={() => handleModalClose('deleteConfirm')}
|
||||
handleSubmit={() => handleModalSubmit('deleteConfirm')}
|
||||
modalText={t('LAND_AUCTION_SELECT_DELETE')}
|
||||
/>
|
||||
{/*삭제 완료*/}
|
||||
<DynamicModal
|
||||
modalType={modalTypes.completed}
|
||||
view={modalState.deleteCompleteModal}
|
||||
handleSubmit={() => handleModalSubmit('deleteComplete')}
|
||||
modalText={t('DEL_COMPLETE')}
|
||||
/>
|
||||
{/* 경고 모달 */}
|
||||
<DynamicModal
|
||||
modalType={modalTypes.completed}
|
||||
view={alertMsg ? 'view' : 'hidden'}
|
||||
modalText={alertMsg}
|
||||
handleSubmit={() => handleModalSubmit('warning')}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
};
|
||||
|
||||
export default withAuth(authType.landAuctionRead)(LandAuction);
|
||||
331
src/pages/ServiceManage/Mail.js
Normal file
331
src/pages/ServiceManage/Mail.js
Normal file
@@ -0,0 +1,331 @@
|
||||
import styled from 'styled-components';
|
||||
import { useState, useEffect, Fragment } from 'react';
|
||||
|
||||
import CheckBox from '../../components/common/input/CheckBox';
|
||||
import Modal from '../../components/common/modal/Modal';
|
||||
|
||||
import { MailDelete, MailDetailView, MailView } from '../../apis';
|
||||
|
||||
import { Title, FormWrapper, TableInfo, ListCount, ListOption, TableStyle, SelectInput, MailTitle, TableWrapper, BtnWrapper, ButtonClose, ModalText } from '../../styles/Components';
|
||||
import Button from '../../components/common/button/Button';
|
||||
|
||||
import 'react-datepicker/dist/react-datepicker.css';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import MailDetailModal from '../../components/ServiceManage/modal/MailDetailModal';
|
||||
import MailListSearchBar from '../../components/ServiceManage/searchBar/MailListSearchBar';
|
||||
import Pagination from '../../components/common/Pagination/Pagination';
|
||||
|
||||
import { authList } from '../../store/authList';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { authType, mailReceiveType, mailSendStatus, mailSendType, mailType } from '../../assets/data';
|
||||
import AuthModal from '../../components/common/modal/AuthModal';
|
||||
import ViewTableInfo from '../../components/common/Table/ViewTableInfo';
|
||||
import { convertKTC} from '../../utils';
|
||||
|
||||
const Mail = () => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
const userInfo = useRecoilValue(authList);
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [pageSize, setPageSize] = useState(50);
|
||||
|
||||
const [dataList, setDataList] = useState([]);
|
||||
const [detailView, setDetailView] = useState('hidden');
|
||||
const [detailData, setDetailData] = useState('');
|
||||
|
||||
const [selectedRow, setSelectedRow] = useState([]);
|
||||
const [searchData, setSearchData] = useState({
|
||||
mailTitle: '',
|
||||
content: '',
|
||||
sendType: 'ALL',
|
||||
sendStatus: 'ALL',
|
||||
mailType: 'ALL',
|
||||
receiveType: 'ALL',
|
||||
sendDate: '',
|
||||
endDate: '',
|
||||
});
|
||||
const [orderBy, setOrderBy] = useState('DESC');
|
||||
|
||||
const [deleteModalClose, setDeleteModalClose] = useState('hidden');
|
||||
const [confirmModalClose, setConfirmModalClose] = useState('hidden');
|
||||
|
||||
// console.log(dataList);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData('', '', 'ALL', 'ALL', 'ALL', 'ALL', '', '');
|
||||
setSelectedRow([]);
|
||||
}, [currentPage]);
|
||||
|
||||
// 리스트 조회
|
||||
const fetchData = async (mailTitle, content, sendType, sendStatus, mailType, receiveType, sendDate, endDate, order, size) => {
|
||||
setDataList(
|
||||
await MailView(
|
||||
token,
|
||||
mailTitle,
|
||||
content,
|
||||
sendType,
|
||||
sendStatus,
|
||||
mailType,
|
||||
receiveType,
|
||||
sendDate && new Date(sendDate).toISOString(),
|
||||
endDate && new Date(endDate).toISOString(),
|
||||
order ? order : orderBy,
|
||||
size ? size : pageSize,
|
||||
currentPage,
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
// 검색 함수
|
||||
const handleSearch = (mailTitle, content, sendType, sendStatus, mailType, receiveType, sendDate, endDate) => {
|
||||
fetchData(mailTitle, content, sendType, sendStatus, mailType, receiveType, sendDate && new Date(sendDate).toISOString(), endDate && new Date(endDate).toISOString());
|
||||
};
|
||||
|
||||
// 오름차순 내림차순
|
||||
const handleOrderBy = e => {
|
||||
const order = e.target.value;
|
||||
|
||||
setOrderBy(order);
|
||||
fetchData(
|
||||
searchData.mailTitle,
|
||||
searchData.content,
|
||||
searchData.sendType,
|
||||
searchData.sendStatus,
|
||||
searchData.mailType,
|
||||
searchData.receiveType,
|
||||
searchData.sendDate && new Date(searchData.sendDate).toISOString(),
|
||||
searchData.endDate && new Date(searchData.endDate).toISOString(),
|
||||
order,
|
||||
pageSize,
|
||||
);
|
||||
};
|
||||
|
||||
const handlePageSize = e => {
|
||||
const size = e.target.value;
|
||||
setPageSize(size);
|
||||
setCurrentPage(1);
|
||||
|
||||
fetchData(
|
||||
searchData.mailTitle,
|
||||
searchData.content,
|
||||
searchData.sendType,
|
||||
searchData.sendStatus,
|
||||
searchData.mailType,
|
||||
searchData.receiveType,
|
||||
searchData.sendDate && new Date(searchData.sendDate).toISOString(),
|
||||
searchData.endDate && new Date(searchData.endDate).toISOString(),
|
||||
orderBy,
|
||||
size,
|
||||
1,
|
||||
);
|
||||
};
|
||||
|
||||
const handleDetailView = () => {
|
||||
if (detailView === 'hidden') setDetailView('view');
|
||||
else setDetailView('hidden');
|
||||
};
|
||||
|
||||
const handleDetailModal = async (e, id) => {
|
||||
setDetailData(await MailDetailView(token, id));
|
||||
|
||||
e.preventDefault();
|
||||
handleDetailView();
|
||||
};
|
||||
|
||||
// 체크박스 선택 리스트
|
||||
const handleSelectCheckBox = e => {
|
||||
let list = [...selectedRow];
|
||||
if (e.target.checked) {
|
||||
list.push(e.target.id);
|
||||
setSelectedRow(list);
|
||||
} else {
|
||||
const filterList = list.filter(data => e.target.id !== data);
|
||||
setSelectedRow(filterList);
|
||||
}
|
||||
};
|
||||
|
||||
// 전체 선택 구현
|
||||
const handleAllSelect = () => {
|
||||
let list = [];
|
||||
if (document.getElementById('check-all').checked === true) {
|
||||
dataList.list.map((data, index) => {
|
||||
document.getElementsByName('select')[index].checked = true;
|
||||
list.push(String(data.id));
|
||||
});
|
||||
} else if (document.getElementById('check-all').checked === false) {
|
||||
for (let i = 0; i < dataList.list.length; i++) {
|
||||
dataList.list.map((data, index) => (document.getElementsByName('select')[index].checked = false));
|
||||
list = [];
|
||||
}
|
||||
}
|
||||
setSelectedRow(list);
|
||||
};
|
||||
|
||||
// 선택 삭제 함수
|
||||
const handleSelectedDelete = () => {
|
||||
let list = [];
|
||||
|
||||
let isChecked = false;
|
||||
|
||||
selectedRow.map(data => {
|
||||
const row = dataList.list.find(row => row.id === Number(data));
|
||||
if(row.send_status === "FINISH" || row.send_status === "RUNNING") isChecked = true;
|
||||
list.push({
|
||||
id: data,
|
||||
});
|
||||
});
|
||||
|
||||
if(isChecked) {
|
||||
alert("발송 완료한 우편은 삭제할 수 없습니다.")
|
||||
handleDeleteModalClose();
|
||||
return;
|
||||
}
|
||||
|
||||
MailDelete(token, list);
|
||||
|
||||
handleDeleteModalClose();
|
||||
handleConfirmeModalClose();
|
||||
};
|
||||
|
||||
// 선택 삭제 모달
|
||||
const handleDeleteModalClose = () => {
|
||||
if (selectedRow.length !== 0 && deleteModalClose === 'hidden') {
|
||||
setDeleteModalClose('view');
|
||||
} else {
|
||||
setDeleteModalClose('hidden');
|
||||
}
|
||||
};
|
||||
|
||||
// 삭제, 승인, 저장 확인 모달창
|
||||
const handleConfirmeModalClose = () => {
|
||||
if (confirmModalClose === 'hidden') {
|
||||
setConfirmModalClose('view');
|
||||
} else {
|
||||
setConfirmModalClose('hidden');
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
const handleCountSelectedRow = () => {
|
||||
return currentPage > (dataList && dataList.total) / pageSize ? selectedRow.length === dataList.total % pageSize : selectedRow.length === Number(pageSize);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{userInfo.auth_list && !userInfo.auth_list.some(auth => auth.id === authType.mailRead) ? (
|
||||
<AuthModal/>
|
||||
) : (
|
||||
<>
|
||||
<Title>우편 조회 및 발송 관리</Title>
|
||||
<FormWrapper>
|
||||
<MailListSearchBar handleSearch={handleSearch} setResultData={setSearchData} />
|
||||
</FormWrapper>
|
||||
<ViewTableInfo total={dataList.total} total_all={dataList.total_all} handleOrderBy={handleOrderBy} handlePageSize={handlePageSize}>
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === authType.mailDelete) && (
|
||||
<Button theme={selectedRow.length === 0 ? 'disable' : 'line'} text="선택 삭제" handleClick={handleDeleteModalClose} />
|
||||
)}
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === authType.mailUpdate) && (
|
||||
<Button
|
||||
theme="primary"
|
||||
text="우편 등록"
|
||||
type="button"
|
||||
handleClick={e => {
|
||||
e.preventDefault();
|
||||
navigate('/servicemanage/mail/mailregist');
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</ViewTableInfo>
|
||||
<TableWrapper>
|
||||
<TableStyle>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="40">
|
||||
<CheckBox id="check-all" handleCheck={handleAllSelect} checked={handleCountSelectedRow()} />
|
||||
</th>
|
||||
<th width="80">번호</th>
|
||||
<th width="210">등록 일시</th>
|
||||
<th width="210">발송 일시</th>
|
||||
<th width="100">발송 방식</th>
|
||||
<th width="100">발송 상태</th>
|
||||
<th width="100">우편 타입</th>
|
||||
<th width="100">수신 대상</th>
|
||||
<th>우편 제목</th>
|
||||
<th width="110">확인 / 수정</th>
|
||||
<th width="200">등록자(처리자)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList.list &&
|
||||
dataList.list.map(mail => (
|
||||
<Fragment key={mail.row_num}>
|
||||
<tr>
|
||||
<td>
|
||||
<CheckBox name={'select'} id={mail.id} setData={e => handleSelectCheckBox(e)} />
|
||||
</td>
|
||||
<td>{mail.row_num}</td>
|
||||
<td>{convertKTC(mail.create_dt)}</td>
|
||||
<td>{convertKTC(mail.send_dt)}</td>
|
||||
<td>{mailSendType.map(data => data.value === mail.send_type && data.name)}</td>
|
||||
<td>
|
||||
{mail.send_status === 'FAIL' ? (
|
||||
<ListState>{mailSendStatus.map(data => data.value === mail.send_status && data.name)}</ListState>
|
||||
) : (
|
||||
mailSendStatus.map(data => data.value === mail.send_status && data.name)
|
||||
)}
|
||||
</td>
|
||||
<td>{mailType.map(data => data.value === mail.mail_type && data.name)}</td>
|
||||
<td>{mailReceiveType.map(data => data.value === mail.receive_type && data.name)}</td>
|
||||
<MailTitle>{mail.title}</MailTitle>
|
||||
<td>
|
||||
<Button theme="line" text="상세보기" handleClick={e => handleDetailModal(e, mail.id)} />
|
||||
</td>
|
||||
<td>{mail.create_by}</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
<Pagination postsPerPage={pageSize} totalPosts={dataList && dataList.total_all} setCurrentPage={setCurrentPage} currentPage={currentPage} pageLimit={10} />
|
||||
|
||||
<MailDetailModal detailView={detailView} handleDetailView={handleDetailView} content={detailData} />
|
||||
{/* 선택 삭제 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={deleteModalClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleDeleteModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">
|
||||
선택된 우편을 삭제하시겠습니까?
|
||||
<br />
|
||||
삭제 시 설정 정보가 제거됩니다.
|
||||
</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="취소" theme="line" size="large" width="100%" handleClick={handleDeleteModalClose} />
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleSelectedDelete} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
{/* 확인 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={confirmModalClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleConfirmeModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">삭제가 완료되었습니다.</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleConfirmeModalClose} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Mail;
|
||||
|
||||
const ListState = styled.span`
|
||||
color: #d60000;
|
||||
`;
|
||||
765
src/pages/ServiceManage/MailRegist.js
Normal file
765
src/pages/ServiceManage/MailRegist.js
Normal file
@@ -0,0 +1,765 @@
|
||||
import { useState, Fragment } from 'react';
|
||||
import Button from '../../components/common/button/Button';
|
||||
import RadioInput from '../../components/common/input/Radio';
|
||||
import CheckBox from '../../components/common/input/CheckBox';
|
||||
import Loading from '../../components/common/Loading';
|
||||
|
||||
import styled from 'styled-components';
|
||||
import { Title, BtnWrapper, TextInput, SelectInput, Label, InputLabel, DatePickerWrapper, Textarea, ModalText, ButtonClose, SearchBarAlert, AlertText } from '../../styles/Components';
|
||||
|
||||
import IconDelete from '../../assets/img/icon/icon-delete.png';
|
||||
import CloseIcon from '../../assets/img/icon/icon-close.png';
|
||||
|
||||
import { HourList, MinuteList, wellType } from '../../assets/data';
|
||||
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import MailRegistUploadBtn from '../../components/ServiceManage/MailRegistUploadBtn';
|
||||
import DatePickerComponent from '../../components/common/Date/DatePickerComponent';
|
||||
import Modal from '../../components/common/modal/Modal';
|
||||
import { MailIsItem, MailMultiRegsit, MailSingleRegist } from '../../apis';
|
||||
|
||||
import { authList } from '../../store/authList';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { MailReceiver, RegistInputRow } from '../../styles/ModuleComponents';
|
||||
import AuthModal from '../../components/common/modal/AuthModal';
|
||||
import { authType } from '../../assets/data';
|
||||
|
||||
const MailRegist = () => {
|
||||
const navigate = useNavigate();
|
||||
const userInfo = useRecoilValue(authList);
|
||||
const { t } = useTranslation();
|
||||
const environment = process.env.REACT_APP_ENV;
|
||||
|
||||
const [doubleSubmitFlag, setDoubleSubmitFlag] = useState(false);
|
||||
|
||||
const [sendHour, setSendHour] = useState('00');
|
||||
const [sendMin, setSendMin] = useState('00');
|
||||
|
||||
const [item, setItem] = useState('');
|
||||
const [itemCount, setItemCount] = useState('');
|
||||
const [resource, setResource] = useState('19010001');
|
||||
const [resourceCount, setResourceCount] = useState(0);
|
||||
|
||||
const [cancelModalClose, setCancelModalClose] = useState('hidden');
|
||||
const [submitModal, setSubmitModal] = useState('hidden');
|
||||
const [completeModal, setCompleteModal] = useState('hidden');
|
||||
const [isNullValue, setIsNullValue] = useState(false);
|
||||
const [btnValidation, setBtnValidation] = useState(false);
|
||||
|
||||
const [excelFile, setExcelFile] = useState(null);
|
||||
const [excelName, setExcelName] = useState(null);
|
||||
|
||||
const [isItemNullValue, setIsItemNullValue] = useState(false);
|
||||
const [isResourceNullValue, setIsResourceNullValue] = useState(false);
|
||||
const [confirmText, setConfirmText] = useState('');
|
||||
const [alertMessage, setAlertMessage] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const [resultData, setResultData] = useState({
|
||||
is_reserve: false,
|
||||
send_dt: '',
|
||||
mail_type: 'SELECT',
|
||||
receive_type: 'SINGLE',
|
||||
user_type: 'GUID',
|
||||
mail_list: [
|
||||
{
|
||||
title: '',
|
||||
content: '',
|
||||
language: 'KO',
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
content: '',
|
||||
language: 'EN',
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
content: '',
|
||||
language: 'JA',
|
||||
}
|
||||
],
|
||||
item_list: [],
|
||||
resource_list: [],
|
||||
guid: '',
|
||||
});
|
||||
|
||||
const benItems = [
|
||||
"19010003"
|
||||
];
|
||||
|
||||
// 아이템 수량 숫자 체크
|
||||
const handleItemCount = e => {
|
||||
if (e.target.value === '0' || e.target.value === '-0') {
|
||||
setItemCount('1');
|
||||
e.target.value = '1';
|
||||
} else if (e.target.value < 0) {
|
||||
let plusNum = Math.abs(e.target.value);
|
||||
setItemCount(plusNum);
|
||||
} else {
|
||||
setItemCount(e.target.value);
|
||||
}
|
||||
};
|
||||
|
||||
// 아이템 추가
|
||||
const handleItemList = async () => {
|
||||
if(benItems.includes(item) && environment === "live"){
|
||||
alert(t('MAIL_ITEM_ADD_BEN'))
|
||||
return;
|
||||
}
|
||||
item.length === 0 || itemCount.length === 0 ? setIsItemNullValue(true) : setIsItemNullValue(false);
|
||||
|
||||
const token = sessionStorage.getItem('token');
|
||||
const result = await MailIsItem(token, {item: item});
|
||||
|
||||
if(result.data.result === "ERROR"){
|
||||
alert(result.data.data.message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.length === '' || itemCount.length === 0 || itemCount <= 0) {
|
||||
setIsItemNullValue(true);
|
||||
} else if (item.length !== 0) {
|
||||
setIsItemNullValue(false);
|
||||
const itemIndex = resultData.item_list.findIndex(
|
||||
(item) => item.item === resource
|
||||
);
|
||||
|
||||
if (itemIndex !== -1) {
|
||||
alert(t('MAIL_ITEM_ADD_DUPL'));
|
||||
return;
|
||||
}
|
||||
const newItem = { item: item, item_cnt: itemCount, item_name: result.data.data.item_info.item_name };
|
||||
|
||||
resultData.item_list.push(newItem);
|
||||
setItem('');
|
||||
setItemCount('');
|
||||
}
|
||||
};
|
||||
|
||||
const onItemRemove = id => {
|
||||
let filterList = resultData.item_list && resultData.item_list.filter(item => item !== resultData.item_list[id]);
|
||||
setResultData({ ...resultData, item_list: filterList });
|
||||
};
|
||||
|
||||
// 입력창 삭제
|
||||
const onLangDelete = language => {
|
||||
let filterList = resultData.mail_list && resultData.mail_list.filter(el => el.language !== language);
|
||||
|
||||
if (filterList.length === 1) {
|
||||
setBtnValidation(true);
|
||||
} else {
|
||||
setBtnValidation(false);
|
||||
}
|
||||
|
||||
setResultData({ ...resultData, mail_list: filterList });
|
||||
};
|
||||
|
||||
// 자원 수량 숫자 체크
|
||||
const handleResourceCount = e => {
|
||||
if (e.target.value === '0' || e.target.value === '-0') {
|
||||
setResourceCount('1');
|
||||
e.target.value = '1';
|
||||
} else if (e.target.value < 0) {
|
||||
let plusNum = Math.abs(e.target.value);
|
||||
setResourceCount(plusNum);
|
||||
} else {
|
||||
setResourceCount(e.target.value);
|
||||
}
|
||||
};
|
||||
|
||||
// 자원 추가
|
||||
const handleResourceList = () => {
|
||||
resourceCount.length === 0 ? setIsItemNullValue(true) : setIsItemNullValue(false);
|
||||
|
||||
if (resourceCount.length === 0 || resourceCount <= 0) {
|
||||
setIsItemNullValue(true);
|
||||
} else {
|
||||
setIsItemNullValue(false);
|
||||
|
||||
const itemIndex = resultData.item_list.findIndex(
|
||||
(item) => item.item === resource
|
||||
);
|
||||
|
||||
if (itemIndex !== -1) {
|
||||
const item_cnt = resultData.item_list[itemIndex].item_cnt;
|
||||
resultData.item_list[itemIndex].item_cnt = Number(item_cnt) + Number(resourceCount);
|
||||
} else {
|
||||
const name = wellType.find(well => well.value === resource).name;
|
||||
const newItem = { item: resource, item_cnt: resourceCount, item_name: name };
|
||||
resultData.item_list.push(newItem);
|
||||
}
|
||||
|
||||
setResourceCount('');
|
||||
}
|
||||
};
|
||||
|
||||
const onResourceRemove = id => {
|
||||
let filterList = resultData.resource_list && resultData.resource_list.filter(item => item !== resultData.resource_list[id]);
|
||||
setResultData({ ...resultData, resource_list: filterList });
|
||||
};
|
||||
|
||||
// 발송 날짜 세팅 로직
|
||||
const handleSelectedDate = data => {
|
||||
const sendDate = new Date(data);
|
||||
|
||||
const resultSendData = new Date(sendDate.getFullYear(), sendDate.getMonth(), sendDate.getDate(), sendHour, sendMin);
|
||||
|
||||
setResultData({ ...resultData, send_dt: resultSendData });
|
||||
};
|
||||
|
||||
// 발송 시간 세팅 로직
|
||||
const handleSendTime = e => {
|
||||
let sendDate = '';
|
||||
|
||||
if (resultData.send_dt.length === 0 || typeof resultData.send_dt.length != 'undefined') {
|
||||
sendDate = new Date();
|
||||
} else {
|
||||
sendDate = new Date(resultData.send_dt);
|
||||
}
|
||||
|
||||
if (e.target.id === 'hour') setSendHour(e.target.value);
|
||||
else if (e.target.id === 'min') setSendMin(e.target.value);
|
||||
|
||||
const result = new Date(sendDate.getFullYear(), sendDate.getMonth(), sendDate.getDate(), e.target.id === 'hour' ? e.target.value : sendHour, e.target.id === 'min' ? e.target.value : sendMin);
|
||||
|
||||
setResultData({ ...resultData, send_dt: result });
|
||||
};
|
||||
|
||||
const handleSubmitModal = () => {
|
||||
if (
|
||||
resultData.mail_list.map(data => data.content === '' || data.title === '').includes(true) ||
|
||||
(resultData.receive_type === 'MULTIPLE' ? excelFile === null : resultData.guid === '') ||
|
||||
(resultData.is_reserve && resultData.send_dt.length === 0) ||
|
||||
resultData.mail_type === 'SELECT' ||
|
||||
alertMessage
|
||||
) {
|
||||
setIsNullValue(true);
|
||||
} else if (submitModal === 'hidden') {
|
||||
setIsNullValue(false);
|
||||
setSubmitModal('view');
|
||||
} else {
|
||||
setSubmitModal('hidden');
|
||||
}
|
||||
};
|
||||
|
||||
// 취소 모달
|
||||
const handleCancelModalClose = () => {
|
||||
if (cancelModalClose === 'hidden') {
|
||||
setCancelModalClose('view');
|
||||
} else {
|
||||
setCancelModalClose('hidden');
|
||||
setConfirmText(t('MAIL_CANCEL'));
|
||||
}
|
||||
};
|
||||
|
||||
// 완료 모달창
|
||||
const handleCompleteModal = () => {
|
||||
if (completeModal === 'hidden') {
|
||||
setCompleteModal('view');
|
||||
} else {
|
||||
setCompleteModal('hidden');
|
||||
|
||||
navigate('/servicemanage/mail');
|
||||
}
|
||||
};
|
||||
|
||||
const handleRegistMail = async () => {
|
||||
setLoading(true);
|
||||
const token = sessionStorage.getItem('token');
|
||||
const message = await MailSingleRegist(token, resultData);
|
||||
|
||||
if (message.data.data.message === t('EXCEL_SELECT')) {
|
||||
setConfirmText('파일 내 중복된 유저 정보가 있습니다. \n 파일을 다시 확인 후 이용해주세요.');
|
||||
} else if (message.data.data.message === '저장 하였습니다.') {
|
||||
setConfirmText('우편이 정상 등록되었습니다.');
|
||||
} else {
|
||||
setConfirmText(message.data.data.message);
|
||||
}
|
||||
setLoading(false);
|
||||
handleCompleteModal();
|
||||
handleSubmitModal();
|
||||
};
|
||||
|
||||
const handleSingleBtn = () => {
|
||||
setResultData({ ...resultData, guid: '' });
|
||||
delete resultData.file_name;
|
||||
|
||||
document.querySelector('#fileinput').value = '';
|
||||
|
||||
setExcelFile(null);
|
||||
};
|
||||
|
||||
const handleMultiBtn = () => {
|
||||
delete resultData.guid;
|
||||
};
|
||||
// console.log('alertMessage', alertMessage);
|
||||
// console.log('resultData: ', resultData);
|
||||
|
||||
return (
|
||||
<>
|
||||
{userInfo.auth_list && !userInfo.auth_list.some(auth => auth.id === authType.mailUpdate) ? (
|
||||
<AuthModal/>
|
||||
) : (
|
||||
<>
|
||||
<Title>우편 등록</Title>
|
||||
|
||||
<RegistGroup>
|
||||
<RegistInputRow>
|
||||
<CheckBox
|
||||
label="예약 발송"
|
||||
id="reserve"
|
||||
checked={resultData.is_reserve}
|
||||
setData={e => setResultData({ ...resultData, is_reserve: e.target.checked, send_dt: new Date() })}
|
||||
/>
|
||||
<InputItem>
|
||||
{resultData.is_reserve && (
|
||||
<>
|
||||
<InputLabel>발송 시간</InputLabel>
|
||||
<InputGroup>
|
||||
<DatePickerWrapper>
|
||||
<DatePickerComponent name="시작 일자" selectedDate={resultData.send_dt} handleSelectedDate={data => handleSelectedDate(data)} pastDate={new Date()} />
|
||||
</DatePickerWrapper>
|
||||
<SelectInput onChange={e => handleSendTime(e)} id="hour">
|
||||
{HourList.map(hour => (
|
||||
<option value={hour} key={hour}>
|
||||
{hour}
|
||||
</option>
|
||||
))}
|
||||
</SelectInput>
|
||||
<SelectInput onChange={e => handleSendTime(e)} id="min">
|
||||
{MinuteList.map(min => (
|
||||
<option value={min} key={min}>
|
||||
{min}
|
||||
</option>
|
||||
))}
|
||||
</SelectInput>
|
||||
</InputGroup>
|
||||
</>
|
||||
)}
|
||||
</InputItem>
|
||||
<InputItem>
|
||||
<InputLabel>우편 타입</InputLabel>
|
||||
<SelectInput onChange={e => setResultData({ ...resultData, mail_type: e.target.value })} value={resultData.mail_type}>
|
||||
<option value="SELECT">타입 선택</option>
|
||||
<option value="SYSTEM_GUID">시스템 안내</option>
|
||||
<option value="INSPECTION_COMPENSATION">점검 보상</option>
|
||||
<option value="RECOVER_COMPENSATION">복구 보상</option>
|
||||
<option value="EVENT_COMPENSATION">이벤트 보상</option>
|
||||
</SelectInput>
|
||||
</InputItem>
|
||||
</RegistInputRow>
|
||||
<MailNotice>* 예약 발송 미선택 시 등록과 함께 우편이 즉시 발송됩니다.</MailNotice>
|
||||
<MailReceiver>
|
||||
<InputItem>
|
||||
<InputLabel>수신대상</InputLabel>
|
||||
<InputItem>
|
||||
<SelectInput onChange={e => setResultData({ ...resultData, user_type: e.target.value })} value={resultData.user_type} disabled={resultData.receive_type !== 'SINGLE'}>
|
||||
<option value="GUID">GUID</option>
|
||||
<option value="NICKNAME">아바타명</option>
|
||||
<option value="EMAIL">이메일</option>
|
||||
</SelectInput>
|
||||
</InputItem>
|
||||
<div>
|
||||
<InputGroup>
|
||||
<RadioInput
|
||||
label="단일"
|
||||
id="SINGLE"
|
||||
name="receiver"
|
||||
value="SINGLE"
|
||||
fontWeight="600"
|
||||
checked={resultData.receive_type === 'SINGLE'}
|
||||
handleChange={e => setResultData({ ...resultData, receive_type: e.target.id })}
|
||||
handleClick={handleSingleBtn}
|
||||
/>
|
||||
<TextInput
|
||||
placeholder={resultData.user_type === "GUID" ? "GUID 입력" : resultData.user_type === "NICKNAME" ? "아바타명 입력" : "이메일 입력"}
|
||||
disabled={resultData.receive_type !== 'SINGLE'}
|
||||
onChange={e => setResultData({ ...resultData, guid: e.target.value })}
|
||||
value={resultData.receive_type === 'SINGLE' && resultData.guid ? resultData.guid : ''}
|
||||
/>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<RadioInput
|
||||
label="복수"
|
||||
id="MULTIPLE"
|
||||
name="receiver"
|
||||
value="MULTIPLE"
|
||||
fontWeight="600"
|
||||
checked={resultData.receive_type === 'MULTIPLE'}
|
||||
handleChange={e => setResultData({ ...resultData, receive_type: e.target.id })}
|
||||
handleClick={handleMultiBtn}
|
||||
/>
|
||||
<MailRegistUploadBtn
|
||||
disabled={resultData.receive_type !== 'MULTIPLE'}
|
||||
setResultData={setResultData}
|
||||
resultData={resultData}
|
||||
excelFile={excelFile}
|
||||
alertMessage={alertMessage}
|
||||
setAlertMessage={setAlertMessage}
|
||||
setExcelFile={setExcelFile}
|
||||
excelName={excelName}
|
||||
setExcelName={setExcelName}
|
||||
/>
|
||||
</InputGroup>
|
||||
</div>
|
||||
</InputItem>
|
||||
</MailReceiver>
|
||||
</RegistGroup>
|
||||
{resultData.mail_list.map((data, idx) => {
|
||||
return (
|
||||
<Fragment key={idx}>
|
||||
<MailRegistBox>
|
||||
<LangArea>
|
||||
언어 : {data.language}
|
||||
{btnValidation === false ? (
|
||||
<BtnClose
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
onLangDelete(data.language);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<BtnClose opacity="10%" />
|
||||
)}
|
||||
</LangArea>
|
||||
<MailRegistTable>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th width="120">
|
||||
<Label>제목</Label>
|
||||
</th>
|
||||
<td>
|
||||
<InputItem>
|
||||
<TextInput
|
||||
placeholder="우편 제목 입력"
|
||||
maxLength="30"
|
||||
id={data.language}
|
||||
value={data.title}
|
||||
onChange={e => {
|
||||
if (e.target.value.length > 30) {
|
||||
return;
|
||||
}
|
||||
let list = [...resultData.mail_list];
|
||||
let findIndex = resultData.mail_list && resultData.mail_list.findIndex(item => item.language === e.target.id);
|
||||
list[findIndex].title = e.target.value.trimStart();
|
||||
|
||||
setResultData({ ...resultData, mail_list: list });
|
||||
}}
|
||||
/>
|
||||
</InputItem>
|
||||
<MailNotice $color={data.title.length > 29 ? 'red' : '#666'}>* 최대 등록 가능 글자수 ({data.title.length}/30자)</MailNotice>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
<Label>내용</Label>
|
||||
</th>
|
||||
<td>
|
||||
<Textarea
|
||||
maxLength="2000"
|
||||
value={data.content}
|
||||
id={data.language}
|
||||
onChange={e => {
|
||||
if (e.target.value.length > 2000) {
|
||||
return;
|
||||
}
|
||||
let list = [...resultData.mail_list];
|
||||
let findIndex = resultData.mail_list && resultData.mail_list.findIndex(item => item.language === e.target.id);
|
||||
list[findIndex].content = e.target.value.trimStart();
|
||||
|
||||
setResultData({ ...resultData, mail_list: list });
|
||||
}}
|
||||
/>
|
||||
<MailNotice $color={data.content.length > 1999 ? 'red' : '#666'}>* 최대 등록 가능 글자수 ({data.content.length}/2000자)</MailNotice>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</MailRegistTable>
|
||||
</MailRegistBox>
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
|
||||
<MailRegistBox>
|
||||
<MailRegistTable>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th width="120">
|
||||
<Label>아이템 첨부</Label>
|
||||
</th>
|
||||
<td>
|
||||
<InputItem>
|
||||
<TextInput placeholder="Item Meta id 입력" value={item} onChange={e => setItem(e.target.value.trimStart())} />
|
||||
<TextInput placeholder="수량" type="number" value={itemCount} onChange={e => handleItemCount(e)} width="100px" />
|
||||
<Button text="추가" theme={itemCount.length === 0 || item.length === 0 ? 'disable' : 'search'} handleClick={handleItemList} width="100px" height="35px" />
|
||||
</InputItem>
|
||||
{/* {isItemNullValue && <SearchBarAlert $marginTop="15px">필수값을 입력해주세요.</SearchBarAlert>}
|
||||
|
||||
<div>
|
||||
{resultData.item_list && (
|
||||
<ItemList>
|
||||
{resultData.item_list.map((data, index) => {
|
||||
return (
|
||||
<Item key={index}>
|
||||
<span>
|
||||
{data.item}({data.item_cnt})
|
||||
</span>
|
||||
<BtnDelete onClick={() => onItemRemove(index)}></BtnDelete>
|
||||
</Item>
|
||||
);
|
||||
})}
|
||||
</ItemList>
|
||||
)}
|
||||
</div> */}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th width="120">
|
||||
<Label>자원 첨부</Label>
|
||||
</th>
|
||||
<td>
|
||||
<InputItem>
|
||||
<SelectInput onChange={e => setResource(e.target.value)} value={resource}>
|
||||
<option value="19010001">골드</option>
|
||||
<option value="19010002">사파이어</option>
|
||||
<option value="19010005">루비</option>
|
||||
</SelectInput>
|
||||
<TextInput placeholder="수량" type="number" value={resourceCount} onChange={e => handleResourceCount(e)} width="200px" />
|
||||
<Button text="추가" theme={resourceCount.length === 0 || resource.length === 0 ? 'disable' : 'search'} handleClick={handleResourceList} width="100px" height="35px" />
|
||||
</InputItem>
|
||||
{isItemNullValue && <SearchBarAlert $marginTop="15px">필수값을 입력해주세요.</SearchBarAlert>}
|
||||
|
||||
<div>
|
||||
{resultData.item_list && (
|
||||
<ItemList>
|
||||
{resultData.item_list.map((data, index) => {
|
||||
return (
|
||||
<Item key={index}>
|
||||
<span>
|
||||
{data.item_name}[{data.item}] ({data.item_cnt})
|
||||
</span>
|
||||
<BtnDelete onClick={() => onItemRemove(index)}></BtnDelete>
|
||||
</Item>
|
||||
);
|
||||
})}
|
||||
</ItemList>
|
||||
)}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</MailRegistTable>
|
||||
</MailRegistBox>
|
||||
{isNullValue && (
|
||||
<SearchBarAlert $align="right" $padding="0 0 15px">
|
||||
필수값을 입력해주세요.
|
||||
</SearchBarAlert>
|
||||
)}
|
||||
|
||||
<BtnWrapper $justify="flex-end" $gap="10px">
|
||||
<Button text="취소" theme="line" handleClick={handleCancelModalClose} />
|
||||
<Button
|
||||
type="submit"
|
||||
text="등록"
|
||||
theme={
|
||||
resultData.mail_list.map(data => data.content === '' || data.title === '').includes(true) ||
|
||||
(resultData.receive_type === 'MULTIPLE' ? excelFile === null : resultData.guid === '') ||
|
||||
(resultData.is_reserve && resultData.send_dt.length === 0) ||
|
||||
resultData.mail_type === 'SELECT' ||
|
||||
alertMessage
|
||||
? 'disable'
|
||||
: 'primary'
|
||||
}
|
||||
handleClick={handleSubmitModal}
|
||||
/>
|
||||
</BtnWrapper>
|
||||
{/* 등록 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={submitModal}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleSubmitModal} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">우편을 등록하시겠습니까?</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="취소" theme="line" size="large" width="100%" handleClick={handleSubmitModal} />
|
||||
<Button
|
||||
text="확인"
|
||||
theme="primary"
|
||||
type="submit"
|
||||
size="large"
|
||||
width="100%"
|
||||
handleClick={() => {
|
||||
doubleSubmitFlag || handleRegistMail();
|
||||
setDoubleSubmitFlag(true);
|
||||
}}
|
||||
/>
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
{/* 완료 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={completeModal}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleCompleteModal} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">{confirmText}</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleCompleteModal} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
{/* 취소 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={cancelModalClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleCancelModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">
|
||||
우편 등록을 취소하시겠습니까?
|
||||
<br />
|
||||
취소 시 설정된 값은 반영되지 않습니다.
|
||||
</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="취소" theme="line" size="large" width="100%" handleClick={handleCancelModalClose} />
|
||||
<Button
|
||||
text="확인"
|
||||
theme="primary"
|
||||
type="submit"
|
||||
size="large"
|
||||
width="100%"
|
||||
handleClick={() => {
|
||||
handleCancelModalClose();
|
||||
handleCompleteModal();
|
||||
}}
|
||||
/>
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
{loading && <Loading/>}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default MailRegist;
|
||||
|
||||
const InputRow = styled.div`
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px 50px;
|
||||
`;
|
||||
|
||||
const InputItem = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
${TextInput},${SelectInput} {
|
||||
height: 35px;
|
||||
font-size: 14px;
|
||||
}
|
||||
${TextInput} {
|
||||
padding: 0 20px;
|
||||
}
|
||||
${SelectInput} {
|
||||
width: max-content;
|
||||
}
|
||||
`;
|
||||
|
||||
const InputGroup = styled.div`
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const MailNotice = styled.span`
|
||||
font-size: 12px;
|
||||
font-weight: 300;
|
||||
color: ${props => props.$color || '#999'};
|
||||
margin-top: 10px;
|
||||
display: block;
|
||||
`;
|
||||
const RegistGroup = styled.div`
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-flow: column;
|
||||
padding: 20px;
|
||||
border-top: 1px solid #000;
|
||||
border-bottom: 1px solid #000;
|
||||
font-size: 14px;
|
||||
margin-bottom: 40px;
|
||||
|
||||
${MailNotice} {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
`;
|
||||
|
||||
const BtnClose = styled.button`
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: url(${CloseIcon}) 50% 50% no-repeat;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translate(0, -50%);
|
||||
right: 20px;
|
||||
opacity: ${props => props.opacity};
|
||||
`;
|
||||
|
||||
const LangArea = styled.div`
|
||||
background: #f9f9f9;
|
||||
padding: 10px 20px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
position: relative;
|
||||
`;
|
||||
|
||||
const MailRegistBox = styled.div`
|
||||
margin-bottom: 20px;
|
||||
border-top: 1px solid #999;
|
||||
border-bottom: 1px solid #999;
|
||||
`;
|
||||
|
||||
const MailRegistTable = styled.table`
|
||||
th {
|
||||
vertical-align: top;
|
||||
line-height: 35px;
|
||||
}
|
||||
th,
|
||||
td {
|
||||
padding: 15px 0;
|
||||
border-bottom: 1px solid #f6f6f6;
|
||||
}
|
||||
td {
|
||||
${InputItem} {
|
||||
gap: 5px;
|
||||
}
|
||||
${TextInput} {
|
||||
max-width: 600px;
|
||||
padding: 0 15px;
|
||||
}
|
||||
${Textarea} {
|
||||
width: 100%;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 5px;
|
||||
height: 255px;
|
||||
padding: 15px;
|
||||
&:focus {
|
||||
border: 1px solid #2c2c2c;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const ItemList = styled.ul`
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px;
|
||||
padding: 10px 20px;
|
||||
`;
|
||||
|
||||
const Item = styled.li`
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const BtnDelete = styled.button`
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background: url(${IconDelete}) 50% 50% no-repeat;
|
||||
`;
|
||||
344
src/pages/ServiceManage/ReportList.js
Normal file
344
src/pages/ServiceManage/ReportList.js
Normal file
@@ -0,0 +1,344 @@
|
||||
import { Fragment, useEffect, useState } from 'react';
|
||||
|
||||
import CheckBox from '../../components/common/input/CheckBox';
|
||||
|
||||
import styled from 'styled-components';
|
||||
import { Title, FormWrapper, TableInfo, ListCount, ListOption, TableStyle, SelectInput, TableWrapper, ButtonClose, ModalText, BtnWrapper } from '../../styles/Components';
|
||||
import Button from '../../components/common/button/Button';
|
||||
|
||||
import { ReportListDetailModal, ReportListAnswerModal, ReportListSearchBar, ReportListSummary } from '../../components/ServiceManage';
|
||||
import Modal from '../../components/common/modal/Modal';
|
||||
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { authList } from '../../store/authList';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { ReportListView, ReportListDetailView, ReportReplyDetail } from '../../apis/Report';
|
||||
import Pagination from '../../components/common/Pagination/Pagination';
|
||||
import { convertKTC } from '../../utils';
|
||||
import AuthModal from '../../components/common/modal/AuthModal';
|
||||
import { authType } from '../../assets/data';
|
||||
import ViewTableInfo from '../../components/common/Table/ViewTableInfo';
|
||||
|
||||
const reportType = [
|
||||
{ value: 'ALL', name: '전체' },
|
||||
{ value: 'UNMANNERED_ACT', name: '비매너 행위' },
|
||||
{ value: 'USE_UNHEALTHY_NAMES', name: '불건전 이름 사용' },
|
||||
{ value: 'CASH_TRADING', name: '현금거래 행위' },
|
||||
{ value: 'INTERFERENCE_GAME', name: '게임 진행 방해' },
|
||||
{ value: 'INTERFERENCE_SERVICE', name: '운영서비스 방해' },
|
||||
{ value: 'ACCOUNT_EXPLOITATION', name: '계정도용' },
|
||||
{ value: 'BUG_ABUSING', name: '버그/어뷰징' },
|
||||
{ value: 'USE_HACK', name: '불법프로그램 사용' },
|
||||
{ value: 'LEAK_PERSONAL_INFO', name: '개인정보 유출' },
|
||||
{ value: 'PRETENDING_GM', name: '운영자 사칭' },
|
||||
];
|
||||
|
||||
const ReportList = () => {
|
||||
const navigate = useNavigate();
|
||||
const token = sessionStorage.getItem('token');
|
||||
const userInfo = useRecoilValue(authList);
|
||||
|
||||
// 권한 설정용
|
||||
let deleteAuth = userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === 31); // 삭제 권한
|
||||
let replyAuth = userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === 31); // 답변 권한
|
||||
|
||||
let d = new Date();
|
||||
const START_DATE = new Date(new Date(d.setDate(d.getDate() - 1)).setHours(0, 0, 0, 0));
|
||||
const END_DATE = new Date();
|
||||
|
||||
// 페이징용
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [pageSize, setPageSize] = useState(50);
|
||||
const [selectedRow, setSelectedRow] = useState([]);
|
||||
|
||||
const [searchData, setSearchData] = useState({
|
||||
startDate: START_DATE,
|
||||
endDate: END_DATE,
|
||||
reportType: 'ALL',
|
||||
status: 'ALL',
|
||||
searchType: 'ALL',
|
||||
searchKey: '',
|
||||
});
|
||||
const [orderBy, setOrderBy] = useState('DESC');
|
||||
const [detailView, setDetailView] = useState('hidden');
|
||||
const [answerView, setAnswerView] = useState('hidden');
|
||||
|
||||
const [dataList, setDataList] = useState([]);
|
||||
|
||||
// 신고내역 상세 조회용
|
||||
const [detailData, setDetailData] = useState([]);
|
||||
|
||||
// 신고답변 상세 조회용
|
||||
const [replyData, setReplyData] = useState([]);
|
||||
const [pkId, setPkId] = useState('');
|
||||
const [skId, setSkId] = useState('');
|
||||
|
||||
const [deleteModalClose, setDeleteModalClose] = useState('hidden');
|
||||
const [confirmModalClose, setConfirmModalClose] = useState('hidden');
|
||||
|
||||
useEffect(() => {
|
||||
fetchData(START_DATE, END_DATE, 'ALL', 'ALL', 'ALL', '');
|
||||
}, [currentPage]);
|
||||
|
||||
const fetchData = async (startDate, endDate, reportType, status, searchType, searchKey, order, size) => {
|
||||
await ReportListView(
|
||||
token,
|
||||
startDate && new Date(startDate).toISOString().split('.')[0],
|
||||
endDate && new Date(endDate).toISOString().split('.')[0],
|
||||
reportType && reportType,
|
||||
status && status,
|
||||
searchType && searchType,
|
||||
searchKey && searchKey,
|
||||
order ? order : orderBy,
|
||||
size ? size : pageSize,
|
||||
currentPage,
|
||||
).then(data => {
|
||||
setDataList(data);
|
||||
})
|
||||
};
|
||||
|
||||
const handlePageSize = e => {
|
||||
const size = e.target.value;
|
||||
setPageSize(size);
|
||||
setCurrentPage(1);
|
||||
|
||||
fetchData(searchData.startDate, searchData.endDate, searchData.reportType, searchData.status, searchData.searchType, searchData.searchKey, orderBy, size, 1);
|
||||
};
|
||||
|
||||
const handleDetail = async (e, pk, sk) => {
|
||||
const pkData = encodeURIComponent(pk);
|
||||
const skData = encodeURIComponent(sk);
|
||||
|
||||
e.preventDefault();
|
||||
setPkId(pk);
|
||||
setSkId(sk);
|
||||
|
||||
setDetailData(await ReportListDetailView(token, pkData, skData));
|
||||
|
||||
handleDetailView();
|
||||
};
|
||||
|
||||
// 상세 정보 모달 띄우기
|
||||
const handleDetailView = () => {
|
||||
if (detailView === 'hidden') {
|
||||
setDetailView('block');
|
||||
} else {
|
||||
setDetailView('hidden');
|
||||
}
|
||||
};
|
||||
|
||||
// 신고 답변 불러오기
|
||||
const handleReply = async e => {
|
||||
const pk = encodeURIComponent(pkId);
|
||||
const sk = encodeURIComponent(skId);
|
||||
|
||||
setReplyData(await ReportReplyDetail(token, pk, sk));
|
||||
handleReplyView();
|
||||
};
|
||||
|
||||
// 답변 모달 띄우기
|
||||
const handleReplyView = () => {
|
||||
if (answerView === 'hidden') {
|
||||
setDetailView('hidden');
|
||||
setAnswerView('block');
|
||||
} else {
|
||||
setAnswerView('hidden');
|
||||
setDetailView('block');
|
||||
}
|
||||
};
|
||||
|
||||
// 검색 함수
|
||||
const handleSearch = (startDate, endDate, reportType, status, searchType, searchKey) => {
|
||||
fetchData(startDate && new Date(startDate).toISOString(), endDate && new Date(endDate).toISOString(), reportType, status, searchType, searchKey, orderBy, pageSize);
|
||||
};
|
||||
|
||||
// 오름차순 내림차순
|
||||
const handleOrderBy = e => {
|
||||
const order = e.target.value;
|
||||
|
||||
setOrderBy(order);
|
||||
fetchData(
|
||||
searchData.startDate && new Date(searchData.startDate).toISOString().split('.')[0],
|
||||
searchData.endDate && new Date(searchData.endDate).toISOString().split('.')[0],
|
||||
searchData.reportType,
|
||||
searchData.status,
|
||||
searchData.searchKey,
|
||||
order,
|
||||
pageSize,
|
||||
);
|
||||
};
|
||||
|
||||
// 선택 삭제 함수
|
||||
const handleSelectedDelete = () => {
|
||||
let list = [];
|
||||
|
||||
selectedRow.map(data =>
|
||||
list.push({
|
||||
id: data,
|
||||
}),
|
||||
);
|
||||
|
||||
// ReportDelete(token, list);
|
||||
|
||||
handleDeleteModalClose();
|
||||
handleConfirmeModalClose();
|
||||
};
|
||||
|
||||
// 선택 삭제 모달
|
||||
const handleDeleteModalClose = () => {
|
||||
if (selectedRow.length !== 0 && deleteModalClose === 'hidden') {
|
||||
setDeleteModalClose('view');
|
||||
} else {
|
||||
setDeleteModalClose('hidden');
|
||||
}
|
||||
};
|
||||
|
||||
// 삭제, 승인, 저장 확인 모달창
|
||||
const handleConfirmeModalClose = () => {
|
||||
if (confirmModalClose === 'hidden') {
|
||||
setConfirmModalClose('view');
|
||||
} else {
|
||||
setConfirmModalClose('hidden');
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
// 체크박스 선택 리스트
|
||||
const handleSelectCheckBox = e => {
|
||||
let list = [...selectedRow];
|
||||
if (e.target.checked) {
|
||||
list.push(e.target.id);
|
||||
setSelectedRow(list);
|
||||
} else {
|
||||
const filterList = list.filter(data => e.target.id !== data);
|
||||
setSelectedRow(filterList);
|
||||
}
|
||||
};
|
||||
|
||||
// 전체 선택 구현
|
||||
const handleAllSelect = () => {
|
||||
let list = [];
|
||||
if (document.getElementById('check-all').checked === true) {
|
||||
dataList.list &&
|
||||
dataList.list.map((data, index) => {
|
||||
document.getElementsByName('select')[index].checked = true;
|
||||
list.push(String(data.id));
|
||||
});
|
||||
} else if (document.getElementById('check-all').checked === false) {
|
||||
for (let i = 0; i < dataList.list.length; i++) {
|
||||
dataList.list && dataList.list.map((data, index) => (document.getElementsByName('select')[index].checked = false));
|
||||
list = [];
|
||||
}
|
||||
}
|
||||
setSelectedRow(list);
|
||||
};
|
||||
|
||||
const handleCountSelectedRow = () => {
|
||||
return currentPage > (dataList && dataList.total) / pageSize ? selectedRow.length === dataList.total % pageSize : selectedRow.length === Number(pageSize);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{userInfo.auth_list && !userInfo.auth_list.some(auth => auth.id === authType.reportRead) ? (
|
||||
<AuthModal/>
|
||||
) : (
|
||||
<>
|
||||
<Title>신고내역 조회 및 답변</Title>
|
||||
<ReportListSummary />
|
||||
<FormWrapper>
|
||||
<ReportListSearchBar handleSearch={handleSearch} setResultData={setSearchData} />
|
||||
</FormWrapper>
|
||||
<ViewTableInfo handlePageSize={handlePageSize} handleOrderBy={handleOrderBy} total={dataList.total} total_all={dataList.total_all}>
|
||||
{deleteAuth && <Button theme={'disable'} text="선택 삭제" />}
|
||||
</ViewTableInfo>
|
||||
<TableWrapper>
|
||||
<TableStyle>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="40">
|
||||
<CheckBox id="check-all" handleCheck={handleAllSelect} checked={handleCountSelectedRow()} />
|
||||
</th>
|
||||
<th width="80">번호</th>
|
||||
<th width="180">신고일자</th>
|
||||
<th width="200">신고자</th>
|
||||
<th width="15%">신고 유형</th>
|
||||
<th width="110">확인 / 답변</th>
|
||||
<th width="90">상태</th>
|
||||
<th width="180">해결 일자</th>
|
||||
<th width="15%">담당자(이메일주소)</th>
|
||||
{deleteAuth && <th width="80">삭제</th>}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList.list &&
|
||||
dataList.list.map((report, index) => (
|
||||
<Fragment key={index}>
|
||||
<tr>
|
||||
<td>
|
||||
<CheckBox name={'select'} id={report.row_num} setData={e => handleSelectCheckBox(e)} />
|
||||
</td>
|
||||
<td>{report.row_num}</td>
|
||||
<td>{convertKTC(report.create_time, false)}</td>
|
||||
<td>{report.reporter_nickname}</td>
|
||||
<td>{reportType.map(data => data.value === report.report_type && data.name)}</td>
|
||||
<td>
|
||||
<Button theme="line" text="상세보기" handleClick={e => handleDetail(e, report.pk, report.sk)} />
|
||||
</td>
|
||||
<td>{report.state === 'UNRESOLVED' ? <ListState>미해결</ListState> : '해결'}</td>
|
||||
<td>
|
||||
{report.resolution_time && convertKTC(report.resolution_time, false)}
|
||||
</td>
|
||||
<td>{report.manager_email}</td>
|
||||
{deleteAuth && (
|
||||
<td>
|
||||
<Button theme="line" text="삭제" />
|
||||
</td>
|
||||
)}
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
|
||||
<Pagination postsPerPage={pageSize} totalPosts={dataList && dataList.total_all} setCurrentPage={setCurrentPage} currentPage={currentPage} pageLimit={10} />
|
||||
|
||||
<ReportListDetailModal detailView={detailView} handleReply={handleReply} handleDetailView={handleDetailView} detailData={detailData} replyData={replyData} replyAuth={replyAuth} />
|
||||
<ReportListAnswerModal answerView={answerView} setAnswerView={setAnswerView} detailData={detailData} replyData={replyData} pkId={pkId} skId={skId} />
|
||||
{/* 선택 삭제 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={deleteModalClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleDeleteModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">
|
||||
선택된 우편을 삭제하시겠습니까?
|
||||
<br />
|
||||
삭제 시 설정 정보가 제거됩니다.
|
||||
</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="취소" theme="line" size="large" width="100%" handleClick={handleDeleteModalClose} />
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleSelectedDelete} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
{/* 확인 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={confirmModalClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleConfirmeModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">삭제가 완료되었습니다.</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleConfirmeModalClose} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ReportList;
|
||||
|
||||
const ListState = styled.span`
|
||||
color: #d60000;
|
||||
`;
|
||||
339
src/pages/ServiceManage/UserBlock.js
Normal file
339
src/pages/ServiceManage/UserBlock.js
Normal file
@@ -0,0 +1,339 @@
|
||||
import { useState, Fragment, useEffect } from 'react';
|
||||
import CheckBox from '../../components/common/input/CheckBox';
|
||||
import Modal from '../../components/common/modal/Modal';
|
||||
import Button from '../../components/common/button/Button';
|
||||
import styled from 'styled-components';
|
||||
import { Title, FormWrapper, TableInfo, ListCount, ListOption, TableStyle, SelectInput, TableWrapper, BtnWrapper, ButtonClose, ModalText } from '../../styles/Components';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { UserBlockDetailModal, UserBlockSearchBar } from '../../components/ServiceManage/';
|
||||
import { BlackListView, BlackListDetail, BlackListDelete } from '../../apis';
|
||||
import Pagination from '../../components/common/Pagination/Pagination';
|
||||
|
||||
import { authList } from '../../store/authList';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { authType, blockPeriod, blockSanctions, blockStatus } from '../../assets/data';
|
||||
import AuthModal from '../../components/common/modal/AuthModal';
|
||||
|
||||
const UserBlock = () => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
const userInfo = useRecoilValue(authList);
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
// 페이지 네이션 관련
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [pageSize, setPageSize] = useState(50);
|
||||
|
||||
// 데이터 조회 관련
|
||||
const [dataList, setDataList] = useState([]);
|
||||
const [detailView, setDetailView] = useState('hidden');
|
||||
const [selectedRow, setSelectedRow] = useState([]);
|
||||
const [selectedData, setSelectedData] = useState([]);
|
||||
const [detail, setDetail] = useState([]);
|
||||
const [requestValue, setRequestValue] = useState([]);
|
||||
|
||||
// 모달 관련 변수
|
||||
const [confirmModal, setConfirmModal] = useState('hidden');
|
||||
const [completeModal, setCompleteModal] = useState('hidden');
|
||||
|
||||
// 검색 관련 변수
|
||||
const [orderBy, setOrderBy] = useState('DESC');
|
||||
const [searchData, setSearchData] = useState({
|
||||
searchType: 'GUID',
|
||||
searchKey: '',
|
||||
status: 'ALL',
|
||||
sanctions: 'ALL',
|
||||
period: 'ALL',
|
||||
});
|
||||
|
||||
// 등록하기 모달 연결
|
||||
const handleDetail = async dataValue => {
|
||||
if (detailView === 'hidden') {
|
||||
setDetailView('block');
|
||||
} else {
|
||||
setDetailView('hidden');
|
||||
setDetail([]);
|
||||
}
|
||||
|
||||
setSelectedData(dataValue);
|
||||
|
||||
const id = dataValue.id;
|
||||
|
||||
if (id) {
|
||||
setDetail(await BlackListDetail(token, id));
|
||||
}
|
||||
};
|
||||
|
||||
const fetchData = async (searchType, data, email, status, sanctions, period, order, size) => {
|
||||
setDataList(await BlackListView(token, searchType, data, email, status, sanctions, period, order ? order : orderBy, size ? size : pageSize, currentPage));
|
||||
};
|
||||
|
||||
// 검색 기능
|
||||
const handleSearch = (searchType, data, email, status, sanctions, period) => {
|
||||
fetchData(searchType, data, email, status, sanctions, period);
|
||||
};
|
||||
|
||||
// 배열 정렬
|
||||
const handleOrderBy = e => {
|
||||
const order = e.target.value;
|
||||
|
||||
setOrderBy(order);
|
||||
fetchData(searchData.searchType, searchData.searchKey, searchData.email, searchData.status, searchData.sanctions, searchData.period, order, pageSize);
|
||||
};
|
||||
|
||||
const handlePageSize = e => {
|
||||
const size = e.target.value;
|
||||
setPageSize(size);
|
||||
setCurrentPage(1);
|
||||
|
||||
fetchData(searchData.searchType, searchData.searchKey, searchData.email, searchData.status, searchData.sanctions, searchData.period, orderBy, size, 1);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchData(searchData.searchType, searchData.searchKey, searchData.email, searchData.status, searchData.sanctions, searchData.period, orderBy, pageSize);
|
||||
setSelectedRow([]);
|
||||
}, [currentPage]);
|
||||
|
||||
// 전체 선택
|
||||
const handleAllSelect = () => {
|
||||
const checkAll = document.getElementById('check-all');
|
||||
let list = [];
|
||||
|
||||
if (checkAll.checked === true) {
|
||||
dataList.list.map((data, index) => {
|
||||
document.getElementsByName('select')[index].checked = true;
|
||||
list.push(String(data.id));
|
||||
});
|
||||
} else if (checkAll.checked === false) {
|
||||
for (let i = 0; i < dataList.list.length; i++) {
|
||||
dataList.list.map((data, index) => (document.getElementsByName('select')[index].checked = false));
|
||||
list = [];
|
||||
}
|
||||
}
|
||||
|
||||
setSelectedRow(list);
|
||||
};
|
||||
|
||||
// 일부 선택
|
||||
const handleSelectCheckBox = e => {
|
||||
let list = [...selectedRow];
|
||||
|
||||
if (e.target.checked) {
|
||||
list.push(e.target.id);
|
||||
|
||||
setSelectedRow(list);
|
||||
} else {
|
||||
const filterList = list.filter(data => e.target.id !== data);
|
||||
setSelectedRow(filterList);
|
||||
}
|
||||
};
|
||||
|
||||
// 삭제 여부 모달
|
||||
const handleConfirmeModalClose = () => {
|
||||
if (confirmModal === 'hidden') {
|
||||
setConfirmModal('view');
|
||||
} else {
|
||||
setConfirmModal('hidden');
|
||||
setRequestValue([]);
|
||||
}
|
||||
};
|
||||
|
||||
// 선택, 복수 삭제 모달창
|
||||
const handleConfirmModal = data => {
|
||||
if (data.id) {
|
||||
setSelectedData(data.id);
|
||||
if (selectedData) {
|
||||
setRequestValue(data.id);
|
||||
}
|
||||
} else if (selectedRow) {
|
||||
setRequestValue(selectedRow);
|
||||
}
|
||||
|
||||
handleConfirmeModalClose();
|
||||
};
|
||||
|
||||
// 완료 확인 모달
|
||||
const handleCompleteModal = () => {
|
||||
if (completeModal === 'hidden') {
|
||||
setCompleteModal('view');
|
||||
} else {
|
||||
setCompleteModal('hidden');
|
||||
setRequestValue([]);
|
||||
handleConfirmeModalClose();
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
// 삭제 기능 구현
|
||||
const handleDelete = () => {
|
||||
let list = [];
|
||||
|
||||
if (requestValue === selectedRow) {
|
||||
selectedRow.map(data =>
|
||||
list.push({
|
||||
id: data,
|
||||
}),
|
||||
);
|
||||
BlackListDelete(token, list);
|
||||
// console.log(list);
|
||||
// console.log(selectedRow);
|
||||
handleCompleteModal();
|
||||
} else if (requestValue !== selectedRow) {
|
||||
list.push({ id: selectedData });
|
||||
// console.log(list);
|
||||
BlackListDelete(token, list);
|
||||
handleCompleteModal();
|
||||
}
|
||||
};
|
||||
|
||||
const handleCountSelectedRow = () => {
|
||||
return currentPage > (dataList && dataList.total) / pageSize ? selectedRow.length === dataList.total % pageSize : selectedRow.length === Number(pageSize);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{userInfo.auth_list && !userInfo.auth_list.some(auth => auth.id === authType.blackListRead) ? (
|
||||
<AuthModal/>
|
||||
) : (
|
||||
<>
|
||||
<Title>이용자 제재 조회 및 등록</Title>
|
||||
<FormWrapper>
|
||||
<UserBlockSearchBar handleSearch={handleSearch} setResultData={setSearchData} />
|
||||
</FormWrapper>
|
||||
<TableInfo>
|
||||
<ListCount>
|
||||
총 : {dataList && dataList.total} 건 / {dataList && dataList.total_all} 건
|
||||
</ListCount>
|
||||
<ListOption>
|
||||
<SelectInput
|
||||
name=""
|
||||
id=""
|
||||
className="input-select"
|
||||
onChange={e => {
|
||||
handleOrderBy(e);
|
||||
}}>
|
||||
<option value="DESC">내림차순</option>
|
||||
<option value="ASC">오름차순</option>
|
||||
</SelectInput>
|
||||
<SelectInput
|
||||
name=""
|
||||
id=""
|
||||
onChange={e => {
|
||||
handlePageSize(e);
|
||||
}}
|
||||
className="input-select">
|
||||
<option value="50">50개</option>
|
||||
<option value="100">100개</option>
|
||||
</SelectInput>
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === 30) && (
|
||||
<Button theme={selectedRow.length === 0 ? 'disable' : 'line'} type="submit" text="선택 삭제" id={selectedRow} handleClick={() => handleConfirmModal(selectedRow)} />
|
||||
)}
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === 25) && (
|
||||
<Button
|
||||
theme="primary"
|
||||
type="submit"
|
||||
text="제재 등록"
|
||||
handleClick={e => {
|
||||
e.preventDefault();
|
||||
navigate('/servicemanage/userblock/userblockregist');
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</ListOption>
|
||||
</TableInfo>
|
||||
<TableWrapper>
|
||||
<TableStyle>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="40">
|
||||
<CheckBox id="check-all" handleCheck={handleAllSelect} checked={handleCountSelectedRow()} />
|
||||
</th>
|
||||
<th width="80">번호</th>
|
||||
<th width="20%">GUID</th>
|
||||
<th width="20%">아바타명</th>
|
||||
<th width="100">상태</th>
|
||||
<th width="100">제재 기간</th>
|
||||
<th width="250">제재 사유</th>
|
||||
<th width="150">등록자</th>
|
||||
<th width="110">상세정보</th>
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === 30) && <th width="80">삭제</th>}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList.list &&
|
||||
dataList.list.map(data => (
|
||||
<Fragment key={data.id}>
|
||||
<tr>
|
||||
<td>
|
||||
<CheckBox name={'select'} id={data.id} setData={e => handleSelectCheckBox(e)} />
|
||||
</td>
|
||||
<td>{data.row_num}</td>
|
||||
<td>{data.guid}</td>
|
||||
<td>{data.nickname}</td>
|
||||
{data.status === 'INPROGRESS' ? (
|
||||
<td>
|
||||
<ListState>{blockStatus.map(item => item.value === data.status && item.name)}</ListState>
|
||||
</td>
|
||||
) : (
|
||||
<td>{blockStatus.map(item => item.value === data.status && item.name)}</td>
|
||||
)}
|
||||
<td>{blockPeriod.map(item => item.value === data.period && item.name)}</td>
|
||||
<td>{blockSanctions.map(item => item.value === data.sanctions && item.name)}</td>
|
||||
<td>{data.create_by}</td>
|
||||
<td>
|
||||
<Button theme="line" text="상세보기" handleClick={() => handleDetail(data)} />
|
||||
</td>
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === 30) && (
|
||||
<td>
|
||||
<Button theme="line" id={data.id} name="single" text="삭제" handleClick={() => handleConfirmModal(data)} />
|
||||
</td>
|
||||
)}
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
<Pagination postsPerPage={pageSize} totalPosts={dataList && dataList.total_all} setCurrentPage={setCurrentPage} currentPage={currentPage} pageLimit={10} />
|
||||
<UserBlockDetailModal stateModal={detailView} data={detail} handleModal={handleDetail} />
|
||||
|
||||
{/* 선택 삭제 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={confirmModal}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleConfirmeModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">
|
||||
제재 대상을 삭제하시겠습니까?
|
||||
<br />
|
||||
삭제 시 제재가 해제됩니다.
|
||||
</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="취소" theme="line" size="large" width="100%" handleClick={handleConfirmeModalClose} />
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleDelete} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
|
||||
{/* 완료창 모달 */}
|
||||
|
||||
{/* 삭제 완료 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={completeModal}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleCompleteModal} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">삭제가 완료되었습니다.</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleCompleteModal} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserBlock;
|
||||
|
||||
const ListState = styled.span`
|
||||
color: #d60000;
|
||||
`;
|
||||
686
src/pages/ServiceManage/UserBlockRegist.js
Normal file
686
src/pages/ServiceManage/UserBlockRegist.js
Normal file
@@ -0,0 +1,686 @@
|
||||
import { useState, useEffect, useRef } from 'react';
|
||||
|
||||
import Button from '../../components/common/button/Button';
|
||||
import RadioInput from '../../components/common/input/Radio';
|
||||
|
||||
import styled from 'styled-components';
|
||||
import { Title, BtnWrapper, TextInput, SelectInput, DatePickerWrapper, ButtonClose, ModalText } from '../../styles/Components';
|
||||
|
||||
import Modal from '../../components/common/modal/Modal';
|
||||
import DatePickerComponent from '../../components/common/Date/DatePickerComponent';
|
||||
|
||||
import { blockPeriod, blockSanctions, blockType, HourList, MinuteList } from '../../assets/data';
|
||||
import DatePicker, { registerLocale } from 'react-datepicker';
|
||||
import { ko } from 'date-fns/esm/locale';
|
||||
import 'react-datepicker/dist/react-datepicker.css';
|
||||
import { getMonth, getYear, setHours } from 'date-fns';
|
||||
import range from 'lodash/range';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import UserBlockUploadBtn from '../../components/ServiceManage/UserBlockUploadBtn';
|
||||
import { BlackListRegist, BlackListMultipleUpload } from '../../apis';
|
||||
|
||||
import { authList } from '../../store/authList';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
registerLocale('ko', ko);
|
||||
|
||||
const UserBlockRegist = () => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
|
||||
const navigate = useNavigate();
|
||||
const userInfo = useRecoilValue(authList);
|
||||
|
||||
//시간 관련 변수
|
||||
const [sendHour, setSendHour] = useState('00');
|
||||
const [sendMin, setSendMin] = useState('00');
|
||||
const [endHour, setEndHour] = useState('00');
|
||||
const [endMin, setEndMin] = useState('00');
|
||||
|
||||
const [selectData, setSelectData] = useState('single');
|
||||
const [selectSingle, setSelectSingle] = useState(false);
|
||||
const [selectMulti, setSelectMulti] = useState(true);
|
||||
const [startDate, setStartDate] = useState(null);
|
||||
const years = range(1990, getYear(new Date()) + 1, 1);
|
||||
const months = ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'];
|
||||
|
||||
const [registModalClose, setRegistModalClose] = useState('hidden');
|
||||
const [completeModalClose, setCompleteModalClose] = useState('hidden');
|
||||
const [isNullValue, setIsNullValue] = useState(false);
|
||||
|
||||
const [guidList, setGuidList] = useState([]);
|
||||
const [typeError, setTypeError] = useState(true);
|
||||
const [resultData, setResultData] = useState({
|
||||
list: { guid: '' },
|
||||
type: '',
|
||||
sanctions: '',
|
||||
period: '',
|
||||
start_dt: '',
|
||||
end_dt: '',
|
||||
});
|
||||
const [confirmText, setConfirmText] = useState('');
|
||||
|
||||
const handleChange = e => {
|
||||
setSelectData(e.target.value);
|
||||
handleReset();
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
setResultData({
|
||||
list: { guid: '' },
|
||||
type: '',
|
||||
sanctions: '',
|
||||
period: '',
|
||||
start_dt: '',
|
||||
end_dt: '',
|
||||
});
|
||||
};
|
||||
|
||||
const [previewModal, setPreviewModal] = useState('hidden');
|
||||
const handlePreview = e => {
|
||||
e.preventDefault();
|
||||
previewModal === 'hidden' ? setPreviewModal('view') : setPreviewModal('hidden');
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (selectData === 'single') {
|
||||
setSelectSingle(false);
|
||||
setSelectMulti(true);
|
||||
if (resultData.period === 'WARNING') {
|
||||
setEndHour('01');
|
||||
} else {
|
||||
setEndHour('00');
|
||||
}
|
||||
} else if (selectData === 'multi') {
|
||||
setSelectSingle(true);
|
||||
setSelectMulti(false);
|
||||
if (resultData.period === 'WARNING') {
|
||||
setEndHour('01');
|
||||
} else {
|
||||
setEndHour('00');
|
||||
}
|
||||
}
|
||||
let list = [];
|
||||
|
||||
if (guidList) {
|
||||
guidList.map(data =>
|
||||
list.push({
|
||||
guid: data.guid,
|
||||
nickname: data.nickname,
|
||||
}),
|
||||
);
|
||||
setResultData({ ...resultData, list: list });
|
||||
}
|
||||
}, [selectData, guidList]);
|
||||
|
||||
// 제재 시간 세팅 로직
|
||||
const handleSendTime = e => {
|
||||
let sendDate = new Date(resultData.start_dt);
|
||||
|
||||
if (resultData.start_dt.length === 0) {
|
||||
sendDate = new Date();
|
||||
} else {
|
||||
sendDate = new Date(resultData.start_dt);
|
||||
}
|
||||
|
||||
const result = new Date(sendDate.getFullYear(), sendDate.getMonth(), sendDate.getDate(), e.target.id === 'hour' ? e.target.value : sendHour, e.target.id === 'min' ? e.target.value : sendMin);
|
||||
|
||||
const blockDay = resultData.period.slice(1) > 0 ? Number(resultData.period.slice(1)) + 1 : 0;
|
||||
const permanentDay = 2999 - sendDate.getFullYear();
|
||||
|
||||
if (e.target.id === 'hour') setSendHour(e.target.value);
|
||||
else if (e.target.id === 'min') setSendMin(e.target.value);
|
||||
if (e.target.id === 'hour' && resultData.period === 'WARNING') {
|
||||
let targetHour = String(e.target.value);
|
||||
let plusHour = Number(e.target.value) + 1;
|
||||
|
||||
if (targetHour < 9) {
|
||||
setEndHour('0' + String(plusHour));
|
||||
} else {
|
||||
setEndHour(plusHour);
|
||||
}
|
||||
} else if (resultData.period !== 'WARNING' && e.target.id === 'hour') {
|
||||
setEndHour(e.target.value);
|
||||
}
|
||||
|
||||
if (resultData.period === 'WARNING') {
|
||||
const EndResult = new Date(
|
||||
sendDate.getFullYear(),
|
||||
sendDate.getMonth(),
|
||||
sendDate.getDate() + blockDay,
|
||||
e.target.id === 'hour' ? e.target.value : sendHour,
|
||||
e.target.id === 'min' ? e.target.value : sendMin + 60,
|
||||
);
|
||||
|
||||
setResultData({ ...resultData, start_dt: result, end_dt: EndResult });
|
||||
} else if (resultData.period === 'PERMANENT') {
|
||||
const EndResult = new Date(
|
||||
sendDate.getFullYear() + permanentDay,
|
||||
sendDate.getMonth(),
|
||||
sendDate.getDate() + blockDay,
|
||||
e.target.id === 'hour' ? e.target.value : sendHour,
|
||||
e.target.id === 'min' ? e.target.value : sendMin,
|
||||
);
|
||||
|
||||
setResultData({ ...resultData, start_dt: result, end_dt: EndResult });
|
||||
} else if (blockDay > 0) {
|
||||
const EndResult = new Date(
|
||||
sendDate.getFullYear(),
|
||||
sendDate.getMonth(),
|
||||
sendDate.getDate() + blockDay,
|
||||
e.target.id === 'hour' ? e.target.value : sendHour,
|
||||
e.target.id === 'min' ? e.target.value : sendMin,
|
||||
);
|
||||
|
||||
setResultData({ ...resultData, start_dt: result, end_dt: EndResult });
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectedDate = data => {
|
||||
setSendHour('00');
|
||||
setSendMin('00');
|
||||
setEndHour('00');
|
||||
|
||||
const sendDate = new Date(data);
|
||||
const blockDay = Number(resultData.period.slice(1));
|
||||
const permanentDay = 2999 - sendDate.getFullYear();
|
||||
|
||||
if (endHour === '00' && resultData.period === 'WARNING') {
|
||||
setEndHour('01');
|
||||
}
|
||||
|
||||
const resultSendData = new Date(sendDate.getFullYear(), sendDate.getMonth(), sendDate.getDate(), sendHour, sendMin);
|
||||
|
||||
if (blockDay > 0) {
|
||||
const resultEndData = new Date(sendDate.getFullYear(), sendDate.getMonth(), sendDate.getDate() + blockDay, sendHour, sendMin);
|
||||
setResultData({ ...resultData, start_dt: resultSendData, end_dt: resultEndData });
|
||||
} else if (resultData.period === 'PERMANENT') {
|
||||
const resultEndData = new Date(sendDate.getFullYear() + permanentDay, sendDate.getMonth(), sendDate.getDate(), sendHour, sendMin);
|
||||
setResultData({ ...resultData, start_dt: resultSendData, end_dt: resultEndData });
|
||||
} else if (resultData.period === 'WARNING') {
|
||||
const resultEndData = new Date(sendDate.getFullYear(), sendDate.getMonth(), sendDate.getDate(), sendHour, sendMin + 60);
|
||||
setResultData({ ...resultData, start_dt: resultSendData, end_dt: resultEndData });
|
||||
}
|
||||
};
|
||||
|
||||
// 기간, 시간 초기화
|
||||
const setTimeValue = e => {
|
||||
setResultData({ ...resultData, period: e.target.value, start_dt: '', end_dt: '' });
|
||||
setSendMin('00');
|
||||
setSendHour('00');
|
||||
|
||||
if (resultData.period === 'WARNING') setEndHour('01');
|
||||
};
|
||||
|
||||
// 등록 확인 모달
|
||||
let notNull = resultData.list.length > 0 && resultData.type && resultData.period && resultData.sanctions && resultData.start_dt && resultData.end_dt;
|
||||
|
||||
const handleRegistModalClose = () => {
|
||||
if(selectData === 'multi'){
|
||||
const guidChk = guidList.some(guid => guid.validate === false);
|
||||
if(guidChk) {
|
||||
alert("유효성 체크가 통과되지 않은 항목이 존재합니다. \r\n수정 후 재등록 해주세요.")
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (notNull) {
|
||||
registModalClose === 'hidden' ? setRegistModalClose('view') : setRegistModalClose('hidden');
|
||||
setIsNullValue(false);
|
||||
} else {
|
||||
setIsNullValue(true);
|
||||
}
|
||||
};
|
||||
|
||||
// 등록 완료 모달
|
||||
const handleCompleteModalClose = () => {
|
||||
if (completeModalClose === 'hidden') {
|
||||
setCompleteModalClose('view');
|
||||
} else {
|
||||
setCompleteModalClose('hidden');
|
||||
handleReset();
|
||||
handleRegistModalClose();
|
||||
|
||||
navigate('/servicemanage/userblock');
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
// 등록 api 연동
|
||||
const handleRegist = async () => {
|
||||
const message = await BlackListRegist(token, resultData);
|
||||
|
||||
message.data.data.message === '등록 하였습니다.' ?
|
||||
setConfirmText('등록이 완료되었습니다.') :
|
||||
message.data.data.message === 'admindb_exit_error' ?
|
||||
setConfirmText("이미 등록된 유저입니다.") : setConfirmText(message.data.data.message);
|
||||
|
||||
handleRegistModalClose();
|
||||
handleCompleteModalClose();
|
||||
};
|
||||
|
||||
// console.log('DataList: ', resultData);
|
||||
// console.log('resultData.period :', resultData.period);
|
||||
// console.log(resultData.period.length);
|
||||
|
||||
return (
|
||||
<>
|
||||
{userInfo.auth_list && !userInfo.auth_list.some(auth => auth.id === 25) ? (
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={'view'}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={() => navigate(-1)} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">
|
||||
해당 메뉴에 대한 등록 권한이 없습니다.
|
||||
<br />
|
||||
권한 등급을 변경 후 다시 이용해주세요.
|
||||
</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={() => navigate(-1)} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
) : (
|
||||
<>
|
||||
<Title>이용자 제재 등록</Title>
|
||||
|
||||
<div>
|
||||
<RadioInput id="single" value="single" label="단일 등록" name="blockregist" fontSize="20px" fontWeight="500" checked={selectData === 'single'} handleChange={handleChange} />
|
||||
<RegistGroup>
|
||||
<InputItem>
|
||||
<Label>제재 대상</Label>
|
||||
<TextInput
|
||||
placeholder="GUID 입력"
|
||||
width="400px"
|
||||
disabled={selectSingle}
|
||||
value={resultData.list.guid}
|
||||
onChange={e => {
|
||||
let list = [];
|
||||
list.push({ guid: e.target.value });
|
||||
setResultData({ ...resultData, list });
|
||||
}}
|
||||
/>
|
||||
</InputItem>
|
||||
<InputRow>
|
||||
<InputItem>
|
||||
<Label>제재 방식</Label>
|
||||
<SelectInput value={resultData.type} onChange={e => setResultData({ ...resultData, type: e.target.value })} disabled={selectSingle}>
|
||||
{blockType.map((data, index) => (
|
||||
<option key={index} value={data.value}>
|
||||
{selectData === 'single' ? data.name : '선택'}
|
||||
</option>
|
||||
))}
|
||||
</SelectInput>
|
||||
</InputItem>
|
||||
<InputItem>
|
||||
<Label>제재 기간</Label>
|
||||
<SelectInput value={resultData.period} onChange={e => setTimeValue(e)} disabled={selectSingle}>
|
||||
{blockPeriod.map((data, index) => (
|
||||
<option key={index} value={data.value}>
|
||||
{selectData === 'single' ? data.name : '선택'}
|
||||
</option>
|
||||
))}
|
||||
</SelectInput>
|
||||
</InputItem>
|
||||
<InputItem>
|
||||
<Label>제재 사유</Label>
|
||||
<SelectInput value={resultData.sanctions} onChange={e => setResultData({ ...resultData, sanctions: e.target.value })} disabled={selectSingle}>
|
||||
{blockSanctions.map((data, index) => (
|
||||
<option key={index} value={data.value}>
|
||||
{selectData === 'single' ? data.name : '선택'}
|
||||
</option>
|
||||
))}
|
||||
</SelectInput>
|
||||
</InputItem>
|
||||
</InputRow>
|
||||
<InputRow>
|
||||
<InputItem>
|
||||
<Label>시작 일시</Label>
|
||||
<InputGroup>
|
||||
<DatePickerWrapper>
|
||||
<DatePickerComponent
|
||||
name="시작 일자"
|
||||
handleSelectedDate={data => handleSelectedDate(data)}
|
||||
selectedDate={resultData.start_dt}
|
||||
disabled={selectSingle || !resultData.period}
|
||||
pastDate={new Date()}
|
||||
/>
|
||||
</DatePickerWrapper>
|
||||
<SelectInput onChange={e => handleSendTime(e)} id="hour" disabled={selectSingle || !resultData.period} value={sendHour}>
|
||||
{HourList.map(hour => (
|
||||
<option value={hour} key={hour}>
|
||||
{hour}
|
||||
</option>
|
||||
))}
|
||||
</SelectInput>
|
||||
<SelectInput onChange={e => handleSendTime(e)} id="min" disabled={selectSingle || !resultData.period} value={sendMin}>
|
||||
{MinuteList.map(min => (
|
||||
<option value={min} key={min}>
|
||||
{min}
|
||||
</option>
|
||||
))}
|
||||
</SelectInput>
|
||||
</InputGroup>
|
||||
</InputItem>
|
||||
<InputItem>
|
||||
<Label>만료 일시</Label>
|
||||
<InputGroup>
|
||||
<DatePickerWrapper>
|
||||
<DatePicker
|
||||
disabled
|
||||
selected={selectData === 'single' ? resultData.end_dt : ''}
|
||||
onChange={date => setStartDate(date)}
|
||||
className="datepicker"
|
||||
placeholderText="만료일자"
|
||||
calendarClassName="calendar"
|
||||
dateFormat="yyyy - MM - dd"
|
||||
locale="ko"
|
||||
renderCustomHeader={({ date, changeYear, changeMonth, decreaseMonth, increaseMonth, prevMonthButtonDisabled, nextMonthButtonDisabled }) => (
|
||||
<div className="calendar-top">
|
||||
<button
|
||||
className="btn-prev"
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
decreaseMonth();
|
||||
}}
|
||||
disabled={prevMonthButtonDisabled}></button>
|
||||
<select value={getYear(date)} onChange={({ target: { value } }) => changeYear(value)}>
|
||||
{years.map(option => (
|
||||
<option key={option} value={option}>
|
||||
{option}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
.
|
||||
<select value={months[getMonth(date)]} onChange={({ target: { value } }) => changeMonth(months.indexOf(value))}>
|
||||
{months.map(option => (
|
||||
<option key={option} value={option}>
|
||||
{option}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<button
|
||||
className="btn-next"
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
increaseMonth();
|
||||
}}
|
||||
disabled={nextMonthButtonDisabled}></button>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
</DatePickerWrapper>
|
||||
<SelectInput disabled>
|
||||
<option value="">{selectData === 'single' && resultData.start_dt ? endHour : '00'}</option>
|
||||
</SelectInput>
|
||||
<SelectInput disabled>
|
||||
<option value="">{selectData === 'single' && resultData.start_dt ? sendMin : '00'}</option>
|
||||
</SelectInput>
|
||||
</InputGroup>
|
||||
</InputItem>
|
||||
</InputRow>
|
||||
</RegistGroup>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<RadioInput id="multi" value="multi" label="복수 등록" name="blockregist" fontSize="20px" fontWeight="500" checked={selectData === 'multi'} handleChange={handleChange} />
|
||||
<RegistGroup>
|
||||
<InputItem>
|
||||
<UserBlockUploadBtn
|
||||
disabled={selectMulti}
|
||||
setResultData={setResultData}
|
||||
resultData={resultData}
|
||||
guidList={guidList}
|
||||
setGuidList={setGuidList}
|
||||
typeError={typeError}
|
||||
setTypeError={setTypeError}
|
||||
/>
|
||||
</InputItem>
|
||||
<InputRow>
|
||||
<InputItem>
|
||||
<Label>제재 방식</Label>
|
||||
<SelectInput value={resultData.type} onChange={e => setResultData({ ...resultData, type: e.target.value })} disabled={selectMulti}>
|
||||
{blockType.map((data, index) => (
|
||||
<option key={index} value={data.value}>
|
||||
{selectData === 'multi' ? data.name : '선택'}
|
||||
</option>
|
||||
))}
|
||||
</SelectInput>
|
||||
</InputItem>
|
||||
<InputItem>
|
||||
<Label>제재 기간</Label>
|
||||
<SelectInput value={resultData.period} onChange={e => setTimeValue(e)} disabled={selectMulti}>
|
||||
{blockPeriod.map((data, index) => (
|
||||
<option key={index} value={data.value}>
|
||||
{selectData === 'multi' ? data.name : '선택'}
|
||||
</option>
|
||||
))}
|
||||
</SelectInput>
|
||||
</InputItem>
|
||||
<InputItem>
|
||||
<Label>제재 사유</Label>
|
||||
<SelectInput value={resultData.sanctions} onChange={e => setResultData({ ...resultData, sanctions: e.target.value })} disabled={selectMulti}>
|
||||
{blockSanctions.map((data, index) => (
|
||||
<option key={index} value={data.value}>
|
||||
{selectData === 'multi' ? data.name : '선택'}
|
||||
</option>
|
||||
))}
|
||||
</SelectInput>
|
||||
</InputItem>
|
||||
</InputRow>
|
||||
<InputRow>
|
||||
<InputItem>
|
||||
<Label>시작 일시</Label>
|
||||
<InputGroup>
|
||||
<DatePickerWrapper>
|
||||
<DatePickerComponent
|
||||
name="시작 일자"
|
||||
handleSelectedDate={data => handleSelectedDate(data)}
|
||||
selectedDate={resultData.start_dt}
|
||||
disabled={selectMulti || !resultData.period}
|
||||
pastDate={new Date()}
|
||||
/>
|
||||
</DatePickerWrapper>
|
||||
<SelectInput onChange={e => handleSendTime(e)} id="hour" disabled={selectMulti || !resultData.period} value={sendHour}>
|
||||
{HourList.map(hour => (
|
||||
<option value={hour} key={hour}>
|
||||
{hour}
|
||||
</option>
|
||||
))}
|
||||
</SelectInput>
|
||||
<SelectInput onChange={e => handleSendTime(e)} id="min" disabled={selectMulti || !resultData.period} value={sendMin}>
|
||||
{MinuteList.map(min => (
|
||||
<option value={min} key={min}>
|
||||
{min}
|
||||
</option>
|
||||
))}
|
||||
</SelectInput>
|
||||
</InputGroup>
|
||||
</InputItem>
|
||||
|
||||
<InputItem>
|
||||
<Label>만료 일시</Label>
|
||||
<InputGroup>
|
||||
<DatePickerWrapper>
|
||||
<DatePicker
|
||||
disabled
|
||||
selected={selectData === 'multi' ? resultData.end_dt : ''}
|
||||
onChange={date => setStartDate(date)}
|
||||
className="datepicker"
|
||||
placeholderText="만료일자"
|
||||
calendarClassName="calendar"
|
||||
dateFormat="yyyy - MM - dd"
|
||||
locale="ko"
|
||||
renderCustomHeader={({ date, changeYear, changeMonth, decreaseMonth, increaseMonth, prevMonthButtonDisabled, nextMonthButtonDisabled }) => (
|
||||
<div className="calendar-top">
|
||||
<button
|
||||
className="btn-prev"
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
decreaseMonth();
|
||||
}}
|
||||
disabled={prevMonthButtonDisabled}></button>
|
||||
<select value={getYear(date)} onChange={({ target: { value } }) => changeYear(value)}>
|
||||
{years.map(option => (
|
||||
<option key={option} value={option}>
|
||||
{option}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
.
|
||||
<select value={months[getMonth(date)]} onChange={({ target: { value } }) => changeMonth(months.indexOf(value))}>
|
||||
{months.map(option => (
|
||||
<option key={option} value={option}>
|
||||
{option}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<button
|
||||
className="btn-next"
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
increaseMonth();
|
||||
}}
|
||||
disabled={nextMonthButtonDisabled}></button>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
</DatePickerWrapper>
|
||||
<SelectInput disabled>
|
||||
<option value="">{selectData === 'multi' ? endHour : '00'}</option>
|
||||
</SelectInput>
|
||||
<SelectInput disabled>
|
||||
<option value="">{selectData === 'multi' ? sendMin : '00'}</option>
|
||||
</SelectInput>
|
||||
</InputGroup>
|
||||
</InputItem>
|
||||
</InputRow>
|
||||
</RegistGroup>
|
||||
</div>
|
||||
|
||||
{isNullValue && <SearchBarAlert>설정값을 모두 입력해주세요.</SearchBarAlert>}
|
||||
<BtnWrapper $justify="flex-end" $gap="10px">
|
||||
<Button
|
||||
text="취소"
|
||||
theme="line"
|
||||
handleClick={e => {
|
||||
e.preventDefault();
|
||||
navigate('/servicemanage/userblock');
|
||||
}}
|
||||
/>
|
||||
<Button type="submit" text="등록" name="등록버튼" handleClick={handleRegistModalClose} theme={notNull ? 'primary' : 'disable'} />
|
||||
</BtnWrapper>
|
||||
|
||||
{/* 일괄등록 모달창 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={registModalClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleRegistModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">
|
||||
이용자 제재 명단에
|
||||
<br />
|
||||
등록하시겠습니까?
|
||||
</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="취소" theme="line" size="large" width="100%" handleClick={handleRegistModalClose} />
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleRegist} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
|
||||
{/* 등록 완료 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={completeModalClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleCompleteModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">{confirmText}</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleCompleteModalClose} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserBlockRegist;
|
||||
|
||||
const RegistGroup = styled.div`
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-flow: column;
|
||||
gap: 20px;
|
||||
padding: 20px 0;
|
||||
border-top: 1px solid #000;
|
||||
border-bottom: 1px solid #000;
|
||||
font-size: 14px;
|
||||
margin-bottom: 40px;
|
||||
`;
|
||||
|
||||
const InputRow = styled.div`
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px 50px;
|
||||
`;
|
||||
|
||||
const InputItem = styled.div`
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
${TextInput},${SelectInput} {
|
||||
height: 35px;
|
||||
font-size: 14px;
|
||||
}
|
||||
`;
|
||||
|
||||
const Label = styled.div`
|
||||
display: block;
|
||||
min-width: 120px;
|
||||
text-align: center;
|
||||
`;
|
||||
|
||||
const InputGroup = styled.div`
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
button {
|
||||
height: 35px;
|
||||
}
|
||||
`;
|
||||
|
||||
const TableWrapper = styled.div`
|
||||
margin-top: 5px;
|
||||
margin-bottom: 30px;
|
||||
max-height: 324px;
|
||||
overflow: auto;
|
||||
&::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #666666;
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
background: #d9d9d9;
|
||||
}
|
||||
`;
|
||||
const Count = styled.div`
|
||||
font-size: 14px;
|
||||
`;
|
||||
|
||||
const FileInput = styled(TextInput)`
|
||||
height: 35px;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 5px;
|
||||
width: 300px;
|
||||
padding: 0 15px;
|
||||
line-height: 35px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
&::file-selector-button {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const SearchBarAlert = styled.div`
|
||||
display: ${props => (props.$view === 'hidden' ? 'none' : 'flex')};
|
||||
justify-content: right;
|
||||
width: 100%;
|
||||
padding-bottom: 20px;
|
||||
color: #d60000;
|
||||
`;
|
||||
507
src/pages/ServiceManage/WhiteList.js
Normal file
507
src/pages/ServiceManage/WhiteList.js
Normal file
@@ -0,0 +1,507 @@
|
||||
import { useState, useEffect, Fragment, useCallback } from 'react';
|
||||
|
||||
import { SearchBar } from '../../components/common/SearchBar';
|
||||
import CheckBox from '../../components/common/input/CheckBox';
|
||||
import Modal from '../../components/common/modal/Modal';
|
||||
import { Title, FormWrapper, TableInfo, ListTitle, ListOption, TableStyle, BtnWrapper, ButtonClose, ModalText } from '../../styles/Components';
|
||||
import Button from '../../components/common/button/Button';
|
||||
import { WhiteListSearchBar } from '../../components/ServiceManage';
|
||||
|
||||
import { styled } from 'styled-components';
|
||||
import { WhiteListData, WhiteListDelete, WhiteListRegist, WhiteListAllow, WhiteListExport } from '../../apis/WhiteList';
|
||||
import { authList } from '../../store/authList';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import AuthModal from '../../components/common/modal/AuthModal';
|
||||
import { authType } from '../../assets/data';
|
||||
|
||||
const WhiteList = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const token = sessionStorage.getItem('token');
|
||||
const userInfo = useRecoilValue(authList);
|
||||
const [resultData, setResultData] = useState({ guid: '' });
|
||||
const [doubleSubmitFlag, setDoubleSubmitFlag] = useState(false);
|
||||
|
||||
const [selectedRow, setSelectedRow] = useState([]);
|
||||
const [selectedId, setSelectedId] = useState([]);
|
||||
const [dataList, setDataList] = useState([]);
|
||||
const [deleteModalClose, setDeleteModalClose] = useState('hidden');
|
||||
const [confirmModalClose, setConfirmModalClose] = useState('hidden');
|
||||
const [deleteUserClose, setDeleteUserClose] = useState('hidden');
|
||||
const [completeModalClose, setCompleteModalClose] = useState('hidden');
|
||||
const [registModalClose, setRegistModalClose] = useState('hidden');
|
||||
const [allowModalClose, setAllowModalClose] = useState('hidden');
|
||||
const [confirmAllowClose, setConfirmAllowClose] = useState('hidden');
|
||||
const [userAllowClose, setUserAllowClose] = useState('hidden');
|
||||
const [isNullValue, setIsNullValue] = useState(false);
|
||||
const [confirmText, setConfirmText] = useState('');
|
||||
|
||||
const [approveAble, setApproveAble] = useState(false);
|
||||
|
||||
const fetchData = async () => {
|
||||
setDataList(await WhiteListData(token));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
handleApproveCheck();
|
||||
}, [selectedRow]);
|
||||
|
||||
// 전체 선택
|
||||
const handleAllSelect = () => {
|
||||
const checkAll = document.getElementById('check-all');
|
||||
let list = [];
|
||||
|
||||
if (checkAll.checked === true) {
|
||||
dataList.map((data, index) => {
|
||||
document.getElementsByName('select')[index].checked = true;
|
||||
list.push(String(data.id));
|
||||
});
|
||||
} else if (checkAll.checked === false) {
|
||||
for (let i = 0; i < dataList.length; i++) {
|
||||
dataList.map((data, index) => (document.getElementsByName('select')[index].checked = false));
|
||||
list = [];
|
||||
}
|
||||
}
|
||||
|
||||
setSelectedRow(list);
|
||||
};
|
||||
|
||||
// 일부 선택
|
||||
const handleSelectCheckBox = e => {
|
||||
let list = [...selectedRow];
|
||||
|
||||
if (e.target.checked) {
|
||||
list.push(e.target.id);
|
||||
|
||||
setSelectedRow(list);
|
||||
} else {
|
||||
const filterList = list.filter(data => e.target.id !== data);
|
||||
setSelectedRow(filterList);
|
||||
}
|
||||
};
|
||||
|
||||
// 선택 승인 유효성 검사
|
||||
const approveCheck = e => {
|
||||
let approveList = [];
|
||||
|
||||
dataList && dataList.map(data => data.status === 'PERMITTED' && approveList.push(data.id));
|
||||
|
||||
return approveList;
|
||||
};
|
||||
|
||||
const handleApproveCheck = () => {
|
||||
let list = [];
|
||||
let approveList = approveCheck();
|
||||
|
||||
selectedRow.map(data => list.push(Number(data)));
|
||||
setApproveAble(approveList.filter(row => list.includes(row)).length === 0);
|
||||
};
|
||||
|
||||
// 선택 삭제 모달창
|
||||
const handleDeleteModalClose = () => {
|
||||
if (selectedRow.length !== 0) {
|
||||
if (deleteModalClose === 'hidden') {
|
||||
setDeleteModalClose('view');
|
||||
} else {
|
||||
setDeleteModalClose('hidden');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 삭제 확인 모달창
|
||||
const handleConfirmModalClose = () => {
|
||||
if (confirmModalClose === 'hidden') {
|
||||
setConfirmModalClose('view');
|
||||
} else {
|
||||
setConfirmModalClose('hidden');
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
// 선택 삭제 버튼
|
||||
const handleSelectedDelete = () => {
|
||||
let list = [];
|
||||
|
||||
selectedRow.map(data =>
|
||||
list.push({
|
||||
id: data,
|
||||
}),
|
||||
);
|
||||
|
||||
WhiteListDelete(token, list);
|
||||
handleDeleteModalClose();
|
||||
handleConfirmModalClose();
|
||||
};
|
||||
|
||||
// 개별 삭제 모달
|
||||
const handleUserDeleteModalClose = dataValue => {
|
||||
if (deleteUserClose === 'hidden') {
|
||||
setDeleteUserClose('view');
|
||||
} else {
|
||||
setDeleteUserClose('hidden');
|
||||
}
|
||||
|
||||
if (dataValue) {
|
||||
setSelectedId(dataValue.id);
|
||||
}
|
||||
};
|
||||
|
||||
// 개별 삭제 버튼
|
||||
const handleDelete = () => {
|
||||
let list = [];
|
||||
|
||||
list.push({ id: selectedId });
|
||||
WhiteListDelete(token, list);
|
||||
handleUserDeleteModalClose();
|
||||
handleConfirmModalClose();
|
||||
setSelectedId([]);
|
||||
};
|
||||
|
||||
// 등록 확인 모달
|
||||
const handleRegistModalClose = () => {
|
||||
if (resultData.guid.length === 0) {
|
||||
setIsNullValue(true);
|
||||
} else if (registModalClose === 'hidden') {
|
||||
setRegistModalClose('view');
|
||||
setIsNullValue(false);
|
||||
} else {
|
||||
setRegistModalClose('hidden');
|
||||
}
|
||||
};
|
||||
// console.log(resultData.guid.length)
|
||||
|
||||
// 등록 완료 모달
|
||||
const handleCompleteModalClose = () => {
|
||||
if (completeModalClose === 'hidden') {
|
||||
setCompleteModalClose('view');
|
||||
} else {
|
||||
setCompleteModalClose('hidden');
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
// 화이트 리스트 등록하기
|
||||
const handleSubmit = async () => {
|
||||
const message = await WhiteListRegist(token, resultData);
|
||||
|
||||
if (message.data.data.message === '등록 하였습니다.') setConfirmText('등록이 완료되었습니다.');
|
||||
else if (message.data.data.message === 'admindb_exit_error') setConfirmText('해당 유저가 이미 등록되어있습니다. \n 확인 후 다시 이용해주세요.');
|
||||
else if (message.data.data.message === '중복된 유저 정보가 있습니다.') setConfirmText('파일 내 중복된 유저 정보가 있습니다. \n 파일을 다시 확인 후 이용해주세요.');
|
||||
else setConfirmText(message.data.data.message);
|
||||
|
||||
handleRegistModalClose();
|
||||
handleCompleteModalClose();
|
||||
};
|
||||
|
||||
// 선택 승인 모달창
|
||||
const handleAllowModalClose = () => {
|
||||
if (selectedRow.length !== 0) {
|
||||
if (allowModalClose === 'hidden') {
|
||||
setAllowModalClose('view');
|
||||
} else {
|
||||
setAllowModalClose('hidden');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 승인 완료 모달창
|
||||
const handleConfirmAllowClose = () => {
|
||||
if (confirmAllowClose === 'hidden') {
|
||||
setConfirmAllowClose('view');
|
||||
} else {
|
||||
setConfirmModalClose('hidden');
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
// 일괄 승인
|
||||
const handleAllow = () => {
|
||||
let list = [];
|
||||
|
||||
selectedRow.map(data =>
|
||||
list.push({
|
||||
id: data,
|
||||
}),
|
||||
);
|
||||
|
||||
WhiteListAllow(token, list);
|
||||
handleAllowModalClose();
|
||||
handleConfirmAllowClose();
|
||||
};
|
||||
|
||||
// 개별 승인
|
||||
const handleUserAllowModalClose = dataValue => {
|
||||
if (userAllowClose === 'hidden') {
|
||||
setUserAllowClose('view');
|
||||
} else {
|
||||
setUserAllowClose('hidden');
|
||||
}
|
||||
|
||||
if (dataValue) {
|
||||
setSelectedId(dataValue.id);
|
||||
}
|
||||
};
|
||||
|
||||
// 개별 승인 버튼
|
||||
const handleUserAllow = () => {
|
||||
let list = [];
|
||||
|
||||
list.push({ id: selectedId });
|
||||
WhiteListAllow(token, list);
|
||||
handleUserAllowModalClose();
|
||||
handleConfirmAllowClose();
|
||||
setSelectedId([]);
|
||||
};
|
||||
|
||||
// 엑셀 다운로드
|
||||
const handleXlsxExport = () => {
|
||||
const fileName = 'Caliverse_whitelist.xlsx';
|
||||
WhiteListExport(token, fileName);
|
||||
};
|
||||
|
||||
const handleCountSelectedRow = () => {
|
||||
return dataList && document.querySelectorAll('input[name="select"]:checked').length === dataList.length;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{userInfo.auth_list && !userInfo.auth_list.some(auth => auth.id === authType.whiteListRead) ? (
|
||||
<AuthModal />
|
||||
) : (
|
||||
<>
|
||||
<Title>화이트리스트 등록/수정</Title>
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === 21) && (
|
||||
<FormWrapper>
|
||||
<WhiteListSearchBar handleRegistModalClose={handleRegistModalClose} isNullValue={isNullValue} resultData={resultData} setResultData={setResultData} />
|
||||
</FormWrapper>
|
||||
)}
|
||||
<TableInfo>
|
||||
<ListTitle>화이트리스트 명단</ListTitle>
|
||||
<ListOption>
|
||||
<Button theme="line" type="file" text="엑셀 다운로드" handleClick={handleXlsxExport} />
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === 28) && (
|
||||
<Button theme={selectedRow.length === 0 ? 'disable' : 'line'} type="submit" text="선택 삭제" handleClick={handleDeleteModalClose} />
|
||||
)}
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === 20) && (
|
||||
<Button
|
||||
theme={selectedRow.length === 0 || !approveAble ? 'disable' : 'line'}
|
||||
type="submit"
|
||||
text="선택 승인"
|
||||
errorMessage={!approveAble}
|
||||
handleClick={handleAllowModalClose}
|
||||
/>
|
||||
)}
|
||||
</ListOption>
|
||||
</TableInfo>
|
||||
<TableWrapper>
|
||||
<TableStyle>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="40">
|
||||
<CheckBox id="check-all" handleCheck={handleAllSelect} checked={handleCountSelectedRow()} />
|
||||
</th>
|
||||
<th width="80">번호</th>
|
||||
<th width="40%">GUID</th>
|
||||
<th width="25%">닉네임</th>
|
||||
<th width="25%">등록자(이메일주소)</th>
|
||||
<th width="100">승인</th>
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === 28) && <th width="100">삭제</th>}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList &&
|
||||
dataList.map(data => (
|
||||
<Fragment key={data.guid}>
|
||||
<tr>
|
||||
<td>
|
||||
<CheckBox name={'select'} id={data.id} setData={e => handleSelectCheckBox(e)} handleCheck={handleApproveCheck} />
|
||||
</td>
|
||||
<td>{data.row_num}</td>
|
||||
<td>{data.guid}</td>
|
||||
<td>{data.nickname}</td>
|
||||
<td>{data.create_by}</td>
|
||||
{/* 승인 상태 */}
|
||||
{data.status !== 'REJECT' ? (
|
||||
<td>승인</td>
|
||||
) : userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === 20) ? (
|
||||
<td>
|
||||
<Button theme="line" text="승인" id={data.id} handleClick={() => handleUserAllowModalClose(data)} />
|
||||
</td>
|
||||
) : (
|
||||
<td>대기 중</td>
|
||||
)}
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === 28) && (
|
||||
<td>
|
||||
<Button theme="line" text="삭제" id={data.id} handleClick={() => handleUserDeleteModalClose(data)} />
|
||||
</td>
|
||||
)}
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
|
||||
{/* 선택삭제 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={deleteModalClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleDeleteModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">
|
||||
선택된 대상을 화이트리스트 유저에서
|
||||
<br />
|
||||
삭제하시겠습니까?
|
||||
</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="취소" theme="line" size="large" width="100%" handleClick={handleDeleteModalClose} />
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleSelectedDelete} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
|
||||
{/* 등록 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={registModalClose}>
|
||||
<BtnWrapper $="flex-end">
|
||||
<ButtonClose onClick={handleRegistModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">
|
||||
화이트리스트 명단에
|
||||
<br />
|
||||
등록하시겠습니까?
|
||||
</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="취소" theme="line" size="large" width="100%" handleClick={handleRegistModalClose} />
|
||||
<Button
|
||||
text="확인"
|
||||
theme="primary"
|
||||
type="submit"
|
||||
size="large"
|
||||
width="100%"
|
||||
handleClick={() => {
|
||||
doubleSubmitFlag || handleSubmit();
|
||||
setDoubleSubmitFlag(true);
|
||||
}}
|
||||
/>
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
|
||||
{/* 개별 삭제 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={deleteUserClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleUserDeleteModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">
|
||||
화이트리스트 유저를
|
||||
<br />
|
||||
삭제하시겠습니까?
|
||||
</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="취소" theme="line" size="large" width="100%" handleClick={handleUserDeleteModalClose} />
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleDelete} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
|
||||
{/* 승인 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={allowModalClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleAllowModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">
|
||||
선택된 대상을 화이트리스트 유저로
|
||||
<br />
|
||||
승인하시겠습니까?
|
||||
</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="취소" theme="line" size="large" width="100%" handleClick={handleAllowModalClose} />
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleAllow} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
|
||||
{/* 개별 승인 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={userAllowClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleUserAllowModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">
|
||||
선택된 대상을 화이트리스트 유저로
|
||||
<br />
|
||||
승인하시겠습니까?
|
||||
</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="취소" theme="line" size="large" width="100%" handleClick={handleUserAllowModalClose} />
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleUserAllow} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
|
||||
{/* 완료 모달 */}
|
||||
|
||||
{/* 등록 완료 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={completeModalClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleCompleteModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">{confirmText}</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleCompleteModalClose} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
|
||||
{/* 승인 완료 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={confirmAllowClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleConfirmAllowClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">승인이 완료되었습니다.</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleConfirmAllowClose} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
|
||||
{/* 삭제 확인 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={confirmModalClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleConfirmModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">삭제가 완료되었습니다.</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleConfirmModalClose} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default WhiteList;
|
||||
|
||||
const TableWrapper = styled.div`
|
||||
height: calc(100vh - 383px);
|
||||
border-top: 1px solid #000;
|
||||
overflow: auto;
|
||||
&::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #666666;
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
background: #d9d9d9;
|
||||
}
|
||||
thead {
|
||||
th {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const StatusRed = styled.td`
|
||||
color: #d60000;
|
||||
`;
|
||||
12
src/pages/ServiceManage/index.js
Normal file
12
src/pages/ServiceManage/index.js
Normal file
@@ -0,0 +1,12 @@
|
||||
export { default as Board } from './Board';
|
||||
export { default as Mail } from './Mail';
|
||||
export { default as MailRegist } from './MailRegist';
|
||||
export { default as ReportList } from './ReportList';
|
||||
export { default as UserBlock } from './UserBlock';
|
||||
export { default as UserBlockRegist } from './UserBlockRegist';
|
||||
export { default as WhiteList } from './WhiteList';
|
||||
export { default as Items } from './Items';
|
||||
export { default as Event } from './Event';
|
||||
export { default as EventRegist } from './EventRegist';
|
||||
export { default as LandAuction} from './LandAuction'
|
||||
export { default as BattleEvent} from './BattleEvent'
|
||||
501
src/pages/UserManage/AdminView.js
Normal file
501
src/pages/UserManage/AdminView.js
Normal file
@@ -0,0 +1,501 @@
|
||||
import { Fragment, useEffect, useState } from 'react';
|
||||
|
||||
import CheckBox from '../../components/common/input/CheckBox';
|
||||
import { Title, FormWrapper, SelectInput, BtnWrapper, TableInfo, ListCount, ListOption, TableStyle, State, ButtonClose, ModalText } from '../../styles/Components';
|
||||
import Button from '../../components/common/button/Button';
|
||||
import Pagination from '../../components/common/Pagination/Pagination';
|
||||
import Modal from '../../components/common/modal/Modal';
|
||||
|
||||
import { AdminViewList, AdminViewGroupList, AdminLoginApprove, AdminDeleteUser, AdminChangeGroup, AdminChangePw } from '../../apis/Admin';
|
||||
import AdminViewSearchBar from '../../components/UserManage/AdminViewSearchBar';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { authList } from '../../store/authList';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import AuthModal from '../../components/common/modal/AuthModal';
|
||||
|
||||
function AdminView() {
|
||||
const token = sessionStorage.getItem('token');
|
||||
const userInfo = useRecoilValue(authList);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
|
||||
const [dataList, setDataList] = useState([]);
|
||||
const [groupList, setGroupList] = useState([]);
|
||||
const [selectedRow, setSelectedRow] = useState([]);
|
||||
const [selectedGroup, setSelectedGroup] = useState([]);
|
||||
const [searchData, setSearchData] = useState({});
|
||||
const [selectedEmail, setSelectedEmail] = useState('');
|
||||
const [orderBy, setOrderBy] = useState('DESC');
|
||||
|
||||
const [deleteModalClose, setDeleteModalClose] = useState('hidden');
|
||||
const [approveModalClose, setApproveModalClose] = useState('hidden');
|
||||
const [saveModalClose, setSaveModalClose] = useState('hidden');
|
||||
const [confirmModalClose, setConfirmModalClose] = useState('hidden');
|
||||
const [confirmText, setConfirmText] = useState('');
|
||||
const [singleConfirmText, setSingleConfirmText] = useState('');
|
||||
const [singleModalClose, setSingleModalClose] = useState('hidden');
|
||||
const [initialModalClose, setInitialModalClose] = useState('hidden');
|
||||
|
||||
const [approveAble, setApproveAble] = useState(false);
|
||||
|
||||
const [pageSize, setPageSize] = useState('50');
|
||||
|
||||
// 그룹 권한 조회 후 전체 리스트 불러오기 && 페이징
|
||||
useEffect(() => {
|
||||
fetchGroupData();
|
||||
setSelectedRow([]);
|
||||
}, [currentPage]);
|
||||
|
||||
useEffect(() => {
|
||||
handleApproveCheck();
|
||||
}, [selectedRow]);
|
||||
|
||||
// 선택 삭제 모달
|
||||
const handleDeleteModalClose = () => {
|
||||
if (selectedRow.length !== 0 && deleteModalClose === 'hidden') {
|
||||
setDeleteModalClose('view');
|
||||
} else {
|
||||
setDeleteModalClose('hidden');
|
||||
setConfirmText('삭제가');
|
||||
}
|
||||
};
|
||||
|
||||
// 선택 승인 모달
|
||||
const handleApproveModalClose = () => {
|
||||
if (selectedRow.length !== 0 && approveModalClose === 'hidden' && approveAble) {
|
||||
setApproveModalClose('view');
|
||||
} else {
|
||||
setApproveModalClose('hidden');
|
||||
setConfirmText('승인이');
|
||||
}
|
||||
};
|
||||
|
||||
// 저장 모달
|
||||
const handleSaveModalClose = () => {
|
||||
if (selectedGroup.length !== 0 && saveModalClose === 'hidden') {
|
||||
setSaveModalClose('view');
|
||||
} else {
|
||||
setSaveModalClose('hidden');
|
||||
setConfirmText('저장이');
|
||||
}
|
||||
};
|
||||
|
||||
// 삭제, 승인, 저장 확인 모달창
|
||||
const handleConfirmeModalClose = () => {
|
||||
if (confirmModalClose === 'hidden') {
|
||||
setConfirmModalClose('view');
|
||||
} else {
|
||||
setConfirmModalClose('hidden');
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
// 단일 승인 or 반려 모달
|
||||
const handleSingleModalClose = () => {
|
||||
if (singleModalClose === 'hidden') {
|
||||
setSingleModalClose('view');
|
||||
} else {
|
||||
setSingleModalClose('hidden');
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
// 비밀번호 초기화 모달
|
||||
const handleInitialModalClose = () => {
|
||||
if (initialModalClose === 'hidden') {
|
||||
setInitialModalClose('view');
|
||||
} else {
|
||||
setInitialModalClose('hidden');
|
||||
}
|
||||
};
|
||||
|
||||
// 리스트 조회
|
||||
const fetchData = async (searchType, searchKey, groupType, joinCheck, order, size) => {
|
||||
setDataList(await AdminViewList(token, searchType, searchKey, groupType, joinCheck, order ? order : orderBy, size ? size : pageSize, currentPage));
|
||||
};
|
||||
|
||||
// 그룹 조회
|
||||
const fetchGroupData = async () => {
|
||||
setGroupList(await AdminViewGroupList(token));
|
||||
fetchData(searchData.searchOption, searchData.data, searchData.authorityOption, searchData.joinCheck, orderBy, pageSize);
|
||||
};
|
||||
|
||||
// 검색 함수
|
||||
const handleSearch = (searchType, searchKey, groupType, joinCheck) => {
|
||||
fetchData(searchType, searchKey, groupType, joinCheck);
|
||||
};
|
||||
|
||||
// 오름차순 내림차순
|
||||
const handleOrderBy = e => {
|
||||
const order = e.target.value;
|
||||
|
||||
setOrderBy(order);
|
||||
fetchData(searchData.searchOption, searchData.data, searchData.authorityOption, searchData.joinCheck, order, pageSize);
|
||||
};
|
||||
|
||||
// 페이징
|
||||
const handlePageSize = e => {
|
||||
const size = e.target.value;
|
||||
setPageSize(size);
|
||||
setCurrentPage(1);
|
||||
fetchData(searchData.searchOption, searchData.data, searchData.authorityOption, searchData.joinCheck, orderBy, size, 1);
|
||||
};
|
||||
|
||||
// 사용자 승인
|
||||
const handleApprove = userEmail => {
|
||||
let list = [];
|
||||
|
||||
list.push({
|
||||
email: userEmail,
|
||||
is_approve: 'APPROVE',
|
||||
});
|
||||
|
||||
AdminLoginApprove(token, list);
|
||||
};
|
||||
|
||||
// 사옹자 반려
|
||||
const handleReject = userEmail => {
|
||||
let list = [];
|
||||
|
||||
list.push({
|
||||
email: userEmail,
|
||||
is_approve: 'REJECT',
|
||||
});
|
||||
|
||||
AdminLoginApprove(token, list);
|
||||
};
|
||||
|
||||
// 체크박스 선택 리스트
|
||||
const handleSelectCheckBox = e => {
|
||||
let list = [...selectedRow];
|
||||
|
||||
if (e.target.checked) {
|
||||
list.push(e.target.id);
|
||||
setSelectedRow(list);
|
||||
} else {
|
||||
const filterList = list.filter(data => e.target.id !== data);
|
||||
setSelectedRow(filterList);
|
||||
}
|
||||
};
|
||||
|
||||
// 승인버튼 유효성 검사
|
||||
const approveCheck = () => {
|
||||
let list = [];
|
||||
dataList.list && dataList.list.map(data => data.status === 'ROLE_NOT_PERMITTED' && list.push(data.email));
|
||||
|
||||
return list;
|
||||
};
|
||||
|
||||
// 승인 버튼 validation
|
||||
const handleApproveCheck = () => {
|
||||
const list = approveCheck();
|
||||
setApproveAble(list.filter(row => selectedRow.includes(row)).length === selectedRow.length);
|
||||
};
|
||||
|
||||
// 변경된 권한 등급 리스트
|
||||
const handleGroupGrade = e => {
|
||||
let list = [...selectedGroup];
|
||||
|
||||
const filterList = list.filter(data => e.target.id !== data.email);
|
||||
filterList.push({ email: e.target.id, group_id: e.target.value });
|
||||
setSelectedGroup(filterList);
|
||||
};
|
||||
|
||||
// 선택 승인 함수
|
||||
const handleSelectedApprove = () => {
|
||||
selectedRow.map(data => handleApprove(data));
|
||||
|
||||
handleApproveModalClose();
|
||||
handleConfirmeModalClose();
|
||||
};
|
||||
|
||||
// 선택 삭제 함수
|
||||
const handleSelectedDelete = () => {
|
||||
let list = [];
|
||||
|
||||
selectedRow.map(data =>
|
||||
list.push({
|
||||
email: data,
|
||||
}),
|
||||
);
|
||||
AdminDeleteUser(token, list);
|
||||
|
||||
handleDeleteModalClose();
|
||||
handleConfirmeModalClose();
|
||||
};
|
||||
|
||||
// 단일 승인 함수
|
||||
const handleSingleApprove = data => {
|
||||
handleApprove(data);
|
||||
|
||||
setSingleConfirmText('승인이 완료되었습니다.');
|
||||
handleSingleModalClose();
|
||||
};
|
||||
|
||||
// 선택 반려 함수
|
||||
const handleSingleReject = data => {
|
||||
handleReject(data);
|
||||
|
||||
setSingleConfirmText('승인이 반려되었습니다.');
|
||||
handleSingleModalClose();
|
||||
};
|
||||
|
||||
// 수정된 권한 등급 저장 함수
|
||||
const handleSelectedGroupSave = () => {
|
||||
AdminChangeGroup(token, selectedGroup);
|
||||
|
||||
handleSaveModalClose();
|
||||
handleConfirmeModalClose();
|
||||
};
|
||||
|
||||
// 비밀번호 저장 함수
|
||||
const handleResetPw = data => {
|
||||
setSelectedEmail(data);
|
||||
|
||||
handleInitialModalClose();
|
||||
};
|
||||
|
||||
const handlePasswordInitialize = () => {
|
||||
AdminChangePw(token, { email: selectedEmail });
|
||||
|
||||
// console.log(selectedEmail);
|
||||
|
||||
setConfirmText('비밀번호 초기화가');
|
||||
handleInitialModalClose();
|
||||
handleConfirmeModalClose();
|
||||
};
|
||||
// 전체 선택 구현
|
||||
const handleAllSelect = () => {
|
||||
let list = [];
|
||||
if (document.getElementById('check-all').checked === true) {
|
||||
dataList.list.map((data, index) => {
|
||||
document.getElementsByName('select')[index].checked = true;
|
||||
list.push(data.email);
|
||||
});
|
||||
} else if (document.getElementById('check-all').checked === false) {
|
||||
for (let i = 0; i < dataList.list.length; i++) {
|
||||
dataList.list.map((data, index) => (document.getElementsByName('select')[index].checked = false));
|
||||
list = [];
|
||||
}
|
||||
}
|
||||
setSelectedRow(list);
|
||||
};
|
||||
|
||||
const handleCountSelectedRow = () => {
|
||||
return currentPage > (dataList && dataList.total) / pageSize ? selectedRow.length === dataList.total % pageSize : selectedRow.length === Number(pageSize);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{userInfo.auth_list && !userInfo.auth_list.some(auth => auth.id === 1) ? (
|
||||
<AuthModal />
|
||||
) : (
|
||||
<>
|
||||
<Title>운영자 조회</Title>
|
||||
<FormWrapper action="" $flow="row">
|
||||
<AdminViewSearchBar handleSearch={handleSearch} groupList={groupList} setResultData={setSearchData} setCurrentPage={setCurrentPage} />
|
||||
</FormWrapper>
|
||||
|
||||
<TableInfo>
|
||||
<ListCount>
|
||||
총 : {dataList && dataList.total} 건 / {dataList && dataList.total_all} 건
|
||||
</ListCount>
|
||||
<ListOption>
|
||||
<SelectInput className="input-select" onChange={e => handleOrderBy(e)}>
|
||||
<option value="DESC">내림차순</option>
|
||||
<option value="ASC">오름차순</option>
|
||||
</SelectInput>
|
||||
<SelectInput className="input-select" onChange={e => handlePageSize(e)}>
|
||||
<option value="50">50개</option>
|
||||
<option value="100">100개</option>
|
||||
</SelectInput>
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === 4) && (
|
||||
<Button theme={selectedRow.length === 0 ? 'disable' : 'line'} text="선택 삭제" handleClick={handleDeleteModalClose} />
|
||||
)}
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === 2) && (
|
||||
<Button theme={selectedRow.length === 0 || !approveAble ? 'disable' : 'line'} text="선택 승인" handleClick={handleApproveModalClose} />
|
||||
)}
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === 3) && <Button theme="primary" text="저장" handleClick={handleSaveModalClose} />}
|
||||
</ListOption>
|
||||
</TableInfo>
|
||||
<TableStyle>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="40">
|
||||
<CheckBox id="check-all" handleCheck={handleAllSelect} checked={handleCountSelectedRow()} />
|
||||
</th>
|
||||
<th width="80">번호</th>
|
||||
<th width="200">이름</th>
|
||||
<th>ID (이메일 주소)</th>
|
||||
<th width="150">로그인 승인 상태</th>
|
||||
<th width="20%">권한 등급</th>
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === 3) && <th width="120">비밀번호 초기화</th>}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList.list &&
|
||||
dataList.list.map(user => (
|
||||
<Fragment key={user.id}>
|
||||
<tr>
|
||||
<td>
|
||||
<CheckBox
|
||||
name={'select'}
|
||||
id={user.email}
|
||||
setData={e => {
|
||||
handleSelectCheckBox(e);
|
||||
}}
|
||||
handleCheck={handleApproveCheck}
|
||||
/>
|
||||
</td>
|
||||
<td>{user.row_num}</td>
|
||||
<td>{user.name}</td>
|
||||
<td>{user.email}</td>
|
||||
{user.status !== 'ROLE_NOT_PERMITTED' ? (
|
||||
user.status === 'PERMITTED' || user.status === 'INIT' ? (
|
||||
<td>
|
||||
<span>승인완료</span>
|
||||
</td>
|
||||
) : (
|
||||
<td>
|
||||
<State color="#d60000">신청 반려</State>
|
||||
</td>
|
||||
)
|
||||
) : userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === 2) ? (
|
||||
<td>
|
||||
<BtnWrapper $gap="5px" $justify="center">
|
||||
<Button theme="primary" text="승인" handleClick={() => handleSingleApprove(user.email)} />
|
||||
<Button theme="line" text="불가" handleClick={() => handleSingleReject(user.email)} />
|
||||
</BtnWrapper>
|
||||
</td>
|
||||
) : (
|
||||
<td>
|
||||
<State color="gray">승인 대기 중</State>
|
||||
</td>
|
||||
)}
|
||||
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === 3) ? (
|
||||
<td>
|
||||
<SelectInput id={user.email} defaultValue={!user.group_id ? '선택' : user.group_id} onChange={e => handleGroupGrade(e)}>
|
||||
{user.group_id || (
|
||||
<option key={'선택'} value={'선택'} disabled>
|
||||
선택
|
||||
</option>
|
||||
)}
|
||||
|
||||
{groupList &&
|
||||
groupList.map(group => (
|
||||
<option key={group.group_id} value={group.group_id}>
|
||||
{group.group_nm}
|
||||
</option>
|
||||
))}
|
||||
</SelectInput>
|
||||
</td>
|
||||
) : (
|
||||
<td>
|
||||
<SelectInput id={user.email} defaultValue={user.group_id} disabled color="gray">
|
||||
{groupList &&
|
||||
groupList.map(group => (
|
||||
<option key={group.group_id} value={group.group_id}>
|
||||
{group.group_nm}
|
||||
</option>
|
||||
))}
|
||||
</SelectInput>
|
||||
</td>
|
||||
)}
|
||||
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === 3) && (
|
||||
<td>{(user.status === 'PERMITTED' || user.status === 'INIT') && <Button theme="reset" handleClick={() => handleResetPw(user.email)} />}</td>
|
||||
)}
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
<Pagination postsPerPage={pageSize} totalPosts={dataList && dataList.total_all} setCurrentPage={setCurrentPage} currentPage={currentPage} pageLimit={10} />
|
||||
{/* 선택 삭제 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={deleteModalClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleDeleteModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">
|
||||
선택된 운영자를 삭제하시겠습니까?
|
||||
<br />
|
||||
삭제 시 계정 정보가 제거됩니다.
|
||||
</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="취소" theme="line" size="large" width="100%" handleClick={handleDeleteModalClose} />
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleSelectedDelete} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
{/* 선택 승인 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={approveModalClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleApproveModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">
|
||||
선택된 운영자 로그인을
|
||||
<br />
|
||||
승인하시겠습니까?
|
||||
</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="취소" theme="line" size="large" width="100%" handleClick={handleApproveModalClose} />
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleSelectedApprove} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
{/* 저장 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={saveModalClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleSaveModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">
|
||||
운영자 정보 수정사항을
|
||||
<br />
|
||||
저장하시겠습니까?
|
||||
</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="취소" theme="line" size="large" width="100%" handleClick={handleSaveModalClose} />
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleSelectedGroupSave} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
{/* 확인 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={confirmModalClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleConfirmeModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">{confirmText} 완료되었습니다.</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleConfirmeModalClose} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
{/* 단일 승인 or 반려 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={singleModalClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleSingleModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">{singleConfirmText}</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleSingleModalClose} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
|
||||
{/* 비밀번호 초기화 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={initialModalClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleInitialModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">비밀번호를 초기화하시겠습니까?</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="취소" theme="line" size="large" width="100%" handleClick={handleInitialModalClose} />
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handlePasswordInitialize} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default AdminView;
|
||||
279
src/pages/UserManage/AuthSetting.js
Normal file
279
src/pages/UserManage/AuthSetting.js
Normal file
@@ -0,0 +1,279 @@
|
||||
import CheckBox from '../../components/common/input/CheckBox';
|
||||
|
||||
import Modal from '../../components/common/modal/Modal';
|
||||
import { Title, FormWrapper, SelectInput, TableInfo, ListCount, ListOption, TableStyle, BtnWrapper, ButtonClose, ModalText } from '../../styles/Components';
|
||||
import Button from '../../components/common/button/Button';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Fragment, useState, useEffect } from 'react';
|
||||
import { GroupViewList, GroupDelete, GroupRegist } from '../../apis/Group';
|
||||
import AuthRegistBar from '../../components/UserManage/AuthRegistBar';
|
||||
import Pagination from '../../components/common/Pagination/Pagination';
|
||||
import { authList } from '../../store/authList';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import AuthModal from '../../components/common/modal/AuthModal';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { authType } from '../../assets/data';
|
||||
import ViewTableInfo from '../../components/common/Table/ViewTableInfo';
|
||||
|
||||
const AuthSetting = () => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
const userInfo = useRecoilValue(authList);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [doubleSubmitFlag, setDoubleSubmitFlag] = useState(false);
|
||||
|
||||
const [dataList, setDataList] = useState([]);
|
||||
const [selectedRow, setSelectedRow] = useState([]);
|
||||
const [deleteModalClose, setDeleteModalClose] = useState('hidden');
|
||||
const [registModalClose, setRegistModalClose] = useState('hidden');
|
||||
const [confirmModalClose, setConfirmModalClose] = useState('hidden');
|
||||
const [isNullValue, setIsNullValue] = useState(false);
|
||||
|
||||
const [confirmText, setConfirmText] = useState();
|
||||
|
||||
const [orderBy, setOrderBy] = useState('DESC');
|
||||
const [pageSize, setPageSize] = useState('50');
|
||||
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
|
||||
const [registData, setRegistData] = useState({
|
||||
group_nm: '',
|
||||
description: '',
|
||||
});
|
||||
|
||||
const fetchData = async (order, size) => {
|
||||
setDataList(await GroupViewList(token, order ? order : orderBy, currentPage, size ? size : pageSize, currentPage));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchData(orderBy, pageSize);
|
||||
setSelectedRow([]);
|
||||
}, [currentPage]);
|
||||
|
||||
// 권한 등록 폼 제출
|
||||
const handleGroupSubmit = async () => {
|
||||
const message = await GroupRegist(token, registData);
|
||||
handleRegistModalClose();
|
||||
handleConfirmeModalClose();
|
||||
message.data.data.message !== '저장 하였습니다.' ? setConfirmText(message.data.data.message) : setConfirmText('등록이 완료되었습니다.');
|
||||
};
|
||||
|
||||
const handleAllSelect = () => {
|
||||
let list = [];
|
||||
|
||||
if (document.getElementById('check-all').checked === true) {
|
||||
dataList.group_list.map((data, index) => {
|
||||
document.getElementsByName('select')[index].checked = true;
|
||||
list.push(String(data.group_id));
|
||||
});
|
||||
} else if (document.getElementById('check-all').checked === false) {
|
||||
for (let i = 0; i < dataList.group_list.length; i++) {
|
||||
dataList.group_list.map((data, index) => (document.getElementsByName('select')[index].checked = false));
|
||||
list = [];
|
||||
}
|
||||
}
|
||||
|
||||
setSelectedRow(list);
|
||||
};
|
||||
|
||||
const handleSelectCheckBox = e => {
|
||||
let list = [...selectedRow];
|
||||
if (e.target.checked) {
|
||||
list.push(e.target.id);
|
||||
setSelectedRow(list);
|
||||
} else {
|
||||
const filterList = list.filter(data => e.target.id !== data);
|
||||
setSelectedRow(filterList);
|
||||
}
|
||||
};
|
||||
|
||||
// 삭제 확인 모달창
|
||||
const handleDeleteModalClose = () => {
|
||||
if (selectedRow.length !== 0 && deleteModalClose === 'hidden') {
|
||||
setDeleteModalClose('view');
|
||||
setConfirmText('삭제가 완료되었습니다.');
|
||||
} else {
|
||||
setDeleteModalClose('hidden');
|
||||
}
|
||||
};
|
||||
|
||||
// 등록 확인 모달창
|
||||
const handleRegistModalClose = () => {
|
||||
if (registData.group_nm.length === 0) {
|
||||
// if(registData.group_nm.length === 0) {
|
||||
// setNullMessage("필수값을 입력해주세요.")
|
||||
// } else if(registData.group_nm.charAt(0) === " "){
|
||||
// setNullMessage("텍스트를 공백으로 시작할 수 없습니다.")
|
||||
// }
|
||||
|
||||
setIsNullValue(true);
|
||||
} else if (registModalClose === 'hidden') {
|
||||
setRegistModalClose('view');
|
||||
setConfirmText('등록이 완료되었습니다.');
|
||||
setIsNullValue(false);
|
||||
} else {
|
||||
setRegistModalClose('hidden');
|
||||
}
|
||||
};
|
||||
|
||||
//삭제, 등록 완료 모달창
|
||||
const handleConfirmeModalClose = () => {
|
||||
if (confirmModalClose === 'hidden') {
|
||||
setConfirmModalClose('view');
|
||||
} else {
|
||||
setConfirmModalClose('hidden');
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
// 삭제 버튼
|
||||
const handleSelectedDelete = () => {
|
||||
let list = [];
|
||||
|
||||
selectedRow.map(data =>
|
||||
list.push({
|
||||
group_id: data,
|
||||
}),
|
||||
);
|
||||
|
||||
GroupDelete(token, list);
|
||||
handleDeleteModalClose();
|
||||
handleConfirmeModalClose();
|
||||
};
|
||||
|
||||
// 배열 정렬
|
||||
const handleOrderBy = e => {
|
||||
const order = e.target.value;
|
||||
|
||||
setOrderBy(order);
|
||||
fetchData(order, pageSize);
|
||||
};
|
||||
|
||||
const handlePageSize = e => {
|
||||
const size = e.target.value;
|
||||
setPageSize(size);
|
||||
setCurrentPage(1);
|
||||
|
||||
fetchData(orderBy, size, 1);
|
||||
};
|
||||
|
||||
const handleCountSelectedRow = () => {
|
||||
return currentPage > (dataList && dataList.total) / pageSize ? selectedRow.length === dataList.total % pageSize : selectedRow.length === Number(pageSize);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{userInfo.auth_list && !userInfo.auth_list.some(auth => auth.id === authType.authoritySettingRead) ? (
|
||||
<AuthModal />
|
||||
) : (
|
||||
<>
|
||||
<Title>권한 설정</Title>
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === authType.authoritySettingUpdate) && (
|
||||
<FormWrapper action="" $flow="row">
|
||||
<AuthRegistBar handleRegistModalClose={handleRegistModalClose} registData={registData} setRegistData={setRegistData} $isNullValue={isNullValue} nullMessage={t('NULL_MSG')} />
|
||||
</FormWrapper>
|
||||
)}
|
||||
<ViewTableInfo total={dataList.total} total_all={dataList.total_all} handleOrderBy={handleOrderBy} handlePageSize={handlePageSize}>
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === authType.authoritySettingDelete) && (
|
||||
<Button theme={selectedRow.length === 0 ? 'disable' : 'line'} text="선택 삭제" handleClick={handleDeleteModalClose} />
|
||||
)}
|
||||
</ViewTableInfo>
|
||||
<TableStyle>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="40">
|
||||
<CheckBox id="check-all" handleCheck={handleAllSelect} checked={handleCountSelectedRow()} />
|
||||
</th>
|
||||
<th width="80">번호</th>
|
||||
<th width="20%">관리자 그룹명</th>
|
||||
<th width="150">그룹 인원</th>
|
||||
<th>설명</th>
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === authType.authoritySettingUpdate) ? <th width="120">권한 설정</th> : ''}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList.group_list &&
|
||||
dataList.group_list.map(data => (
|
||||
<Fragment key={data.row_num}>
|
||||
<tr>
|
||||
<td>
|
||||
<CheckBox name={'select'} id={data.group_id} setData={e => handleSelectCheckBox(e)} />
|
||||
</td>
|
||||
<td>{data.row_num}</td>
|
||||
<td>{data.group_nm}</td>
|
||||
<td>{data.member_cnt}</td>
|
||||
<td>{data.description}</td>
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === authType.authoritySettingUpdate) && (
|
||||
<td>
|
||||
<Button
|
||||
theme="line"
|
||||
handleClick={e => {
|
||||
e.preventDefault();
|
||||
navigate(`/usermanage/authsetting/${data.group_id}`);
|
||||
}}
|
||||
text="수정"
|
||||
/>
|
||||
</td>
|
||||
)}
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
<Pagination postsPerPage={pageSize} totalPosts={dataList && dataList.total_all} setCurrentPage={setCurrentPage} currentPage={currentPage} pageLimit={10} />
|
||||
{/* 선택 삭제 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={deleteModalClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleDeleteModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">
|
||||
선택된 관리자 그룹을 삭제하시겠습니까?
|
||||
<br />
|
||||
삭제 시 관리자 그룹 정보가 제거됩니다.
|
||||
</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="취소" theme="line" size="large" width="100%" handleClick={handleDeleteModalClose} />
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleSelectedDelete} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
{/* 삭제 확인 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={confirmModalClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleConfirmeModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">{confirmText}</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleConfirmeModalClose} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
{/* 등록 확인 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={registModalClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={e => handleRegistModalClose(e)} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">신규 그룹을 등록하시겠습니까?</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="취소" theme="line" size="large" width="100%" handleClick={handleRegistModalClose} />
|
||||
<Button
|
||||
text="확인"
|
||||
theme="primary"
|
||||
type="submit"
|
||||
size="large"
|
||||
width="100%"
|
||||
handleClick={() => {
|
||||
doubleSubmitFlag || handleGroupSubmit();
|
||||
setDoubleSubmitFlag(true);
|
||||
}}
|
||||
/>
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AuthSetting;
|
||||
250
src/pages/UserManage/AuthSettingUpdate.js
Normal file
250
src/pages/UserManage/AuthSettingUpdate.js
Normal file
@@ -0,0 +1,250 @@
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { authList } from '../../store/authList';
|
||||
import { authType, modalTypes } from '../../assets/data';
|
||||
import { menuConfig } from '../../assets/data/menuConfig';
|
||||
import { Title, FormWrapper, BtnWrapper, TableStyle } from '../../styles/Components';
|
||||
import { GroupDetailViewList, GroupModify } from '../../apis';
|
||||
import Button from '../../components/common/button/Button';
|
||||
import AuthModal from '../../components/common/modal/AuthModal';
|
||||
import DynamicModal from '../../components/common/modal/DynamicModal';
|
||||
import { AuthGroupRows } from '../../components/UserManage';
|
||||
|
||||
const AuthSettingUpdate = () => {
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const userInfo = useRecoilValue(authList);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const id = location.pathname.split('/')[3];
|
||||
const [msg, setMsg] = useState('');
|
||||
|
||||
const {
|
||||
authGroups,
|
||||
selectedPermissions,
|
||||
modalState,
|
||||
setSelectedPermissions,
|
||||
setModalState
|
||||
} = useAuthSetting(id);
|
||||
|
||||
if (!userInfo.auth_list?.some(auth => auth.id === authType.authoritySettingUpdate)) {
|
||||
return <AuthModal />;
|
||||
}
|
||||
|
||||
const handlePermissionChange = (groupId, permissionId) => {
|
||||
setSelectedPermissions(prev => {
|
||||
const newPermissions = { ...prev };
|
||||
|
||||
if (permissionId === 'all') {
|
||||
const group = authGroups.find(g => g.id === groupId);
|
||||
const allPermissions = group.items.flatMap(item =>
|
||||
Object.values(item.permissions)
|
||||
);
|
||||
|
||||
newPermissions[groupId] = allPermissions;
|
||||
} else if (permissionId === 'none') {
|
||||
newPermissions[groupId] = [];
|
||||
} else {
|
||||
const currentGroupPermissions = newPermissions[groupId] || [];
|
||||
if (currentGroupPermissions.includes(Number(permissionId))) {
|
||||
newPermissions[groupId] = currentGroupPermissions.filter(id =>
|
||||
id !== Number(permissionId)
|
||||
);
|
||||
} else {
|
||||
newPermissions[groupId] = [...currentGroupPermissions, Number(permissionId)];
|
||||
}
|
||||
}
|
||||
|
||||
return newPermissions;
|
||||
});
|
||||
};
|
||||
|
||||
const handleModalView = (type) => {
|
||||
setModalState((prevState) => ({
|
||||
...prevState,
|
||||
[`${type}Modal`]: 'view',
|
||||
}));
|
||||
}
|
||||
|
||||
const handleModalClose = (type) => {
|
||||
setModalState((prevState) => ({
|
||||
...prevState,
|
||||
[`${type}Modal`]: 'hidden',
|
||||
}));
|
||||
}
|
||||
|
||||
const handleSubmit = async (type, param = null) => {
|
||||
switch (type) {
|
||||
case "cancelConfirm":
|
||||
setMsg(t('CANCEL_COMPLETED'));
|
||||
|
||||
handleModalClose('cancelConfirm');
|
||||
handleModalView('complete');
|
||||
break;
|
||||
case "registConfirm":
|
||||
const token = sessionStorage.getItem('token');
|
||||
const resultList = Object.values(selectedPermissions)
|
||||
.flat()
|
||||
.map(permissionId => ({ auth_id: permissionId }));
|
||||
|
||||
await GroupModify(token, id, resultList);
|
||||
|
||||
setMsg(t('SAVE_COMPLETED'));
|
||||
|
||||
handleModalClose('registConfirm');
|
||||
handleModalView('complete');
|
||||
break;
|
||||
case "complete":
|
||||
handleModalClose('complete');
|
||||
setMsg('');
|
||||
navigate('/usermanage/authsetting');
|
||||
// window.location.reload();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{userInfo.auth_list && !userInfo.auth_list.some(auth => auth.id === authType.authoritySettingUpdate) ? (
|
||||
<AuthModal />
|
||||
) : (
|
||||
<>
|
||||
<Title>권한 설정</Title>
|
||||
<FormWrapper $flow="column">
|
||||
<TableStyle>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="40"></th>
|
||||
<th></th>
|
||||
<th>메뉴</th>
|
||||
<th>조회</th>
|
||||
<th>승인</th>
|
||||
<th>등록/수정</th>
|
||||
<th>삭제</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{authGroups.map((group) => (
|
||||
<AuthGroupRows
|
||||
key={group.id}
|
||||
group={group}
|
||||
selectedPermissions={selectedPermissions[group.id] || []}
|
||||
onPermissionChange={handlePermissionChange}
|
||||
/>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
<BtnWrapper $justify="flex-end" $gap="5px">
|
||||
<Button
|
||||
theme="line"
|
||||
handleClick={() => handleModalView('cancelConfirm')}
|
||||
text="취소"
|
||||
/>
|
||||
<Button
|
||||
theme="primary"
|
||||
handleClick={() => handleModalView('registConfirm')}
|
||||
text="저장"
|
||||
/>
|
||||
</BtnWrapper>
|
||||
</FormWrapper>
|
||||
|
||||
<DynamicModal
|
||||
modalType={modalTypes.confirmOkCancel}
|
||||
view={modalState.cancelConfirmModal}
|
||||
modalText={t('CANCEL_CONFIRM')}
|
||||
handleSubmit={() => handleSubmit('cancelConfirm')}
|
||||
handleCancel={() => handleModalClose('cancelConfirm')}
|
||||
/>
|
||||
|
||||
<DynamicModal
|
||||
modalType={modalTypes.confirmOkCancel}
|
||||
view={modalState.registConfirmModal}
|
||||
modalText={t('SAVE_CONFIRM')}
|
||||
handleSubmit={() => handleSubmit('registConfirm')}
|
||||
handleCancel={() => handleModalClose('registConfirm')}
|
||||
/>
|
||||
|
||||
<DynamicModal
|
||||
modalType={modalTypes.completed}
|
||||
view={modalState.completeModal}
|
||||
modalText={msg}
|
||||
handleSubmit={() => handleSubmit('complete')}
|
||||
/>
|
||||
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const useAuthSetting = (initialId) => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
const [selectedPermissions, setSelectedPermissions] = useState({});
|
||||
const [modalState, setModalState] = useState({
|
||||
cancelConfirmModal: 'hidden',
|
||||
registConfirmModal: 'hidden',
|
||||
completeModal: 'hidden',
|
||||
});
|
||||
|
||||
// menuConfig를 기반으로 권한 그룹 구조화
|
||||
const authGroups = useMemo(() => {
|
||||
return Object.entries(menuConfig).map(([key, section]) => ({
|
||||
id: key,
|
||||
title: section.title,
|
||||
items: Object.entries(section.items).map(([itemKey, item]) => ({
|
||||
id: itemKey,
|
||||
title: item.title,
|
||||
permissions: item.permissions
|
||||
}))
|
||||
}));
|
||||
}, []);
|
||||
|
||||
// 권한 ID로 그룹과 아이템 찾기
|
||||
const findPermissionLocation = useCallback((permissionId) => {
|
||||
for (const [groupKey, group] of Object.entries(menuConfig)) {
|
||||
for (const [itemKey, item] of Object.entries(group.items)) {
|
||||
if (Object.values(item.permissions).includes(permissionId)) {
|
||||
return { groupKey, itemKey };
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}, []);
|
||||
|
||||
// API 데이터를 menuConfig 구조에 맞게 변환
|
||||
const formatPermissionsData = useCallback((apiData) => {
|
||||
return apiData.auth_list.reduce((acc, auth) => {
|
||||
const location = findPermissionLocation(auth.id);
|
||||
if (location) {
|
||||
if (!acc[location.groupKey]) {
|
||||
acc[location.groupKey] = [];
|
||||
}
|
||||
acc[location.groupKey].push(auth.id);
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
}, [findPermissionLocation]);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchInitialData = async () => {
|
||||
const data = await GroupDetailViewList(token, initialId);
|
||||
const formattedPermissions = formatPermissionsData(data);
|
||||
setSelectedPermissions(formattedPermissions);
|
||||
};
|
||||
|
||||
fetchInitialData();
|
||||
}, [initialId, formatPermissionsData]);
|
||||
|
||||
return {
|
||||
authGroups,
|
||||
selectedPermissions,
|
||||
modalState,
|
||||
setSelectedPermissions,
|
||||
setModalState
|
||||
};
|
||||
};
|
||||
|
||||
export default AuthSettingUpdate;
|
||||
678
src/pages/UserManage/AuthSettingUpdate_old.js
Normal file
678
src/pages/UserManage/AuthSettingUpdate_old.js
Normal file
@@ -0,0 +1,678 @@
|
||||
import AuthCheckBox from '../../components/common/input/AuthCheckBox';
|
||||
import CheckBox from '../../components/common/input/CheckBox';
|
||||
import { Title, FormWrapper, BtnWrapper, TableStyle, ButtonClose, ModalText } from '../../styles/Components';
|
||||
import Button from '../../components/common/button/Button';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { GroupDetailViewList, GroupModify } from '../../apis';
|
||||
import Modal from '../../components/common/modal/Modal';
|
||||
|
||||
import { authList } from '../../store/authList';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import AuthModal from '../../components/common/modal/AuthModal';
|
||||
import { authType } from '../../assets/data';
|
||||
|
||||
const AuthSettingUpdate = () => {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const userInfo = useRecoilValue(authList);
|
||||
|
||||
const id = location.pathname.split('/')[3];
|
||||
const token = sessionStorage.getItem('token');
|
||||
const [dataList, setDataList] = useState([]);
|
||||
const [selectedRow, setSelectedRow] = useState({ group1: [], group2: [], group3: [], group4: [] });
|
||||
|
||||
const [cancelModalClose, setCancelModalClose] = useState('hidden');
|
||||
const [saveModalClose, setSaveModalClose] = useState('hidden');
|
||||
const [confirmModalClose, setConfirmModalClose] = useState('hidden');
|
||||
const [confirmText, setConfirmText] = useState('');
|
||||
const [authRow, setAuthRow] = useState([]);
|
||||
|
||||
const AdminViewList = ['2', '3', '4'];
|
||||
const AuthSettingList = ['7', '8'];
|
||||
const UserViewList = ['12', '35'];
|
||||
const BoardList = ['17', '18'];
|
||||
const WhiteList = ['20', '21', '28'];
|
||||
const MailList = ['23', '29'];
|
||||
const ReportList = ['25', '31'];
|
||||
const UserBlockList = ['27', '30']; //DB상 report가 31이고 blocklist가 30인데 추후 테스트 필요해보인다
|
||||
const ItemList = ['33', '34'];
|
||||
const EventList = ['37', '38'];
|
||||
const CaliumRequest = ['40'];
|
||||
const LandAuctionList = ['41', '42', '43'];
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
selectedRow && setAuthRow(selectedRow);
|
||||
}, [selectedRow]);
|
||||
|
||||
const AdminView = authRow.group1 && authRow.group1.filter(data => AdminViewList.includes(data)).length > 0;
|
||||
const AuthSettingView = authRow.group1 && authRow.group1.filter(data => AuthSettingList.includes(data)).length > 0;
|
||||
const CaliumRequestView = authRow.group1 && authRow.group1.filter(data => CaliumRequest.includes(data)).length > 0;
|
||||
const UserView = authRow.group3 && authRow.group3.filter(data => UserViewList.includes(data)).length > 0;
|
||||
const BoardView = authRow.group4 && authRow.group4.filter(data => BoardList.includes(data)).length > 0;
|
||||
const WhiteView = authRow.group4 && authRow.group4.filter(data => WhiteList.includes(data)).length > 0;
|
||||
const MailView = authRow.group4 && authRow.group4.filter(data => MailList.includes(data)).length > 0;
|
||||
const ReportView = authRow.group4 && authRow.group4.filter(data => ReportList.includes(data)).length > 0;
|
||||
const BlockView = authRow.group4 && authRow.group4.filter(data => UserBlockList.includes(data)).length > 0;
|
||||
const ItemView = authRow.group4 && authRow.group4.filter(data => ItemList.includes(data)).length > 0;
|
||||
const EventView = authRow.group4 && authRow.group4.filter(data => EventList.includes(data)).length > 0;
|
||||
const LandAuctionView = authRow.group4 && authRow.group4.filter(data => LandAuctionList.includes(data)).length > 0;
|
||||
|
||||
const fetchData = async () => {
|
||||
setDataList(await GroupDetailViewList(token, id));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const Group1List = dataList.auth_list && dataList.auth_list.filter(data => data.id >= 1 && data.id <= 8
|
||||
|| (data.id >= authType.caliumRequestRead && data.id <= authType.caliumRequestUpdate)).map(group => String(group.id));
|
||||
const Group2List = dataList.auth_list && dataList.auth_list.filter(data => data.id >= 9 && data.id <= 10).map(group => String(group.id));
|
||||
const Group3List = dataList.auth_list && dataList.auth_list.filter(data => (data.id >= 11 && data.id <= 15)
|
||||
|| data.id === 35).map(group => String(group.id));
|
||||
const Group4List = dataList.auth_list && dataList.auth_list.filter(data => (data.id >= 16 && data.id <= 34)
|
||||
|| (data.id >= 36 && data.id <= 38)
|
||||
|| (data.id >= authType.landAuctionRead && data.id <= authType.landAuctionDelete) ).map(group => String(group.id));
|
||||
|
||||
setSelectedRow({ group1: Group1List, group2: Group2List, group3: Group3List, group4: Group4List });
|
||||
}, [dataList]);
|
||||
|
||||
// 전체 선택 구현
|
||||
const handlGroupSelect = order => {
|
||||
let list = [];
|
||||
const groupAllCheck = document.getElementById('group' + order);
|
||||
const groupData = document.getElementsByName('group' + order);
|
||||
|
||||
if (groupAllCheck.checked === true) {
|
||||
// console.log(groupData.length);
|
||||
for (let i = 0; i < groupData.length; i++) {
|
||||
const data = document.getElementsByName('group' + order)[i];
|
||||
data.checked = true;
|
||||
list.push(data.id);
|
||||
}
|
||||
} else if (groupAllCheck.checked === false) {
|
||||
for (let i = 0; i < groupData.length; i++) {
|
||||
const data = document.getElementsByName('group' + order)[i];
|
||||
data.checked = false;
|
||||
list = [];
|
||||
}
|
||||
}
|
||||
|
||||
setSelectedRow({ ...selectedRow, ['group' + order]: list });
|
||||
};
|
||||
|
||||
const handleSelectedAuthSave = () => {
|
||||
let strArr1 = Object.values(selectedRow[`group1`]);
|
||||
let strArr2 = Object.values(selectedRow[`group2`]);
|
||||
let strArr3 = Object.values(selectedRow[`group3`]);
|
||||
let strArr4 = Object.values(selectedRow[`group4`]);
|
||||
|
||||
let resultList = [];
|
||||
|
||||
const newArr = [...strArr1, ...strArr2, ...strArr3, ...strArr4];
|
||||
|
||||
newArr.map(data => resultList.push({ auth_id: data }));
|
||||
|
||||
GroupModify(token, id, resultList);
|
||||
|
||||
handleSaveModalClose();
|
||||
handleConfirmeModalClose();
|
||||
};
|
||||
|
||||
const handleExistedId = (id, name) => {
|
||||
return selectedRow[name] && selectedRow[name].includes(String(id));
|
||||
};
|
||||
|
||||
// 취소 모달
|
||||
const handleCancelModalClose = () => {
|
||||
if (cancelModalClose === 'hidden') {
|
||||
setCancelModalClose('view');
|
||||
} else {
|
||||
setCancelModalClose('hidden');
|
||||
setConfirmText('취소가');
|
||||
}
|
||||
};
|
||||
|
||||
// 저장 모달
|
||||
const handleSaveModalClose = () => {
|
||||
if (saveModalClose === 'hidden') {
|
||||
setSaveModalClose('view');
|
||||
} else {
|
||||
setSaveModalClose('hidden');
|
||||
setConfirmText('저장이');
|
||||
}
|
||||
};
|
||||
|
||||
// 확인 모달창
|
||||
const handleConfirmeModalClose = () => {
|
||||
if (confirmModalClose === 'hidden') {
|
||||
setConfirmModalClose('view');
|
||||
} else {
|
||||
setConfirmModalClose('hidden');
|
||||
navigate('/usermanage/authsetting');
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
const handleCountSelectedRow = (name, count) => {
|
||||
switch (name) {
|
||||
case 'group1':
|
||||
return selectedRow.group1 && selectedRow.group1.filter(data => data >= 1 && data <= 8).length > 0;
|
||||
case 'group2':
|
||||
return selectedRow.group2 && selectedRow.group2.filter(data => data >= 9 && data <= 10).length > 0;
|
||||
case 'group3':
|
||||
return selectedRow.group3 && selectedRow.group3.filter(data => (data >= 11 && data <= 15)).length > 0;
|
||||
case 'group4':
|
||||
return selectedRow.group4 && selectedRow.group4.filter(data => (data >= 16 && data <= 38) || (data >= 41 && data <= 43)).length > 0;
|
||||
default:
|
||||
}
|
||||
};
|
||||
|
||||
function killEvent(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
// 체크박스 선택 리스트
|
||||
const handleSelectAuthCheckBox = e => {
|
||||
let list = selectedRow[e.target.name];
|
||||
|
||||
if (e.target.checked) {
|
||||
list.push(e.target.id);
|
||||
|
||||
if (AdminViewList.includes(e.target.id)) list.includes('1') || list.push('1');
|
||||
else if (AuthSettingList.includes(e.target.id)) list.includes('6') || list.push('6');
|
||||
else if (UserViewList.includes(e.target.id)) list.includes('11') || list.push('11');
|
||||
else if (BoardList.includes(e.target.id)) list.includes('16') || list.push('16');
|
||||
else if (WhiteList.includes(e.target.id)) list.includes('19') || list.push('19');
|
||||
else if (MailList.includes(e.target.id)) list.includes('22') || list.push('22');
|
||||
else if (ReportList.includes(e.target.id)) list.includes('24') || list.push('24');
|
||||
else if (UserBlockList.includes(e.target.id)) list.includes('26') || list.push('26');
|
||||
else if (ItemList.includes(e.target.id)) list.includes('32') || list.push('32');
|
||||
else if (EventList.includes(e.target.id)) list.includes('36') || list.push('36');
|
||||
else if (CaliumRequest.includes(e.target.id)) list.includes('39') || list.push('39');
|
||||
else if (CaliumRequest.includes(e.target.id)) list.includes('41') || list.push('41');
|
||||
|
||||
setSelectedRow({ ...selectedRow, [e.target.name]: list });
|
||||
} else {
|
||||
const filterList = list.filter(data => e.target.id !== data);
|
||||
setSelectedRow({ ...selectedRow, [e.target.name]: filterList });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{userInfo.auth_list && !userInfo.auth_list.some(auth => auth.id === authType.authoritySettingUpdate) ? (
|
||||
<AuthModal />
|
||||
) : (
|
||||
<>
|
||||
<Title>권한 설정</Title>
|
||||
<FormWrapper $flow="column">
|
||||
<TableStyle>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="40"></th>
|
||||
<th></th>
|
||||
<th>메뉴</th>
|
||||
<th>조회</th>
|
||||
<th>승인</th>
|
||||
<th>등록 / 수정</th>
|
||||
<th>삭제</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td rowSpan="4">
|
||||
<AuthCheckBox id="group1" handleCheck={() => handlGroupSelect(1)}
|
||||
checked={handleCountSelectedRow('group1', 8)} />
|
||||
</td>
|
||||
<td rowSpan="4">운영자 관리</td>
|
||||
<td>운영자 조회</td>
|
||||
<td>
|
||||
<AuthCheckBox id="1" name="group1"
|
||||
checked={handleExistedId(authType.adminSearchRead, 'group1') || AdminView}
|
||||
setData={handleSelectAuthCheckBox} disabled={AdminView} />
|
||||
</td>
|
||||
<td>
|
||||
<AuthCheckBox id="2" name="group1"
|
||||
checked={handleExistedId(authType.adminSearchConfirm, 'group1')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<AuthCheckBox id="3" name="group1"
|
||||
checked={handleExistedId(authType.adminSearchUpdate, 'group1')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<AuthCheckBox id="4" name="group1"
|
||||
checked={handleExistedId(authType.adminSearchDelete, 'group1')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>사용 이력 조회</td>
|
||||
<td>
|
||||
<AuthCheckBox id="5" name="group1"
|
||||
checked={handleExistedId(authType.adminLogSearchRead, 'group1')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>권한 설정</td>
|
||||
<td>
|
||||
<AuthCheckBox id="6" name="group1"
|
||||
checked={handleExistedId(authType.authoritySettingRead, 'group1') || AuthSettingView}
|
||||
disabled={AuthSettingView} setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
<td>
|
||||
<AuthCheckBox id="7" name="group1"
|
||||
checked={handleExistedId(authType.authoritySettingUpdate, 'group1')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<AuthCheckBox id="8" name="group1"
|
||||
checked={handleExistedId(authType.authoritySettingDelete, 'group1')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>칼리움 요청</td>
|
||||
<td>
|
||||
<AuthCheckBox id="39" name="group1"
|
||||
checked={handleExistedId(authType.caliumRequestRead, 'group1') || CaliumRequestView}
|
||||
disabled={CaliumRequestView} setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
<td>
|
||||
<AuthCheckBox id="40" name="group1"
|
||||
checked={handleExistedId(authType.caliumRequestUpdate, 'group1')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr className="table-line">
|
||||
<td rowSpan="2">
|
||||
<AuthCheckBox id="group2" handleCheck={() => handlGroupSelect(2)}
|
||||
checked={handleCountSelectedRow('group2', 2)} />
|
||||
</td>
|
||||
<td rowSpan="2">지표 관리</td>
|
||||
<td>유저 지표</td>
|
||||
<td>
|
||||
<AuthCheckBox id="9" name="group2"
|
||||
checked={handleExistedId(authType.userIndicatorsRead, 'group2')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>경제 지표</td>
|
||||
<td>
|
||||
<AuthCheckBox id="10" name="group2"
|
||||
checked={handleExistedId(authType.economicIndicatorsRead, 'group2')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr className="table-line">
|
||||
<td rowSpan="4">
|
||||
<AuthCheckBox id="group3" handleCheck={() => handlGroupSelect(3)}
|
||||
checked={handleCountSelectedRow('group3', 5)} />
|
||||
</td>
|
||||
<td rowSpan="4">운영 정보 관리</td>
|
||||
<td>유저 조회</td>
|
||||
<td>
|
||||
<AuthCheckBox id="11" name="group3"
|
||||
checked={handleExistedId(authType.userSearchRead, 'group3') || UserView}
|
||||
disabled={UserView} setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
<td>
|
||||
<AuthCheckBox id="12" name="group3"
|
||||
checked={handleExistedId(authType.userSearchUpdate, 'group3')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<AuthCheckBox id="35" name="group3"
|
||||
checked={handleExistedId(authType.userSearchDelete, 'group3')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>컨텐츠 조회</td>
|
||||
<td>
|
||||
<AuthCheckBox id="13" name="group3"
|
||||
checked={handleExistedId(authType.contentSearchRead, 'group3')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>게임 로그 조회</td>
|
||||
<td>
|
||||
<AuthCheckBox id="14" name="group3"
|
||||
checked={handleExistedId(authType.gameLogRead, 'group3')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>크립토 조회</td>
|
||||
<td>
|
||||
<AuthCheckBox id="15" name="group3"
|
||||
checked={handleExistedId(authType.cryptoRead, 'group3')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr className="table-line">
|
||||
<td rowSpan="8">
|
||||
<AuthCheckBox id="group4" handleCheck={() => handlGroupSelect(4)}
|
||||
checked={handleCountSelectedRow('group4', 25)} />
|
||||
</td>
|
||||
<td rowSpan="8">운영 서비스 관리</td>
|
||||
<td>인게임 메시지</td>
|
||||
<td>
|
||||
<AuthCheckBox id="16" name="group4"
|
||||
checked={handleExistedId(authType.inGameRead, 'group4') || BoardView}
|
||||
disabled={BoardView} setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
<td>
|
||||
<AuthCheckBox id="17" name="group4"
|
||||
checked={handleExistedId(authType.inGameUpdate, 'group4')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<AuthCheckBox id="18" name="group4"
|
||||
checked={handleExistedId(authType.inGameDelete, 'group4')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>화이트리스트</td>
|
||||
<td>
|
||||
<AuthCheckBox id="19" name="group4"
|
||||
checked={handleExistedId(authType.whiteListRead, 'group4') || WhiteView}
|
||||
disabled={WhiteView} setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<AuthCheckBox id="20" name="group4"
|
||||
checked={handleExistedId(authType.whiteListConfirm, 'group4')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<AuthCheckBox id="21" name="group4"
|
||||
checked={handleExistedId(authType.whiteListUpdate, 'group4')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<AuthCheckBox id="28" name="group4"
|
||||
checked={handleExistedId(authType.whiteListDelete, 'group4')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>우편</td>
|
||||
<td>
|
||||
<AuthCheckBox id="22" name="group4"
|
||||
checked={handleExistedId(authType.mailRead, 'group4') || MailView}
|
||||
disabled={MailView} setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
<td>
|
||||
<AuthCheckBox id="23" name="group4"
|
||||
checked={handleExistedId(authType.mailUpdate, 'group4')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<AuthCheckBox id="29" name="group4"
|
||||
checked={handleExistedId(authType.mailDelete, 'group4')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>이용자 제재</td>
|
||||
<td>
|
||||
<AuthCheckBox id="24" name="group4"
|
||||
checked={handleExistedId(authType.blackListRead, 'group4') || ReportView}
|
||||
disabled={ReportView} setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
<td>
|
||||
<AuthCheckBox id="25" name="group4"
|
||||
checked={handleExistedId(authType.blackListUpdate, 'group4')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<AuthCheckBox id="30" name="group4"
|
||||
checked={handleExistedId(authType.blackListDelete, 'group4')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>신고내역</td>
|
||||
<td>
|
||||
<AuthCheckBox id="26" name="group4"
|
||||
checked={handleExistedId(authType.reportRead, 'group4') || BlockView}
|
||||
disabled={BlockView} setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
<td>
|
||||
<AuthCheckBox id="27" name="group4"
|
||||
checked={handleExistedId(authType.reportUpdate, 'group4')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<AuthCheckBox id="31" name="group4"
|
||||
checked={handleExistedId(authType.reportDelete, 'group4')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>아이템 복구 및 삭제</td>
|
||||
<td>
|
||||
<AuthCheckBox id="32" name="group4"
|
||||
checked={handleExistedId(authType.itemRead, 'group4') || ItemView}
|
||||
disabled={ItemView} setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
<td>
|
||||
<AuthCheckBox id="33" name="group4"
|
||||
checked={handleExistedId(authType.itemUpdate, 'group4')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<AuthCheckBox id="34" name="group4"
|
||||
checked={handleExistedId(authType.itemDelete, 'group4')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>보상 이벤트 관리</td>
|
||||
<td>
|
||||
<AuthCheckBox id="36" name="group4"
|
||||
checked={handleExistedId(authType.eventRead, 'group4')}
|
||||
disabled={EventView} setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
<td>
|
||||
<AuthCheckBox id="37" name="group4"
|
||||
checked={handleExistedId(authType.eventUpdate, 'group4')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<AuthCheckBox id="38" name="group4"
|
||||
checked={handleExistedId(authType.eventDelete, 'group4')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>랜드 경매 관리</td>
|
||||
<td>
|
||||
<AuthCheckBox id="41" name="group4"
|
||||
checked={handleExistedId(authType.landAuctionRead, 'group4')}
|
||||
disabled={LandAuctionView} setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<CheckBox disabled={true} />
|
||||
</td>
|
||||
<td>
|
||||
<AuthCheckBox id="42" name="group4"
|
||||
checked={handleExistedId(authType.landAuctionUpdate, 'group4')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
<td>
|
||||
<AuthCheckBox id="43" name="group4"
|
||||
checked={handleExistedId(authType.landAuctionDelete, 'group4')}
|
||||
setData={handleSelectAuthCheckBox} />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
<BtnWrapper $justify="flex-end" $gap="5px">
|
||||
<Button
|
||||
theme="line"
|
||||
handleClick={e => {
|
||||
e.preventDefault();
|
||||
handleCancelModalClose();
|
||||
}}
|
||||
text="취소"
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
theme="primary"
|
||||
text="저장"
|
||||
handleClick={e => {
|
||||
e.preventDefault();
|
||||
handleSaveModalClose();
|
||||
}}
|
||||
/>
|
||||
</BtnWrapper>
|
||||
</FormWrapper>
|
||||
|
||||
{/* 취소 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={cancelModalClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleCancelModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">
|
||||
취소하시겠습니까?
|
||||
<br />
|
||||
취소 시 변경된 값은 초기화됩니다.
|
||||
</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="취소" theme="line" size="large" width="100%" handleClick={handleCancelModalClose} />
|
||||
<Button
|
||||
text="확인"
|
||||
theme="primary"
|
||||
type="submit"
|
||||
size="large"
|
||||
width="100%"
|
||||
handleClick={() => {
|
||||
handleCancelModalClose();
|
||||
handleConfirmeModalClose();
|
||||
}}
|
||||
/>
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
{/* 저장 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={saveModalClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleSaveModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">저장하시겠습니까? </ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="취소" theme="line" size="large" width="100%" handleClick={handleSaveModalClose} />
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleSelectedAuthSave} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
{/* 확인 모달 */}
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={confirmModalClose}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={handleConfirmeModalClose} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">{confirmText} 완료되었습니다.</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={handleConfirmeModalClose} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AuthSettingUpdate;
|
||||
277
src/pages/UserManage/CaliumRequest.js
Normal file
277
src/pages/UserManage/CaliumRequest.js
Normal file
@@ -0,0 +1,277 @@
|
||||
import { useState, useEffect, Fragment, useRef } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import 'react-datepicker/dist/react-datepicker.css';
|
||||
|
||||
import { authList } from '../../store/authList';
|
||||
import {
|
||||
authType,
|
||||
commonStatus,
|
||||
modalTypes,
|
||||
ViewTitleCountType,
|
||||
caliumStatus
|
||||
} from '../../assets/data';
|
||||
import { Title, FormWrapper, TableStyle, TableWrapper, PopupMessage } from '../../styles/Components';
|
||||
import {
|
||||
StatusWapper,
|
||||
ChargeBtn,
|
||||
StatusLabel,
|
||||
} from '../../styles/ModuleComponents';
|
||||
import {Button, ExcelDownButton, Pagination, DynamicModal, ViewTableInfo, Loading} from '../../components/common';
|
||||
import { convertKTC, truncateText } from '../../utils';
|
||||
import { CaliumRequestRegistModal, CaliumRequestSearchBar } from '../../components/UserManage';
|
||||
import { CaliumCharge, CaliumRequestView } from '../../apis';
|
||||
import { withAuth } from '../../utils/hook';
|
||||
import { convertEndDateToISO, convertStartDateToISO } from '../../utils/date';
|
||||
|
||||
const CaliumRequest = () => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
const userInfo = useRecoilValue(authList);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const tableRef = useRef(null);
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [pageSize, setPageSize] = useState(50);
|
||||
|
||||
const [dataList, setDataList] = useState([]);
|
||||
const [detailData, setDetailData] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [alertMsg, setAlertMsg] = useState('');
|
||||
const [selectCharge, setSelectCharge] = useState({});
|
||||
|
||||
const [searchData, setSearchData] = useState({
|
||||
content: '',
|
||||
status: 'ALL',
|
||||
startDate: '',
|
||||
endDate: '',
|
||||
});
|
||||
const [orderBy, setOrderBy] = useState('DESC');
|
||||
const [modalState, setModalState] = useState({
|
||||
detailModal: 'hidden',
|
||||
registerModal: 'hidden',
|
||||
chargedCompleteModal: 'hidden',
|
||||
chargedConfirmModal: 'hidden'
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
fetchData('', 'ALL', '', '');
|
||||
}, [currentPage]);
|
||||
|
||||
// 리스트 조회
|
||||
const fetchData = async (content, status, startDate, endDate, order, size) => {
|
||||
setDataList(
|
||||
await CaliumRequestView(
|
||||
token,
|
||||
content,
|
||||
status,
|
||||
startDate && convertStartDateToISO(startDate),
|
||||
endDate && convertEndDateToISO(endDate),
|
||||
order ? order : orderBy,
|
||||
size ? size : pageSize,
|
||||
currentPage,
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
// 검색 함수
|
||||
const handleSearch = (content, status, startDate, endDate) => {
|
||||
fetchData(content, status, startDate, endDate);
|
||||
};
|
||||
|
||||
// 오름차순 내림차순
|
||||
const handleOrderBy = e => {
|
||||
const order = e.target.value;
|
||||
|
||||
setOrderBy(order);
|
||||
fetchData(
|
||||
searchData.content,
|
||||
searchData.status,
|
||||
searchData.startDate,
|
||||
searchData.endDate,
|
||||
order,
|
||||
pageSize,
|
||||
);
|
||||
};
|
||||
|
||||
const handlePageSize = e => {
|
||||
const size = e.target.value;
|
||||
setPageSize(size);
|
||||
setCurrentPage(1);
|
||||
|
||||
fetchData(
|
||||
searchData.content,
|
||||
searchData.status,
|
||||
searchData.startDate,
|
||||
searchData.endDate,
|
||||
orderBy,
|
||||
size,
|
||||
1,
|
||||
);
|
||||
};
|
||||
|
||||
// 상세보기 호출
|
||||
// const handleDetailModal = async (e, id) => {
|
||||
// await EventDetailView(token, id).then(data => {
|
||||
// setDetailData(data);
|
||||
// });
|
||||
//
|
||||
// e.preventDefault();
|
||||
// handleModalView('detail');
|
||||
// };
|
||||
|
||||
const handleModalView = (type) => {
|
||||
setModalState((prevState) => ({
|
||||
...prevState,
|
||||
[`${type}Modal`]: 'view',
|
||||
}));
|
||||
}
|
||||
|
||||
const handleModalClose = (type) => {
|
||||
setModalState((prevState) => ({
|
||||
...prevState,
|
||||
[`${type}Modal`]: 'hidden',
|
||||
}));
|
||||
}
|
||||
|
||||
const handleSubmit = async (type, param = null) => {
|
||||
switch (type) {
|
||||
case "detail":
|
||||
setDetailData(param);
|
||||
handleModalView('detail');
|
||||
break;
|
||||
case "chargedConfirm":
|
||||
setSelectCharge({id: param.id, count: param.count});
|
||||
handleModalView('chargedConfirm');
|
||||
break;
|
||||
case "charged":
|
||||
handleModalClose('chargedConfirm');
|
||||
setLoading(true);
|
||||
await CaliumCharge(token, selectCharge).then(data => {
|
||||
setLoading(false);
|
||||
if(data.result === "SUCCESS") {
|
||||
setAlertMsg(t('CHARGE_COMPLTED'));
|
||||
handleModalView('chargedComplete');
|
||||
}else if(data.result === "ERROR_CALIUM_FINISH") {
|
||||
setAlertMsg(t('CHARGE_FINISH_FAIL'));
|
||||
handleModalView('chargedComplete');
|
||||
}else{
|
||||
setAlertMsg(t('CHARGE_FAIL'));
|
||||
handleModalView('chargedComplete');
|
||||
}
|
||||
setSelectCharge({});
|
||||
});
|
||||
break;
|
||||
case "chargedComplete":
|
||||
handleModalClose('chargedComplete');
|
||||
await fetchData(
|
||||
searchData.content,
|
||||
searchData.status,
|
||||
searchData.startDate,
|
||||
searchData.endDate
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Title>칼리움 사용 수량 요청</Title>
|
||||
<FormWrapper>
|
||||
<CaliumRequestSearchBar handleSearch={handleSearch} setResultData={setSearchData} />
|
||||
</FormWrapper>
|
||||
<ViewTableInfo total={dataList.total} total_all={dataList.total_all} handleOrderBy={handleOrderBy} handlePageSize={handlePageSize} countType={ViewTitleCountType.calium}>
|
||||
<ExcelDownButton tableRef={tableRef} fileName={t('FILE_CALIUM_REQUEST')} />
|
||||
{userInfo.auth_list && userInfo.auth_list.some(auth => auth.id === authType.eventUpdate) && (
|
||||
<Button
|
||||
theme="primary"
|
||||
text="요청 등록"
|
||||
type="button"
|
||||
handleClick={e => {
|
||||
e.preventDefault();
|
||||
handleModalView('register');
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</ViewTableInfo>
|
||||
<TableWrapper>
|
||||
<TableStyle ref={tableRef}>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
{/*<th width="80">번호</th>*/}
|
||||
<th width="210">요청 일시</th>
|
||||
<th width="140">요청 부서</th>
|
||||
<th width="100">요청자</th>
|
||||
<th>요청 사유</th>
|
||||
<th width="80">요청수량</th>
|
||||
<th width="160">진행상태</th>
|
||||
<th width="210">최종 처리일시</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList.list &&
|
||||
dataList.list.map(calium => (
|
||||
<Fragment key={calium.row_num}>
|
||||
<tr>
|
||||
{/*<td>{calium.row_num}</td>*/}
|
||||
<td>{convertKTC(calium.create_dt)}</td>
|
||||
<td>{calium.dept}</td>
|
||||
<td>{calium.create_by}</td>
|
||||
<td>
|
||||
<PopupMessage onClick={e => handleSubmit('detail', calium.content)}>
|
||||
{truncateText(calium.content)}
|
||||
</PopupMessage>
|
||||
</td>
|
||||
<td>{calium.count}</td>
|
||||
<StatusWapper>
|
||||
<StatusLabel $status={calium.status}>{caliumStatus.map(data => data.value === calium.status && data.name)}</StatusLabel>
|
||||
{calium.status === commonStatus.complete && userInfo.auth_list?.some(auth => auth.id === authType.eventUpdate) && calium.create_by === userInfo.name &&
|
||||
<ChargeBtn onClick={() => handleSubmit('chargedConfirm', {id: calium.id, count: calium.count})}>충전</ChargeBtn>
|
||||
}
|
||||
</StatusWapper>
|
||||
<td>{convertKTC(calium.state_time)}</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
</TableWrapper>
|
||||
|
||||
<Pagination postsPerPage={pageSize} totalPosts={dataList && dataList.total_all} setCurrentPage={setCurrentPage} currentPage={currentPage} pageLimit={10} />
|
||||
|
||||
{/*상세*/}
|
||||
{/*<EventDetailModal detailView={modalState.detailModal} handleDetailView={() => handleModalClose('detail')} content={detailData} setDetailData={setDetailData}/>*/}
|
||||
|
||||
<CaliumRequestRegistModal registView={modalState.registerModal} setRegistView={() => handleModalClose('register')} userInfo={userInfo} />
|
||||
|
||||
<DynamicModal
|
||||
modalType={modalTypes.confirmOkCancel}
|
||||
view={modalState.chargedConfirmModal}
|
||||
handleCancel={() => handleModalClose('chargedConfirm')}
|
||||
handleSubmit={() => handleSubmit('charged')}
|
||||
modalText={t('CALIUM_CHARGE_CONFIRM')}
|
||||
/>
|
||||
<DynamicModal
|
||||
modalType={modalTypes.completed}
|
||||
view={modalState.chargedCompleteModal}
|
||||
modalText={alertMsg}
|
||||
handleSubmit={() => handleSubmit('chargedComplete')}
|
||||
/>
|
||||
<DynamicModal
|
||||
modalType={modalTypes.completed}
|
||||
view={modalState.chargedCompleteModal}
|
||||
modalText={alertMsg}
|
||||
handleSubmit={() => handleSubmit('chargedComplete')}
|
||||
/>
|
||||
<DynamicModal
|
||||
modalType={modalTypes.completed}
|
||||
view={modalState.detailModal}
|
||||
modalText={detailData}
|
||||
handleSubmit={() => handleModalClose('detail')}
|
||||
/>
|
||||
{loading && <Loading/>}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default withAuth(authType.caliumRequestRead)(CaliumRequest);
|
||||
170
src/pages/UserManage/LogView.js
Normal file
170
src/pages/UserManage/LogView.js
Normal file
@@ -0,0 +1,170 @@
|
||||
import { Fragment, useState, useEffect } from 'react';
|
||||
|
||||
import LogViewSearchBar from '../../components/UserManage/LogViewSearchBar';
|
||||
import { Title, FormWrapper, SelectInput, TableInfo, ListCount, ListOption, TableStyle, BtnWrapper, ButtonClose, ModalText } from '../../styles/Components';
|
||||
import Button from '../../components/common/button/Button';
|
||||
import Pagination from '../../components/common/Pagination/Pagination';
|
||||
import Modal from '../../components/common/modal/Modal';
|
||||
|
||||
import LogViewModal from '../../components/UserManage/LogViewModal';
|
||||
|
||||
import { LogViewList } from '../../apis';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { authList } from '../../store/authList';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { logOption } from '../../assets/data';
|
||||
import { convertKTC } from '../../utils';
|
||||
|
||||
const LogView = () => {
|
||||
const navigate = useNavigate();
|
||||
const userInfo = useRecoilValue(authList);
|
||||
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
|
||||
const [stateModal, setStateModal] = useState('hidden');
|
||||
const [dataList, setDataList] = useState([]);
|
||||
const [detailData, setDetailData] = useState('');
|
||||
const [searchData, setSearchData] = useState({});
|
||||
const [orderBy, setOrderBy] = useState('DESC');
|
||||
const [pageSize, setPageSize] = useState('50');
|
||||
|
||||
const handleButtonClick = content => {
|
||||
setStateModal('view');
|
||||
setDetailData(content);
|
||||
};
|
||||
|
||||
const handleModal = () => {
|
||||
if (stateModal === 'hidden') {
|
||||
setStateModal('view');
|
||||
} else {
|
||||
setStateModal('hidden');
|
||||
}
|
||||
};
|
||||
|
||||
const handleOrderBy = e => {
|
||||
const order = e.target.value;
|
||||
setOrderBy(order);
|
||||
fetchData(
|
||||
searchData.searchOption,
|
||||
searchData.data,
|
||||
searchData.logOption,
|
||||
searchData.startDate && new Date(searchData.startDate).toISOString(),
|
||||
searchData.endDate && new Date(searchData.endDate).toISOString(),
|
||||
order,
|
||||
pageSize,
|
||||
);
|
||||
};
|
||||
|
||||
const handlePageSize = e => {
|
||||
const size = e.target.value;
|
||||
setPageSize(size);
|
||||
setCurrentPage(1);
|
||||
fetchData(
|
||||
searchData.searchOption,
|
||||
searchData.data,
|
||||
searchData.logOption,
|
||||
searchData.startDate && new Date(searchData.startDate).toISOString(),
|
||||
searchData.endDate && new Date(searchData.endDate).toISOString(),
|
||||
orderBy,
|
||||
size,
|
||||
1,
|
||||
);
|
||||
};
|
||||
|
||||
const fetchData = async (searchType, searchKey, historyType, startDt, endDt, order, size) => {
|
||||
const token = sessionStorage.getItem('token');
|
||||
setDataList(await LogViewList(token, searchType, searchKey, historyType, startDt, endDt, order ? order : orderBy, size ? size : pageSize, currentPage));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchData(
|
||||
searchData.searchOption,
|
||||
searchData.data,
|
||||
searchData.logOption,
|
||||
searchData.startDate && new Date(searchData.startDate).toISOString(),
|
||||
searchData.endDate && new Date(searchData.endDate).toISOString(),
|
||||
orderBy,
|
||||
pageSize,
|
||||
);
|
||||
}, [currentPage]);
|
||||
|
||||
const handleSearch = (searchType, searchKey, historyType, startDt, endDt) => {
|
||||
fetchData(searchType, searchKey, historyType, startDt, endDt);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{userInfo.auth_list && !userInfo.auth_list.some(auth => auth.id === 5) ? (
|
||||
<Modal min="440px" $padding="40px" $bgcolor="transparent" $view={'view'}>
|
||||
<BtnWrapper $justify="flex-end">
|
||||
<ButtonClose onClick={() => navigate(-1)} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">
|
||||
해당 메뉴에 대한 조회 권한이 없습니다.
|
||||
<br />
|
||||
권한 등급을 변경 후 다시 이용해주세요.
|
||||
</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="확인" theme="primary" type="submit" size="large" width="100%" handleClick={() => navigate(-1)} />
|
||||
</BtnWrapper>
|
||||
</Modal>
|
||||
) : (
|
||||
<>
|
||||
<Title>사용 이력 조회</Title>
|
||||
<FormWrapper action="" $flow="row">
|
||||
<LogViewSearchBar handleSearch={handleSearch} resultData={setSearchData} />
|
||||
</FormWrapper>
|
||||
<TableInfo>
|
||||
<ListCount>
|
||||
총 : {dataList && dataList.total} 건 / {dataList && dataList.total_all} 건
|
||||
</ListCount>
|
||||
<ListOption>
|
||||
<SelectInput className="input-select" onChange={e => handleOrderBy(e)}>
|
||||
<option value="DESC">최신일자</option>
|
||||
<option value="ASC">오래된순</option>
|
||||
</SelectInput>
|
||||
<SelectInput className="input-select" onChange={e => handlePageSize(e)}>
|
||||
<option value="50">50개</option>
|
||||
<option value="100">100개</option>
|
||||
</SelectInput>
|
||||
</ListOption>
|
||||
</TableInfo>
|
||||
<TableStyle>
|
||||
<caption></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="200">일시</th>
|
||||
<th width="200">이름</th>
|
||||
<th width="50%">ID</th>
|
||||
<th width="30%">사용 이력</th>
|
||||
{/* <th width="25%">상세 이력</th> */}
|
||||
<th width="150">상세 보기</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{dataList.list &&
|
||||
dataList.list.map((history, index) => (
|
||||
<Fragment key={index}>
|
||||
<tr>
|
||||
<td>{convertKTC(history.create_dt)}</td>
|
||||
<td>{history.name}</td>
|
||||
<td>{history.mail}</td>
|
||||
<td>{logOption.map(data => data.value === history.history_type && data.name)}</td>
|
||||
<td>
|
||||
<Button theme="line" text="JSON INFO" handleClick={() => handleButtonClick(history.content)} />
|
||||
</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</TableStyle>
|
||||
<Pagination postsPerPage={pageSize} totalPosts={dataList && dataList.total_all} setCurrentPage={setCurrentPage} currentPage={currentPage} pageLimit={10} />
|
||||
|
||||
<LogViewModal stateModal={stateModal} handleModal={handleModal} data={detailData} />
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default LogView;
|
||||
6
src/pages/UserManage/index.js
Normal file
6
src/pages/UserManage/index.js
Normal file
@@ -0,0 +1,6 @@
|
||||
export { default as AdminView } from './AdminView';
|
||||
export { default as LogView } from './LogView';
|
||||
export { default as AuthSetting } from './AuthSetting';
|
||||
export { default as AuthSettingUpdate } from './AuthSettingUpdate';
|
||||
export { default as CaliumRequest} from './CaliumRequest';
|
||||
export { default as CaliumRequestRegist} from '../../components/UserManage/CaliumRequestRegistModal';
|
||||
44
src/pages/ValidationTest/Button.js
Normal file
44
src/pages/ValidationTest/Button.js
Normal file
@@ -0,0 +1,44 @@
|
||||
import React from 'react';
|
||||
|
||||
import { styled } from 'styled-components';
|
||||
|
||||
const Button = (props) => {
|
||||
const {
|
||||
isActive,
|
||||
isDisabled,
|
||||
backColor,
|
||||
color,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Block
|
||||
active={isActive}
|
||||
disabled={isDisabled}
|
||||
backColor={backColor}
|
||||
color={color}
|
||||
>확인</Block>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Button;
|
||||
|
||||
const Block = styled.button `
|
||||
width: 130px;
|
||||
padding: 13px;
|
||||
font-size: 13px;
|
||||
border: none;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
|
||||
color: ${({color})=> color};
|
||||
background-color: ${(props) => props.backColor};
|
||||
`;
|
||||
|
||||
// 확인 버튼 불 들어왔을 때
|
||||
// const Block = styled.button `
|
||||
// color: #E1E3ED;
|
||||
// background-color: #00A6B5;
|
||||
// `;
|
||||
35
src/pages/ValidationTest/Input.js
Normal file
35
src/pages/ValidationTest/Input.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import React from 'react';
|
||||
|
||||
import { styled } from 'styled-components';
|
||||
|
||||
const Input = ({ placeholder, inputPw, inputType, register,id }) => {
|
||||
return (
|
||||
<Wrap>
|
||||
<InputBox
|
||||
placeholder={placeholder}
|
||||
pw={inputPw}
|
||||
type="password"
|
||||
id={id}
|
||||
{...register(id)}
|
||||
/>
|
||||
</Wrap>
|
||||
);
|
||||
};
|
||||
|
||||
export default Input;
|
||||
|
||||
const Wrap = styled.div`
|
||||
& input:focus {
|
||||
border-color: #00626B;
|
||||
outline: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const InputBox = styled.input`
|
||||
height: 45px;
|
||||
width: 300px;
|
||||
border: 1px solid #E1E3ED;
|
||||
padding-left: 20px;
|
||||
color: #2C2C2C;
|
||||
font-size: 16px;
|
||||
`;
|
||||
28
src/pages/ValidationTest/Validation.js
Normal file
28
src/pages/ValidationTest/Validation.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import * as Yup from 'yup';
|
||||
|
||||
export const SignUpValidationSchema = Yup.object({
|
||||
email: Yup.string()
|
||||
.matches(/^[^@\s]+@[^@\s]+\.[^@\s]+$/, '이메일 형식에 맞지 않습니다.')
|
||||
.required('이메일을 입력해주세요.'),
|
||||
password: Yup.string()
|
||||
.matches(
|
||||
/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{6,10}$/,
|
||||
'6~10자의 영문, 숫자를 조합해서 입력하세요.',
|
||||
)
|
||||
.min(6, '6글자 이상 10글자 이하로 입력해주세요.')
|
||||
.max(10, '6글자 이상 10글자 이하로 입력해주세요.')
|
||||
.required('비밀번호를 입력해주세요.'),
|
||||
passwordConfirm: Yup.string()
|
||||
.oneOf([Yup.ref('password'), null], '비밀번호가 다릅니다.')
|
||||
.required('비밀번호를 한번 더 입력해주세요.'),
|
||||
phone: Yup.string()
|
||||
.matches(/^[0-9]{11}$/i, '번호는 01012345678형태로 입력해주세요')
|
||||
.required('휴대폰 번호를 입력해주세요'),
|
||||
name: Yup.string()
|
||||
.matches(/^[가-힣]{2,5}$/, '한글로 입력해주세요.')
|
||||
.min(2, '2글자 이상 5글자 이하로 입력해주세요')
|
||||
.max(4, '2글자 이상 5글자 이하로 입력해주세요')
|
||||
.required('이름을 입력해주세요.'),
|
||||
code: Yup.string().length(6, '코드의 길이가 다릅니다.').required('인증코드를 입력해주세요.'),
|
||||
privacy: Yup.boolean().oneOf([true], '회원가입을 위해 약관에 동의해주세요.'),
|
||||
});
|
||||
111
src/pages/ValidationTest/main.js
Normal file
111
src/pages/ValidationTest/main.js
Normal file
@@ -0,0 +1,111 @@
|
||||
import React from 'react';
|
||||
import Input from './Input';
|
||||
import Button from './Button';
|
||||
|
||||
import { styled } from 'styled-components';
|
||||
import { useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import Validation from './Validation';
|
||||
|
||||
const Regist = () => {
|
||||
const {
|
||||
register,
|
||||
setValue,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
watch,
|
||||
} = useForm({
|
||||
resolver: yupResolver(validation),
|
||||
});
|
||||
|
||||
const values = watch();
|
||||
|
||||
return (
|
||||
<>
|
||||
<form>
|
||||
<Wrap>
|
||||
<Title>비밀번호 재설정</Title>
|
||||
|
||||
<InputArea>
|
||||
<InputBlock>
|
||||
<InputTitle>비밀번호</InputTitle>
|
||||
<Input
|
||||
id="pw1"
|
||||
// onChange={e=> onChangePW(e)}
|
||||
|
||||
register={register}
|
||||
/>
|
||||
<InfoText>영어/숫자/특수문자만 가능합니다. (8~20자 이내로)</InfoText>
|
||||
</InputBlock>
|
||||
|
||||
<InputBlock>
|
||||
<InputTitle>비밀번호 확인</InputTitle>
|
||||
<Input
|
||||
// onChange={e=> onChangePW(e)}
|
||||
id="pw2"
|
||||
register={register}
|
||||
/>
|
||||
<ErrorText>비밀번호를 다시 확인해주세요.</ErrorText>
|
||||
</InputBlock>
|
||||
|
||||
<ButtonArea>
|
||||
<Button
|
||||
backColor={values.pw1 && values.pw2 ? '#00A6B5' : '#E1E3ED'}
|
||||
color={values.pw1 && values.pw2 ? '#E1E3ED' : '#00A6B5'}
|
||||
isDisabled={values.pw1 && values.pw2 ? false : true}
|
||||
/>
|
||||
</ButtonArea>
|
||||
</InputArea>
|
||||
</Wrap>
|
||||
</form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Regist;
|
||||
|
||||
const Wrap = styled.div`
|
||||
text-align: center;
|
||||
margin: 15%;
|
||||
`;
|
||||
|
||||
const Title = styled.h1`
|
||||
font-size: 32px;
|
||||
line-height: 40px;
|
||||
color: #00626b;
|
||||
`;
|
||||
|
||||
const InputArea = styled.div`
|
||||
display: grid;
|
||||
justify-content: center;
|
||||
`;
|
||||
|
||||
const InputTitle = styled.p`
|
||||
font-size: 16px;
|
||||
`;
|
||||
|
||||
const InputBlock = styled.div`
|
||||
width: 320px;
|
||||
font-size: 16px;
|
||||
text-align: left;
|
||||
`;
|
||||
|
||||
const InfoText = styled.p`
|
||||
margin-left: 10px;
|
||||
font-size: 13px;
|
||||
text-align: left;
|
||||
color: #818181;
|
||||
`;
|
||||
|
||||
const ErrorText = styled.p`
|
||||
margin-left: 10px;
|
||||
font-size: 13px;
|
||||
text-align: left;
|
||||
color: #fe565e;
|
||||
`;
|
||||
|
||||
const ButtonArea = styled.div`
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
margin-top: 20px;
|
||||
`;
|
||||
Reference in New Issue
Block a user