From 75d5837707ceb12055a63157dbcf51c49fccac0a Mon Sep 17 00:00:00 2001 From: HyeonJongKim Date: Tue, 4 Nov 2025 11:04:25 +0900 Subject: [PATCH] Refactor additional service filters and update related pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move filter components to separate ars/filter and payout directories - Update additional service types and list item component - Modify page routes and path constants πŸ€– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../additional-service/model/payout/types.ts | 12 +- .../ui/{ => ars}/filter/ars-filter.tsx | 4 +- .../additional-service/ui/list-item.tsx | 14 +- .../ui/payout/detail/payout-detail.tsx | 208 ++++++++++++++++++ .../ui/{ => payout}/filter/payout-filter.tsx | 4 +- .../ui/payout/payout-list.tsx | 69 ++++++ .../additional-service-pages.tsx | 2 - .../additional-service/ars/list-page.tsx | 2 +- .../additional-service/payout/list-page.tsx | 76 +++++-- src/shared/constants/paths.ts | 4 - src/shared/constants/route-names.ts | 1 - 11 files changed, 351 insertions(+), 45 deletions(-) rename src/entities/additional-service/ui/{ => ars}/filter/ars-filter.tsx (98%) create mode 100644 src/entities/additional-service/ui/payout/detail/payout-detail.tsx rename src/entities/additional-service/ui/{ => payout}/filter/payout-filter.tsx (98%) create mode 100644 src/entities/additional-service/ui/payout/payout-list.tsx diff --git a/src/entities/additional-service/model/payout/types.ts b/src/entities/additional-service/model/payout/types.ts index 5c377a6..13607ee 100644 --- a/src/entities/additional-service/model/payout/types.ts +++ b/src/entities/additional-service/model/payout/types.ts @@ -1,5 +1,5 @@ import { DefaulResponsePagination, DefaultRequestPagination } from '@/entities/common/model/types'; -import { ListItemProps } from '../types'; +import { AdditionalServiceCategory, DetailData, ListItemProps } from '../types'; export enum PayoutSearchDateType { @@ -13,6 +13,14 @@ export enum PayoutDisbursementStatus { FAIL = 'FAIL', }; +export interface PayoutListProps { + additionalServiceCategory: AdditionalServiceCategory; + listItems: Array; + searchDateType: PayoutSearchDateType + mid: string; + setDetailData: (detailData: DetailData) => void; +} + export interface PayoutListItem { tid?: string; submallId?: string; @@ -31,7 +39,7 @@ export interface ExtensionPayoutRequestParams { }; export interface ExtensionPayoutRequestResponse { status: boolean; - + error?: { message?: string } diff --git a/src/entities/additional-service/ui/filter/ars-filter.tsx b/src/entities/additional-service/ui/ars/filter/ars-filter.tsx similarity index 98% rename from src/entities/additional-service/ui/filter/ars-filter.tsx rename to src/entities/additional-service/ui/ars/filter/ars-filter.tsx index 2fc15ec..233bba6 100644 --- a/src/entities/additional-service/ui/filter/ars-filter.tsx +++ b/src/entities/additional-service/ui/ars/filter/ars-filter.tsx @@ -13,8 +13,8 @@ import { } from '@/entities/common/model/constant'; import moment from 'moment'; import { FilterInput } from '@/shared/ui/filter/input'; -import { OrderStatus, PaymentStatus } from '../../model/ars/types'; -import { getArsOrderStatusBtnGroup, getArsPaymentStatusBtnGroup } from '../../model/ars/constant'; +import { OrderStatus, PaymentStatus } from '../../../model/ars/types'; +import { getArsOrderStatusBtnGroup, getArsPaymentStatusBtnGroup } from '../../../model/ars/constant'; import { useStore } from '@/shared/model/store'; import { FilterSelectMid } from '@/shared/ui/filter/select-mid'; import { FullMenuClose } from '@/entities/common/ui/full-menu-close'; diff --git a/src/entities/additional-service/ui/list-item.tsx b/src/entities/additional-service/ui/list-item.tsx index 58ea914..dbb36d5 100644 --- a/src/entities/additional-service/ui/list-item.tsx +++ b/src/entities/additional-service/ui/list-item.tsx @@ -161,7 +161,7 @@ export const ListItem = ({ } //μ΄ν•˜ μƒμ„ΈνŽ˜μ΄μ§€ 쑴재 else if (additionalServiceCategory === AdditionalServiceCategory.AccountHolderAuth) { - if(setDetailData && !!mid && !!tid){ + if (setDetailData && !!mid && !!tid) { setDetailData({ mid: mid, tid: tid, @@ -220,13 +220,13 @@ export const ListItem = ({ } else if (additionalServiceCategory === AdditionalServiceCategory.Payout) { - navigate(PATHS.additionalService.payout.detail, { - state: { - additionalServiceCategory: additionalServiceCategory, + if (setDetailData && !!mid && !!tid) { + setDetailData({ mid: mid, - tid: tid - } - }); + tid: tid, + detailOn: true + }); + } } else if (additionalServiceCategory === AdditionalServiceCategory.Ars) { if (setDetailData && !!mid && !!tid) { diff --git a/src/entities/additional-service/ui/payout/detail/payout-detail.tsx b/src/entities/additional-service/ui/payout/detail/payout-detail.tsx new file mode 100644 index 0000000..bea79fa --- /dev/null +++ b/src/entities/additional-service/ui/payout/detail/payout-detail.tsx @@ -0,0 +1,208 @@ +import moment from 'moment'; +import { motion } from 'framer-motion'; +import { ExtensionPayoutDetailDownloadCertificateParams, ExtensionPayoutDetailDownloadCertificateResponse, ExtensionPayoutDetailParams, ExtensionPayoutDetailResponse } from "@/entities/additional-service/model/payout/types"; +import { useTranslation } from "react-i18next"; +import { useEffect, useState } from 'react'; +import { useExtensionPayoutDetailMutation } from '@/entities/additional-service/api/payout/use-extension-payout-detail-mutation'; +import { useExtensionPayoutDetailDownloadCertificateMutation } from '@/entities/additional-service/api/payout/use-extension-payout-detail-download-cetificate-mutation'; +import { DetailMotionDuration, DetailMotionStyle, DetailMotionVariants } from '@/entities/common/model/constant'; +import { FullMenuClose } from '@/entities/common/ui/full-menu-close'; +import { DownloadTypeBottomSheet } from '@/entities/common/ui/download-type-bottom-sheet'; +import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet'; + + +export interface PayoutDetailProps { + detailOn: boolean; + setDetailOn: (detailOn: boolean) => void; + mid: string; + tid: string; +}; + +export const PayoutDetail = ({ + detailOn, + setDetailOn, + mid, + tid +}: PayoutDetailProps) => { + const { t } = useTranslation(); + + const [detail, setDetail] = useState(); + const [downloadTypeBottomSheetOn, setDownloadTypeBottomSheetOn] = useState(false); + const [emailBottomSheetOn, setEmailBottomSheetOn] = useState(false); + + const { mutateAsync: extensionPayoutDetail } = useExtensionPayoutDetailMutation(); + const { mutateAsync: extensionPayoutDetailDownloadCertification } = useExtensionPayoutDetailDownloadCertificateMutation(); + + + const callDetail = () => { + let params: ExtensionPayoutDetailParams = { + tid: tid, + mid: mid, + }; + + extensionPayoutDetail(params).then((rs: ExtensionPayoutDetailResponse) => { + setDetail(rs); + }); + } + + const onClickToDownload = () => { + setDownloadTypeBottomSheetOn(true); + }; + + const onSelectDownloadType = (type: 'IMAGE' | 'EMAIL') => { + if (type === 'IMAGE') { + // Save image directly + const params: ExtensionPayoutDetailDownloadCertificateParams = { + mid: mid, + tid: tid, + requestType: 'IMAGE', + email: '' + }; + extensionPayoutDetailDownloadCertification(params) + .then((rs: ExtensionPayoutDetailDownloadCertificateResponse) => { + console.log('Certificate Download Status:', rs); + }) + .catch((error) => { + console.error('Certificate Download Failed:', error); + }); + } else { + // Open EmailBottomSheet for email option + setEmailBottomSheetOn(true); + } + }; + + const onSendRequest = (selectedEmail?: string) => { + if (selectedEmail) { + const params: ExtensionPayoutDetailDownloadCertificateParams = { + mid: mid, + tid: tid, + requestType: 'EMAIL', + email: selectedEmail + }; + extensionPayoutDetailDownloadCertification(params) + .then((rs: ExtensionPayoutDetailDownloadCertificateResponse) => { + console.log('Certificate Download Status:', rs); + }) + .catch((error) => { + console.error('Certificate Download Failed:', error); + }); + } + setEmailBottomSheetOn(false); + }; + + const onClickToClose = () => { + setDetailOn(false); + }; + + + useEffect(() => { + if (!!mid && !!tid) { + callDetail(); + } + }, [mid, tid]); + + return ( + <> + +
+
+
{t('additionalService.payout.detailTitle')}
+
+ +
+
+
+
+
+ + {t('home.money', { value: new Intl.NumberFormat('en-US').format(detail?.disbursementAmount || 0) })} + +
+
{detail?.companyName}
+
{detail?.settlementDate}
+
+ +
+
+
+
+
{t('additionalService.payout.detailInfo')}
+
    +
  • + {t('additionalService.payout.disbursementStatus')} + {detail?.disbursementStatus} +
  • +
  • + {t('additionalService.payout.transactionType')} + {detail?.transTypeName} +
  • +
  • + {t('common.requestDate')} + {moment(detail?.requestDate).format('YYYY.MM.DD')} +
  • +
  • + {t('additionalService.payout.disbursementDateTime')} + {moment(detail?.settlementDateTime, 'YYYYMMDDHHmmss').format('YYYY.MM.DD HH:mm:ss')} +
  • +
  • + {t('additionalService.payout.businessNumber')} + {detail?.companyNo} +
  • +
  • + {t('additionalService.payout.accountHolder')} + {detail?.accountName} +
  • +
  • + {t('additionalService.payout.bank')} + {detail?.bankName} +
  • +
  • + {t('additionalService.payout.accountNumber')} + {detail?.accountNo} +
  • +
  • + {t('additionalService.payout.depositor')} + {detail?.depositName} +
  • +
  • + {t('additionalService.payout.failureReason')} + {detail?.failReason} +
  • +
+
+
+
+ + +
+ + ) + +} \ No newline at end of file diff --git a/src/entities/additional-service/ui/filter/payout-filter.tsx b/src/entities/additional-service/ui/payout/filter/payout-filter.tsx similarity index 98% rename from src/entities/additional-service/ui/filter/payout-filter.tsx rename to src/entities/additional-service/ui/payout/filter/payout-filter.tsx index 7b56040..10b90f1 100644 --- a/src/entities/additional-service/ui/filter/payout-filter.tsx +++ b/src/entities/additional-service/ui/payout/filter/payout-filter.tsx @@ -8,11 +8,11 @@ import { FilterRangeAmount } from '@/shared/ui/filter/range-amount'; import { PayoutDisbursementStatus, PayoutSearchDateType -} from '../../model/payout/types'; +} from '../../../model/payout/types'; import { getPayoutSearchClBtnGroup, getPayoutDisbursementStatusBtnGroup -} from '../../model/payout/constant'; +} from '../../../model/payout/constant'; import { FilterMotionDuration, FilterMotionStyle, diff --git a/src/entities/additional-service/ui/payout/payout-list.tsx b/src/entities/additional-service/ui/payout/payout-list.tsx new file mode 100644 index 0000000..e669d2e --- /dev/null +++ b/src/entities/additional-service/ui/payout/payout-list.tsx @@ -0,0 +1,69 @@ +import { PayoutListProps, PayoutSearchDateType } from "../../model/payout/types"; +import { AdditionalServiceCategory } from "../../model/types"; +import { ListDateGroup } from "../list-date-group"; + +export const PayoutList = ({ + additionalServiceCategory, + listItems, + searchDateType, + mid, + setDetailData +}: PayoutListProps) => { + + const getListDateGroup = () => { + let rs = []; + let date = ''; + let list = []; + for (let i = 0; i < listItems.length; i++) { + let itemDateStr = ''; + if (searchDateType === PayoutSearchDateType.REQUEST_DATE) { + itemDateStr = listItems[i]?.requestDate || ''; + } else if (searchDateType === PayoutSearchDateType.SETTLEMENT_DATE) { + itemDateStr = listItems[i]?.settlementDate || ''; + } + let itemDate = itemDateStr.substring(0, 8); + if (i === 0) { + date = itemDate; + } + if (date !== itemDate) { + if (list.length > 0) { + rs.push( + + ); + } + date = itemDate; + list = []; + } + list.push(listItems[i] as any); + } + if (list.length > 0) { + rs.push( + + ); + } + return rs; + }; + + return ( + <> +
+ {getListDateGroup()} +
+ + ) + +} \ No newline at end of file diff --git a/src/pages/additional-service/additional-service-pages.tsx b/src/pages/additional-service/additional-service-pages.tsx index a8b1a06..f4b8dd5 100644 --- a/src/pages/additional-service/additional-service-pages.tsx +++ b/src/pages/additional-service/additional-service-pages.tsx @@ -25,7 +25,6 @@ import { SettlementAgencyMemberPage } from './settlement-agency/member-page'; import { SettlementAgencyRegisterPage } from './settlement-agency/register-page'; import { SettlementAgencyDetailPage } from './settlement-agency/detail-page'; import { PayoutListPage } from './payout/list-page'; -import { PayoutDetailPage } from './payout/detail-page'; import { PayoutRequestPage } from './payout/request-page'; import { LinkPaymentApplyPage } from './link-payment/apply/link-payment-apply-page'; import { LinkPaymentApplyConfirmPage } from './link-payment/apply/link-payment-apply-confirm-page'; @@ -90,7 +89,6 @@ export const AdditionalServicePages = () => { } /> - } /> } /> diff --git a/src/pages/additional-service/ars/list-page.tsx b/src/pages/additional-service/ars/list-page.tsx index 6293e6c..d493969 100644 --- a/src/pages/additional-service/ars/list-page.tsx +++ b/src/pages/additional-service/ars/list-page.tsx @@ -18,7 +18,7 @@ import { ListDateGroup } from '@/entities/additional-service/ui/list-date-group' import { AdditionalServiceCategory, DetailData } from '@/entities/additional-service/model/types'; import { SortTypeBox } from '@/entities/common/ui/sort-type-box'; import { getArsPaymentStatusBtnGroup } from '@/entities/additional-service/model/ars/constant'; -import { ArsFilter } from '@/entities/additional-service/ui/filter/ars-filter'; +import { ArsFilter } from '@/entities/additional-service/ui/ars/filter/ars-filter'; import { useTranslation } from 'react-i18next'; import { useStore } from '@/shared/model/store'; import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet'; diff --git a/src/pages/additional-service/payout/list-page.tsx b/src/pages/additional-service/payout/list-page.tsx index bb14382..c194b83 100644 --- a/src/pages/additional-service/payout/list-page.tsx +++ b/src/pages/additional-service/payout/list-page.tsx @@ -23,15 +23,17 @@ import { import moment from 'moment'; import { SortTypeBox } from '@/entities/common/ui/sort-type-box'; import { useExtensionPayoutExcelMutation } from '@/entities/additional-service/api/payout/use-extension-payout-excel-mutation'; -import { PayoutFilter } from '@/entities/additional-service/ui/filter/payout-filter'; +import { PayoutFilter } from '@/entities/additional-service/ui/payout/filter/payout-filter'; import { getPayoutDisbursementStatusBtnGroup } from '@/entities/additional-service/model/payout/constant'; import { ListDateGroup } from '@/entities/additional-service/ui/list-date-group'; import { useTranslation } from 'react-i18next'; -import { AdditionalServiceCategory } from '@/entities/additional-service/model/types'; +import { AdditionalServiceCategory, DetailData } from '@/entities/additional-service/model/types'; import { useStore } from '@/shared/model/store'; import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet'; import { useExtensionAccessCheck } from '@/shared/lib/hooks/use-extension-access-check'; import useIntersectionObserver from '@/widgets/intersection-observer'; +import { PayoutList } from '@/entities/additional-service/ui/payout/payout-list'; +import { PayoutDetail } from '@/entities/additional-service/ui/payout/detail/payout-detail'; export const PayoutListPage = () => { // Access check @@ -56,22 +58,26 @@ export const PayoutListPage = () => { const [maxAmount, setMaxAmount] = useState(); const [emailBottomSheetOn, setEmailBottomSheetOn] = useState(false); + const [detailOn, setDetailOn] = useState(false); + const [detailMid, setDetailMid] = useState(''); + const [detailTid, setDetailTid] = useState(''); + const { mutateAsync: extensionPayoutList } = useExtensionPayoutListMutation(); const { mutateAsync: extensionPayoutExcel } = useExtensionPayoutExcelMutation(); const onIntersect: IntersectionObserverCallback = (entries: Array) => { entries.forEach((entry: IntersectionObserverEntry) => { - if(entry.isIntersecting){ - if(onActionIntersect && !!pageParam.cursor){ + if (entry.isIntersecting) { + if (onActionIntersect && !!pageParam.cursor) { setOnActionIntersect(false); callList('page'); - } + } } }); }; - const { setTarget } = useIntersectionObserver({ - threshold: 1, - onIntersect + const { setTarget } = useIntersectionObserver({ + threshold: 1, + onIntersect }); useSetHeaderTitle(t('additionalService.payout.title')); @@ -96,41 +102,41 @@ export const PayoutListPage = () => { minAmount: minAmount, maxAmount: maxAmount, page: { - ...pageParam, - ...{ sortType: sortType } - } + ...pageParam, + ...{ sortType: sortType } + } }; - if(type !== 'page' && listParams.page){ + if (type !== 'page' && listParams.page) { listParams.page.cursor = null; } extensionPayoutList(listParams).then((rs: ExtensionPayoutListResponse) => { - if(type === 'page'){ + if (type === 'page') { setListItems([ ...listItems, ...rs.content ]); } - else{ + else { setListItems(rs.content); } - if(rs.hasNext + if (rs.hasNext && rs.nextCursor !== pageParam.cursor && rs.content.length === DEFAULT_PAGE_PARAM.size - ){ + ) { setPageParam({ ...pageParam, ...{ cursor: rs.nextCursor } }); } - else{ + else { setPageParam({ ...pageParam, ...{ cursor: null } }); } setOnActionIntersect( - !!rs.hasNext + !!rs.hasNext && rs.nextCursor !== pageParam.cursor && rs.content.length === DEFAULT_PAGE_PARAM.size ); @@ -155,6 +161,17 @@ export const PayoutListPage = () => { } setEmailBottomSheetOn(false); }; + + const setDetailData = (detailData: DetailData) => { + setDetailOn(detailData.detailOn); + if (detailData.mid) { + setDetailMid(detailData.mid); + } + if (detailData.tid) { + setDetailTid(detailData.tid); + } + }; + const onClickToOpenFilter = () => { setFilterOn(!filterOn); }; @@ -276,7 +293,7 @@ export const PayoutListPage = () => { -
+
{ }
-
-
- { getListDateGroup() } -
-
+ + +