diff --git a/src/apis/Users.js b/src/apis/Users.js
index 213c24a..39a11fc 100644
--- a/src/apis/Users.js
+++ b/src/apis/Users.js
@@ -201,9 +201,9 @@ export const UserFriendListView = async (token, guid) => {
};
// 우편 조회
-export const UserMailView = async (token, guid, option) => {
+export const UserMailView = async (token, params) => {
try {
- const res = await Axios.get(`/api/v1/users/mail?guid=${guid}&type=${option}`, {
+ const res = await Axios.post(`/api/v1/users/mail`, params, {
headers: { Authorization: `Bearer ${token}` },
});
diff --git a/src/assets/data/index.js b/src/assets/data/index.js
index 201cbe5..a9433ca 100644
--- a/src/assets/data/index.js
+++ b/src/assets/data/index.js
@@ -21,6 +21,11 @@ export {
languageType,
opLandCategoryType,
opLandOwnedType,
- opSuccessType
+ opSuccessType,
+ opPickupType,
+ opReadType,
+ opYNType,
+ opUserSessionType,
+ opMailType,
} from './options'
export {benItems, MinuteList, HourList, caliumRequestInitData, STATUS_STYLES, months} from './data'
\ No newline at end of file
diff --git a/src/assets/data/options.js b/src/assets/data/options.js
index 00b9c10..017f8fd 100644
--- a/src/assets/data/options.js
+++ b/src/assets/data/options.js
@@ -267,6 +267,11 @@ export const opPickupType = [
{ value: false, name: '미수령' },
];
+export const opMailType = [
+ { value: 'RECEIVE', name: '받은 우편' },
+ { value: 'SEND', name: '보낸 우편' },
+];
+
// export const logAction = [
// { value: "None", name: "ALL" },
// { value: "AIChatDeleteCharacter", name: "NPC 삭제" },
diff --git a/src/components/DataManage/UserDefaultInfo.js b/src/components/DataManage/UserDefaultInfo.js
index 34c79ae..fe6ff8b 100644
--- a/src/components/DataManage/UserDefaultInfo.js
+++ b/src/components/DataManage/UserDefaultInfo.js
@@ -18,7 +18,7 @@ import { TableSkeleton } from '../Skeleton/TableSkeleton';
import { UserInfoSkeleton } from '../Skeleton/UserInfoSkeleton';
import { opUserSessionType } from '../../assets/data/options';
import Button from '../common/button/Button';
-import { useModal } from '../../utils/hook';
+import { useModal } from '../../hooks/hook';
import { InitData } from '../../apis/Data';
const UserDefaultInfo = ({ userInfo }) => {
@@ -38,6 +38,11 @@ const UserDefaultInfo = ({ userInfo }) => {
const [dataList, setDataList] = useState({});
const [adminLevel, setAdminLevel] = useState('0');
const [loading, setLoading] = useState(true);
+ const [authDelete, setAuthDelete] = useState(false);
+
+ useEffect(() => {
+ setAuthDelete(authInfo?.auth_list?.some(auth => auth.id === authType.userSearchDelete));
+ }, [authInfo]);
useEffect(() => {
fetchData();
@@ -126,8 +131,13 @@ const UserDefaultInfo = ({ userInfo }) => {
| 접속상태 |
{dataList.user_session !== undefined && opUserSessionType.find(session => session.value === dataList.user_session)?.name}
- {
diff --git a/src/components/DataManage/UserMailInfo.js b/src/components/DataManage/UserMailInfo.js
index 524ea60..3102784 100644
--- a/src/components/DataManage/UserMailInfo.js
+++ b/src/components/DataManage/UserMailInfo.js
@@ -12,55 +12,67 @@ import CompletedModal from '../common/modal/CompletedModal';
import { useTranslation } from 'react-i18next';
import CustomConfirmModal from '../common/modal/CustomConfirmModal';
import DynamicModal from '../common/modal/DynamicModal';
-import { authType, ivenTabType } from '../../assets/data';
+import { authType, ivenTabType, opMailType } from '../../assets/data';
import { useRecoilValue } from 'recoil';
import { authList } from '../../store/authList';
import { convertKTC } from '../../utils';
import { TableSkeleton } from '../Skeleton/TableSkeleton';
-import { opPickupType, opReadType, opYNType } from '../../assets/data/options';
+import { eventSearchType, opPickupType, opReadType, opYNType } from '../../assets/data/options';
+import { useDynamoDBPagination, useModal } from '../../hooks/hook';
+import { DynamoPagination } from '../common';
const UserMailInfo = ({ userInfo }) => {
const token = sessionStorage.getItem('token');
const { t } = useTranslation();
const authInfo = useRecoilValue(authList);
- //데이터 리스트
- const [dataList, setDataList] = useState([]);
// 받은 우편, 보낸 우편
const [option, setOption] = useState('RECEIVE');
- // 상세 정보
const [detail, setDetail] = useState({ title: '', content: '', item_list: [], mail_guid: '' });
const [deleteSelected, setDeleteSelected] = useState({});
const [itemUpdateCount, setItemUpdateCount] = useState('1');
const [authDelete, setAuthDelete] = useState(false);
- const [loading, setLoading] = useState(true);
- const [modalState, setModalState] = useState({
- detailModal: 'hidden',
- deleteItemModal: 'hidden',
- deleteSubmitModal: 'hidden',
- deleteCompleteModal: 'hidden',
- deleteItemCompleteModal: 'hidden'
+ const {
+ modalState,
+ handleModalView,
+ handleModalClose
+ } = useModal({
+ detail: 'hidden',
+ deleteItem: 'hidden',
+ deleteSubmit: 'hidden',
+ deleteComplete: 'hidden',
+ deleteItemComplete: 'hidden'
});
- // 받은 우편, 보낸 우편 option 에 따른 data fetch
+ const fetchMailData = async (page, startKey) => {
+ const params = {
+ mail_type: option,
+ guid: userInfo.guid,
+ page_key: startKey
+ };
+ return await UserMailView(token, params);
+ };
+
+ const {
+ data: dataList,
+ loading,
+ pagination,
+ fetchPage,
+ goToNextPage,
+ goToPrevPage,
+ resetPagination
+ } = useDynamoDBPagination(fetchMailData);
+
useEffect(() => {
- fetchData(option);
+ resetPagination();
+ fetchPage(1);
}, [option]);
useEffect(() => {
setAuthDelete(authInfo.auth_list.some(auth => auth.id === authType.userSearchDelete));
}, [authInfo]);
- const fetchData = async option => {
- setLoading(true);
- await UserMailView(token, userInfo.guid, option).then(data =>{
- setDataList(data);
- setLoading(false);
- });
- };
-
- // 상세 모달 value 세팅
const handleDetail = (title, content, itmeList, mail_guid) => {
setDetail({ title: title, content: content, item_list: itmeList, mail_guid: mail_guid });
};
@@ -81,20 +93,6 @@ const UserMailInfo = ({ userInfo }) => {
}
};
- const handleModalView = (type) => {
- setModalState((prevState) => ({
- ...prevState,
- [`${type}Modal`]: 'view',
- }));
- }
-
- const handleModalClose = (type) => {
- setModalState((prevState) => ({
- ...prevState,
- [`${type}Modal`]: 'hidden',
- }));
- }
-
const handleModalSubmit = async (type, param = null) => {
let params;
let result;
@@ -147,7 +145,7 @@ const UserMailInfo = ({ userInfo }) => {
// if(idx >= 0) {
// dataList.mail_list.splice(idx, 1);
// }
- fetchData(option);
+ fetchPage(pagination.currentPage);
break;
case "deleteItemComplete":
handleModalClose('deleteItemComplete');
@@ -167,21 +165,28 @@ const UserMailInfo = ({ userInfo }) => {
return (
loading ? :
<>
-
+
{
setOption(e.target.value);
}}>
-
-
+ {opMailType.map((data, index) => (
+
+ ))}
-
+
+
+
+
{option === 'RECEIVE' && (
<>
- {/*
-
- */}
@@ -197,7 +202,7 @@ const UserMailInfo = ({ userInfo }) => {
- {dataList.mail_list &&
+ {dataList && dataList.mail_list &&
dataList.mail_list.map((mail, idx) => {
return (
@@ -230,9 +235,6 @@ const UserMailInfo = ({ userInfo }) => {
)}
{option === 'SEND' && (
<>
- {/*
-
- */}
@@ -244,7 +246,7 @@ const UserMailInfo = ({ userInfo }) => {
- {dataList.mail_list &&
+ {dataList && dataList.mail_list &&
dataList.mail_list.map((mail, idx) => {
return (
@@ -269,6 +271,8 @@ const UserMailInfo = ({ userInfo }) => {
>
)}
+
+
{/*상세*/}
props.disabled ? '#e0e0e0' : '#6c7eb7'};
+ color: ${props => props.disabled ? '#a0a0a0' : 'white'};
+ border: none;
+ padding: 6px 12px;
+ border-radius: 4px;
+ font-size: 12px;
+ cursor: ${props => props.disabled ? 'not-allowed' : 'pointer'};
+ transition: background-color 0.2s;
+
+ &:hover {
+ background-color: ${props => props.disabled ? '#e0e0e0' : '#5a6a9b'};
+ }
+`;
+
+const PageInfo = styled.div`
+ font-size: 12px;
+ font-weight: 500;
+ color: #666;
`;
\ No newline at end of file
diff --git a/src/components/ServiceManage/modal/BattleEventModal.js b/src/components/ServiceManage/modal/BattleEventModal.js
index 2aef89f..fb061aa 100644
--- a/src/components/ServiceManage/modal/BattleEventModal.js
+++ b/src/components/ServiceManage/modal/BattleEventModal.js
@@ -22,7 +22,7 @@ import {
import { modalTypes } from '../../../assets/data';
import { DynamicModal, Modal, SingleDatePicker, SingleTimePicker } from '../../common';
import { NONE, TYPE_MODIFY, TYPE_REGISTRY } from '../../../assets/data/adminConstants';
-import { useModal } from '../../../utils/hook';
+import { useModal } from '../../../hooks/hook';
import { convertKTCDate } from '../../../utils';
import {
battleEventHotTime,
diff --git a/src/components/ServiceManage/modal/LandAuctionModal.js b/src/components/ServiceManage/modal/LandAuctionModal.js
index c4fecc0..3678d42 100644
--- a/src/components/ServiceManage/modal/LandAuctionModal.js
+++ b/src/components/ServiceManage/modal/LandAuctionModal.js
@@ -31,7 +31,7 @@ import {
TYPE_REGISTRY,
} from '../../../assets/data/adminConstants';
import { landAuctionStatus, landAuctionStatusType, languageType, CurrencyType } from '../../../assets/data';
-import { useModal } from '../../../utils/hook';
+import { useModal } from '../../../hooks/hook';
import { convertKTCDate } from '../../../utils';
import { msToMinutes } from '../../../utils/date';
diff --git a/src/components/ServiceManage/modal/OwnerChangeModal.js b/src/components/ServiceManage/modal/OwnerChangeModal.js
index 62d971c..9427d9c 100644
--- a/src/components/ServiceManage/modal/OwnerChangeModal.js
+++ b/src/components/ServiceManage/modal/OwnerChangeModal.js
@@ -22,7 +22,7 @@ import {
import { modalTypes } from '../../../assets/data';
import { DynamicModal, Modal, SingleDatePicker, SingleTimePicker } from '../../common';
import { NONE, TYPE_MODIFY, TYPE_REGISTRY } from '../../../assets/data/adminConstants';
-import { useModal } from '../../../utils/hook';
+import { useModal } from '../../../hooks/hook';
import { convertKTCDate } from '../../../utils';
import { BattleEventModify, BattleEventSingleRegist } from '../../../apis/Battle';
import { battleEventStatusType } from '../../../assets/data/types';
@@ -144,7 +144,6 @@ const OwnerChangeModal = ({ modalType, detailView, handleDetailView, content, se
}
setLoading(true);
await UserInfoView(token, guid).then(data => {
- setLoading(false);
if(Object.keys(data).length === 0){
setAlertMsg(t('WARNING_GUID_CHECK'));
setResultData({ ...resultData, user_name: '' })
@@ -154,13 +153,14 @@ const OwnerChangeModal = ({ modalType, detailView, handleDetailView, content, se
setResultData({ ...resultData, user_name: nickname })
}).catch(reason => {
setAlertMsg(t('API_FAIL'));
+ }).finally(()=>{
+ setLoading(false);
});
break;
case "registConfirm":
setLoading(true);
if(isView()){
- console.log(resultData);
setLoading(false);
handleModalClose('registConfirm');
@@ -173,7 +173,6 @@ const OwnerChangeModal = ({ modalType, detailView, handleDetailView, content, se
}
await LandOwnerChangesDelete(token, resultData).then(data => {
- setLoading(false);
handleModalClose('registConfirm');
if(data.result === "SUCCESS") {
handleModalView('registComplete');
@@ -184,10 +183,11 @@ const OwnerChangeModal = ({ modalType, detailView, handleDetailView, content, se
}
}).catch(reason => {
setAlertMsg(t('API_FAIL'));
+ }).finally(() => {
+ setLoading(false);
});
}else{
await LandOwnedChangesRegist(token, resultData).then(data => {
- setLoading(false);
handleModalClose('registConfirm');
if(data.result === "SUCCESS") {
handleModalView('registComplete');
@@ -202,6 +202,8 @@ const OwnerChangeModal = ({ modalType, detailView, handleDetailView, content, se
}
}).catch(reason => {
setAlertMsg(t('API_FAIL'));
+ }).finally(() => {
+ setLoading(false);
});
}
diff --git a/src/components/common/Pagination/DynamoPagination.js b/src/components/common/Pagination/DynamoPagination.js
new file mode 100644
index 0000000..33737c8
--- /dev/null
+++ b/src/components/common/Pagination/DynamoPagination.js
@@ -0,0 +1,56 @@
+import React from 'react';
+import styled from 'styled-components';
+
+const DynamoPagination = ({
+ pagination,
+ onNextPage,
+ onPrevPage,
+ className
+ }) => {
+ return (
+
+
+ 이전
+
+ {pagination.currentPage}
+
+ 다음
+
+
+ );
+};
+
+const PaginationButtons = styled.div`
+ display: flex;
+ align-items: center;
+ gap: 10px;
+`;
+
+const PaginationButton = styled.button`
+ background-color: ${props => props.disabled ? '#e0e0e0' : '#6c7eb7'};
+ color: ${props => props.disabled ? '#a0a0a0' : 'white'};
+ border: none;
+ padding: 6px 12px;
+ border-radius: 4px;
+ font-size: 12px;
+ cursor: ${props => props.disabled ? 'not-allowed' : 'pointer'};
+ transition: background-color 0.2s;
+
+ &:hover {
+ background-color: ${props => props.disabled ? '#e0e0e0' : '#5a6a9b'};
+ }
+`;
+
+const PageInfo = styled.div`
+ font-size: 12px;
+ font-weight: 500;
+ color: #666;
+`;
+
+export default DynamoPagination;
\ No newline at end of file
diff --git a/src/components/common/index.js b/src/components/common/index.js
index 93450aa..8337858 100644
--- a/src/components/common/index.js
+++ b/src/components/common/index.js
@@ -11,6 +11,7 @@ import DynamicModal from './modal/DynamicModal';
import CustomConfirmModal from './modal/CustomConfirmModal';
import Modal from './modal/Modal';
import Pagination from './Pagination/Pagination';
+import DynamoPagination from './Pagination/DynamoPagination';
import ViewTableInfo from './Table/ViewTableInfo';
import Loading from './Loading';
import CDivider from './CDivider';
@@ -40,5 +41,6 @@ export { DateTimeInput,
ViewTableInfo,
Loading,
CDivider,
- TopButton
+ TopButton,
+ DynamoPagination
};
\ No newline at end of file
diff --git a/src/utils/hook.js b/src/hooks/hook.js
similarity index 74%
rename from src/utils/hook.js
rename to src/hooks/hook.js
index 55e8c45..3a61529 100644
--- a/src/utils/hook.js
+++ b/src/hooks/hook.js
@@ -188,4 +188,77 @@ export const useDataFetch = (fetchFunction, dependencies = [], initialState = nu
refetch: fetchData,
setData
};
+};
+
+export const useDynamoDBPagination = (fetchFunction) => {
+
+ const [data, setData] = useState(null);
+ const [loading, setLoading] = useState(false);
+ const [pagination, setPagination] = useState({
+ currentPage: 1,
+ pageKeys: { 1: null },
+ hasNextPage: false
+ });
+
+ const resetPagination = useCallback(() => {
+ setPagination({
+ currentPage: 1,
+ pageKeys: { 1: null },
+ hasNextPage: false
+ });
+ }, []);
+
+ const fetchPage = useCallback(async (page) => {
+ setLoading(true);
+ try {
+ const startKey = pagination.pageKeys[page];
+ const response = await fetchFunction(page, startKey);
+
+ setData(response);
+
+ const updatedPagination = { ...pagination, currentPage: page };
+
+ if (response.pageKey) {
+ updatedPagination.pageKeys[page + 1] = response.pageKey;
+ updatedPagination.hasNextPage = true;
+ } else {
+ updatedPagination.hasNextPage = false;
+ }
+
+ setPagination(updatedPagination);
+ return response;
+ } catch (error) {
+ console.error('페이지 데이터 가져오기 오류:', error);
+ throw error;
+ } finally {
+ setLoading(false);
+ }
+ }, [fetchFunction, pagination]);
+
+ const goToNextPage = useCallback(() => {
+ if (!pagination.hasNextPage) return;
+
+ const nextPage = pagination.currentPage + 1;
+ return fetchPage(nextPage);
+ }, [pagination, fetchPage]);
+
+ const goToPrevPage = useCallback(() => {
+ if (pagination.currentPage <= 1) return;
+
+ const prevPage = pagination.currentPage - 1;
+ return fetchPage(prevPage);
+ }, [pagination, fetchPage]);
+
+ return {
+ data,
+ loading,
+ pagination,
+
+ setData,
+ setPagination,
+ fetchPage,
+ goToNextPage,
+ goToPrevPage,
+ resetPagination
+ };
};
\ No newline at end of file
diff --git a/src/hooks/hooks.js b/src/hooks/hooks.js
deleted file mode 100644
index e42f918..0000000
--- a/src/hooks/hooks.js
+++ /dev/null
@@ -1 +0,0 @@
-// 공통으로 사용될 함수를 관리하는 폴더입니다. 이 파일은 삭제하셔도 됩니다.
\ No newline at end of file
diff --git a/src/pages/DataManage/BusinessLogView.js b/src/pages/DataManage/BusinessLogView.js
index 6c0c112..d3e7edf 100644
--- a/src/pages/DataManage/BusinessLogView.js
+++ b/src/pages/DataManage/BusinessLogView.js
@@ -13,7 +13,7 @@ import {
DetailTableInfo,
} from '../../styles/Components';
-import { withAuth } from '../../utils/hook';
+import { withAuth } from '../../hooks/hook';
import {
authType,
modalTypes,
diff --git a/src/pages/DataManage/LandInfoView.js b/src/pages/DataManage/LandInfoView.js
index 5f717ad..284f3cd 100644
--- a/src/pages/DataManage/LandInfoView.js
+++ b/src/pages/DataManage/LandInfoView.js
@@ -14,7 +14,7 @@ import Button from '../../components/common/button/Button';
import { useNavigate } from 'react-router-dom';
import { authList } from '../../store/authList';
import { useRecoilValue } from 'recoil';
-import { useDataFetch, useModal, useTable, withAuth } from '../../utils/hook';
+import { useDataFetch, useModal, useTable, withAuth } from '../../hooks/hook';
import {
authType,
landSize,
diff --git a/src/pages/ServiceManage/BattleEvent.js b/src/pages/ServiceManage/BattleEvent.js
index 2cd9843..c3f158a 100644
--- a/src/pages/ServiceManage/BattleEvent.js
+++ b/src/pages/ServiceManage/BattleEvent.js
@@ -31,7 +31,7 @@ import {
import { convertKTC, convertKTCDate, convertUTC, timeDiffMinute } from '../../utils';
import { BattleEventModal } from '../../components/ServiceManage';
import { INITIAL_PAGE_SIZE, INITIAL_PAGE_LIMIT } from '../../assets/data/adminConstants';
-import { useDataFetch, useModal, useTable, withAuth } from '../../utils/hook';
+import { useDataFetch, useModal, useTable, withAuth } from '../../hooks/hook';
import { StatusWapper, StatusLabel } from '../../styles/ModuleComponents';
import { battleEventStatus, battleRepeatType } from '../../assets/data/options';
import BattleEventSearchBar, {
diff --git a/src/pages/ServiceManage/LandAuction.js b/src/pages/ServiceManage/LandAuction.js
index 5fb8fd1..c147d4e 100644
--- a/src/pages/ServiceManage/LandAuction.js
+++ b/src/pages/ServiceManage/LandAuction.js
@@ -29,7 +29,7 @@ import {
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 { useDataFetch, useModal, useTable, withAuth } from '../../hooks/hook';
import { useLandAuctionSearch } from '../../components/ServiceManage/searchBar/LandAuctionSearchBar';
import { StatusWapper, ChargeBtn, StatusLabel } from '../../styles/ModuleComponents';
diff --git a/src/pages/ServiceManage/MailRegist.js b/src/pages/ServiceManage/MailRegist.js
index 5da6b00..3d0820d 100644
--- a/src/pages/ServiceManage/MailRegist.js
+++ b/src/pages/ServiceManage/MailRegist.js
@@ -24,7 +24,7 @@ import { useTranslation } from 'react-i18next';
import { MailReceiver, RegistInputRow } from '../../styles/ModuleComponents';
import AuthModal from '../../components/common/modal/AuthModal';
import { authType } from '../../assets/data';
-import { useDataFetch } from '../../utils/hook';
+import { useDataFetch } from '../../hooks/hook';
import { BattleConfigView } from '../../apis/Battle';
import { currencyCodeTypes } from '../../assets/data/types';
import { DynamicModal } from '../../components/common';
diff --git a/src/pages/UserManage/CaliumRequest.js b/src/pages/UserManage/CaliumRequest.js
index bb3f97e..5dcff5d 100644
--- a/src/pages/UserManage/CaliumRequest.js
+++ b/src/pages/UserManage/CaliumRequest.js
@@ -21,7 +21,7 @@ import {Button, ExcelDownButton, Pagination, DynamicModal, ViewTableInfo, Loadin
import { convertKTC, truncateText } from '../../utils';
import { CaliumRequestRegistModal, CaliumRequestSearchBar } from '../../components/UserManage';
import { CaliumCharge, CaliumRequestView } from '../../apis';
-import { withAuth } from '../../utils/hook';
+import { withAuth } from '../../hooks/hook';
import { convertEndDateToISO, convertStartDateToISO } from '../../utils/date';
const CaliumRequest = () => {
diff --git a/src/pages/UserManage/DataInitView.js b/src/pages/UserManage/DataInitView.js
index 82ce717..253afd5 100644
--- a/src/pages/UserManage/DataInitView.js
+++ b/src/pages/UserManage/DataInitView.js
@@ -23,7 +23,7 @@ import {
FormRowGroup, MessageWrapper,
} from '../../styles/ModuleComponents';
import { authType } from '../../assets/data';
-import { useModal, withAuth } from '../../utils/hook';
+import { useModal, withAuth } from '../../hooks/hook';
import { DynamicModal, TopButton } from '../../components/common';
import { opInitDataType, opSuccessType } from '../../assets/data/options';
import { InitData } from '../../apis/Data';