Files
nice-app-web/src/pages/transaction/all-transaction/list-page.tsx
focp212@naver.com 1fcbc35aab 달력 관련 수정
2025-11-07 12:36:58 +09:00

383 lines
13 KiB
TypeScript

import moment from 'moment';
import { useStore } from '@/shared/model/store';
import { ChangeEvent, useEffect, useState } from 'react';
import { IMAGE_ROOT } from '@/shared/constants/common';
import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { AllTransactionList } from '@/entities/transaction/ui/all-transaction-list';
import {
TransactionCategory,
AllTransactionSearchCl,
AllTransactionListParams,
ListItemProps,
AllTransactionListSummaryParams,
AllTransactionListResponse,
AllTransactionListSummaryResponse,
DetailData
} from '@/entities/transaction/model/types';
import { useAllTransactionListMutation } from '@/entities/transaction/api/use-all-transaction-list-mutation';
import { useAllTransactionListSummaryMutation } from '@/entities/transaction/api/use-all-transaction-list-summary-mutation';
import { useDownloadExcelMutation } from '@/entities/transaction/api/use-download-excel-mutation';
import { DEFAULT_PAGE_PARAM } from '@/entities/common/model/constant';
import { AllTransactionFilter } from '@/entities/transaction/ui/filter/all-transaction-filter';
import { SortTypeBox } from '@/entities/common/ui/sort-type-box';
import { SortTypeKeys, HeaderType, DefaultRequestPagination } from '@/entities/common/model/types';
import {
useSetOnBack,
useSetHeaderTitle,
useSetHeaderType,
useSetFooterMode
} from '@/widgets/sub-layout/use-sub-layout';
import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet';
import useIntersectionObserver from '@/widgets/intersection-observer';
import { useTranslation } from 'react-i18next';
import { AllTransactionDetail } from '@/entities/transaction/ui/detail/all-transaction-detail';
import { showAlert } from '@/widgets/show-alert';
import { snackBar } from '@/shared/lib';
import { checkGrant } from '@/shared/lib/check-grant';
/* 거래내역조회 31 */
const menuId = 31;
export const AllTransactionListPage = () => {
const { navigate } = useNavigate();
const { t, i18n } = useTranslation();
const userMid = useStore.getState().UserStore.mid;
const [serviceCodeOptions, setServiceCodeOptions] = useState<Array<Record<string, any>>>();
const [onActionIntersect, setOnActionIntersect] = useState<boolean>(false);
const [sortType, setSortType] = useState<SortTypeKeys>(SortTypeKeys.LATEST);
const [listItems, setListItems] = useState<Array<ListItemProps>>([]);
const [filterOn, setFilterOn] = useState<boolean>(false);
const [pageParam, setPageParam] = useState<DefaultRequestPagination>(DEFAULT_PAGE_PARAM);
const [mid, setMid] = useState<string>(userMid);
const [moid, setMoid] = useState<string>('');
const [tid, setTid] = useState<string>('');
const [dateCl, setDateCl] = useState<string>('');
const [goodsName, setGoodsName] = useState<string>('');
const [fromDate, setFromDate] = useState(moment().format('YYYYMMDD'));
const [toDate, setToDate] = useState(moment().format('YYYYMMDD'));
const [statusCode, setStatusCode] = useState<string>('');
const [serviceCode, setServiceCode] = useState<string>('01');
const [minAmount, setMinAmount] = useState<number>();
const [maxAmount, setMaxAmount] = useState<number>();
const [cardCode, setCardCode] = useState<string | undefined>();
const [bankCode, setBankCode] = useState<string | undefined>();
const [searchCl, setSearchCl] = useState<AllTransactionSearchCl | undefined>();
const [searchValue, setSearchValue] = useState<string | undefined>();
const [totalCount, setTotalCount] = useState<number>(0);
const [totalAmount, setTotalAmount] = useState<number>(0);
const [emailBottomSheetOn, setEmailBottomSheetOn] = useState<boolean>(false);
const [detailOn, setDetailOn] = useState<boolean>(false);
const [detailTid, setDetailTid] = useState<string>('');
const [detailServiceCode, setDetailServiceCode] = useState<string>('');
useSetHeaderTitle(t('transaction.listTitle'));
useSetHeaderType(HeaderType.LeftArrow);
useSetOnBack(() => {
navigate(PATHS.home);
});
useSetFooterMode(false);
const { mutateAsync: allTransactionList } = useAllTransactionListMutation();
const { mutateAsync: allTransactionListSummary } = useAllTransactionListSummaryMutation();
const { mutateAsync: downloadExcel } = useDownloadExcelMutation();
const onIntersect: IntersectionObserverCallback = (entries: Array<IntersectionObserverEntry>) => {
entries.forEach((entry: IntersectionObserverEntry) => {
if(entry.isIntersecting){
if(onActionIntersect && !!pageParam.cursor){
setOnActionIntersect(false);
callList('page');
}
}
});
};
const { setTarget } = useIntersectionObserver({
threshold: 1,
onIntersect
});
const callList = (type?: string) => {
setOnActionIntersect(false);
let listSummaryParams: AllTransactionListSummaryParams = {
mid: mid,
moid: moid,
tid: tid,
fromDate: fromDate,
toDate: toDate,
statusCode: statusCode,
serviceCode: serviceCode,
minAmount: minAmount,
maxAmount: maxAmount,
dateCl: dateCl,
goodsName: goodsName,
cardCode: cardCode,
bankCode: bankCode,
searchCl: searchCl,
searchValue: searchValue,
sortType: sortType
};
let listParams: AllTransactionListParams = {
...listSummaryParams,
...{
page: {
...pageParam,
...{ sortType: sortType }
}
}
};
if(type !== 'page' && listParams.page){
listParams.page.cursor = null;
}
allTransactionList(listParams).then((rs: AllTransactionListResponse) => {
if(type === 'page'){
setListItems([
...listItems,
...rs.content
]);
}
else{
setListItems(rs.content);
}
if(rs.hasNext
&& rs.nextCursor !== pageParam.cursor
&& rs.content.length === DEFAULT_PAGE_PARAM.size
){
setPageParam({
...pageParam,
...{ cursor: rs.nextCursor }
});
}
else{
setPageParam({
...pageParam,
...{ cursor: null }
});
}
setOnActionIntersect(
!!rs.hasNext
&& rs.nextCursor !== pageParam.cursor
&& rs.content.length === DEFAULT_PAGE_PARAM.size
);
}).catch((e: any) => {
if(e.response?.data?.error?.message){
showAlert(e.response?.data?.error?.message);
return;
}
});
allTransactionListSummary(listSummaryParams).then((rs: AllTransactionListSummaryResponse) => {
setTotalAmount(rs.totalAmount);
setTotalCount(rs.totalCount);
}).catch((e: any) => {
if(e.response?.data?.error?.message){
showAlert(e.response?.data?.error?.message);
return;
}
});
};
const onClickToOpenFilter = () => {
setFilterOn(!filterOn);
};
const onClickToDownloadExcel = () => {
if(checkGrant(menuId, 'D')){
setEmailBottomSheetOn(true);
}
else{
showAlert(t('common.nopermission'));
}
};
const onRequestDownloadExcel = (userEmail?: string) => {
};
const onClickToSort = (sort: SortTypeKeys) => {
setSortType(sort);
};
const callServiceCodeOptions = () => {
let serviceCodes = useStore.getState().CommonStore.serviceCodes;
setServiceCodeOptions(serviceCodes);
setServiceCode(serviceCodes[0].value);
};
const onChangeServiceCode = (e: ChangeEvent<HTMLSelectElement>) => {
let val = e.target.value;
// onchagne 에서 useState가 즉시 반영 안되므로 값을 직접 바로 넘긴다.
setServiceCode(val);
};
const getServiceCodeOptions = () => {
let rs = [];
if(!!serviceCodeOptions && serviceCodeOptions.length > 0)
for(let i=0;i<serviceCodeOptions.length;i++){
const option = serviceCodeOptions[i];
const localizedName = getLocalizedServiceCodeName(option?.name);
rs.push(
<option
key={`key-${i}`}
value={option?.value}
>{ localizedName }</option>
)
}
return rs;
};
const setDetailData = (detailData: DetailData) => {
setDetailOn(detailData.detailOn);
setDetailTid(detailData.tid);
if(detailData?.serviceCode){
setDetailServiceCode(detailData?.serviceCode);
}
};
const getLocalizedServiceCodeName = (name?: string): string => {
if (!name) return '';
const nameMap: Record<string, string> = {
'전체': t('transaction.constants.all'),
'신용카드': t('transaction.constants.creditCard'),
'계좌이체': t('transaction.constants.accountTransfer'),
'가상계좌': t('transaction.constants.virtualAccount'),
'휴대폰': t('transaction.constants.mobilePayment'),
'문화상품권': t('transaction.constants.cultureLand'),
'(구)SSG머니': t('transaction.constants.ssgMoney'),
'SSG은행계좌결제': t('transaction.constants.ssgBank'),
'계좌간편결제': t('transaction.constants.accountSimpleTransfer'),
'티머니페이': t('transaction.constants.tmoneyPay'),
};
return nameMap[name] || name;
};
useEffect(() => {
callServiceCodeOptions();
}, []);
useEffect(() => {
callList();
}, [
mid, moid, tid, sortType,
fromDate, toDate,
statusCode, serviceCode,
minAmount, maxAmount,
bankCode, cardCode,
searchCl, searchValue
]);
return (
<>
<main>
<div className="tab-content">
<div className="tab-pane sub active">
<div className="summary-section">
<div className="summary-label">{t('transaction.searchAmount')}</div>
<div className="summary-amount">
<span className="amount-text">
{t('home.money', { value: new Intl.NumberFormat('en-US').format(totalAmount || 0) })}
</span>
<div className="summary-actions">
<button className="filter-btn">
<img
src={ IMAGE_ROOT + '/ico_setting.svg' }
alt={t('transaction.searchOptions')}
onClick={ () => onClickToOpenFilter() }
/>
</button>
<button className="download-btn">
<img
src={ IMAGE_ROOT + '/ico_download.svg' }
alt={t('transaction.download')}
onClick={ () => onClickToDownloadExcel() }
/>
</button>
</div>
</div>
<div className="summary-details">
<div className="detail-item">
<span className="detail-label">{t('transaction.searchDate')}</span>
<span className="detail-value">{ moment(fromDate).format('YYYY.MM.DD') } ~ { moment(toDate).format('YYYY.MM.DD') }</span>
</div>
<div className="detail-item">
<span className="detail-label">{t('transaction.transactionCount')}</span>
<span className="detail-value">
{t('transaction.total')} {t('home.count', { value: new Intl.NumberFormat('en-US').format(totalCount || 0) })}
</span>
</div>
</div>
</div>
<div className="filter-section">
<SortTypeBox
sortType={ sortType }
onClickToSort={ onClickToSort }
></SortTypeBox>
<select
value={ serviceCode }
onChange={ (e) => onChangeServiceCode(e) }>
{ getServiceCodeOptions() }
</select>
</div>
<AllTransactionList
listItems={ listItems }
transactionCategory={ TransactionCategory.AllTransaction }
setDetailData={ setDetailData }
></AllTransactionList>
<div ref={ setTarget }></div>
</div>
</div>
</main>
<AllTransactionFilter
filterOn={ filterOn }
setFilterOn={ setFilterOn }
mid={ mid }
fromDate={ fromDate }
toDate={ toDate }
statusCode={ statusCode }
serviceCode={ serviceCode }
minAmount={ minAmount }
maxAmount={ maxAmount }
cardCode={ cardCode }
bankCode={ bankCode }
searchCl={ searchCl }
searchValue={ searchValue }
setMid={ setMid }
setMoid={ setMoid }
setTid={ setTid }
setFromDate={ setFromDate }
setToDate={ setToDate }
setStatusCode={ setStatusCode }
setServiceCode={ setServiceCode }
setMinAmount={ setMinAmount }
setMaxAmount={ setMaxAmount }
setCardCode={ setCardCode }
setBankCode={ setBankCode }
setSearchCl={ setSearchCl }
setSearchValue={ setSearchValue }
serviceCodeOptions={ serviceCodeOptions }
></AllTransactionFilter>
<AllTransactionDetail
detailOn={ detailOn }
setDetailOn={ setDetailOn }
tid={ detailTid }
serviceCode={ detailServiceCode }
></AllTransactionDetail>
{ !!emailBottomSheetOn &&
<EmailBottomSheet
bottomSheetOn={ emailBottomSheetOn }
setBottomSheetOn={ setEmailBottomSheetOn }
imageSave={ false }
sendEmail={ true }
sendRequest={ onRequestDownloadExcel }
></EmailBottomSheet>
}
</>
);
};