This commit is contained in:
focp212@naver.com
2025-11-04 11:08:39 +09:00
11 changed files with 351 additions and 45 deletions

View File

@@ -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';

View File

@@ -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) {

View File

@@ -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<ExtensionPayoutDetailResponse>();
const [downloadTypeBottomSheetOn, setDownloadTypeBottomSheetOn] = useState<boolean>(false);
const [emailBottomSheetOn, setEmailBottomSheetOn] = useState<boolean>(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 (
<>
<motion.div
className="full-menu-modal"
initial="hidden"
animate={(detailOn) ? 'visible' : 'hidden'}
variants={DetailMotionVariants}
transition={DetailMotionDuration}
style={DetailMotionStyle}
>
<div className="full-menu-container pdw-16">
<div className="full-menu-header">
<div className="full-menu-title center">{t('additionalService.payout.detailTitle')}</div>
<div className="full-menu-actions">
<FullMenuClose
addClass="full-menu-close"
onClickToCallback={onClickToClose}
></FullMenuClose>
</div>
</div>
<div className="tab-pane sub active">
<div className="pay-top">
<div className="num-amount">
<span className="amount">
{t('home.money', { value: new Intl.NumberFormat('en-US').format(detail?.disbursementAmount || 0) })}
</span>
</div>
<div className="num-store">{detail?.companyName}</div>
<div className="num-day">{detail?.settlementDate}</div>
<div className="receipt-row">
<button
className="receipt-btn"
type="button"
onClick={onClickToDownload}
>
<span className="icon-24 download"></span>
<span>{t('additionalService.payout.depositCertificate')}</span>
</button>
</div>
</div>
<div className="detail-divider"></div>
<div className="pay-detail">
<div className="detail-title">{t('additionalService.payout.detailInfo')}</div>
<ul className="kv-list">
<li className="kv-row">
<span className="k">{t('additionalService.payout.disbursementStatus')}</span>
<span className="v">{detail?.disbursementStatus}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.payout.transactionType')}</span>
<span className="v">{detail?.transTypeName}</span>
</li>
<li className="kv-row">
<span className="k">{t('common.requestDate')}</span>
<span className="v">{moment(detail?.requestDate).format('YYYY.MM.DD')}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.payout.disbursementDateTime')}</span>
<span className="v">{moment(detail?.settlementDateTime, 'YYYYMMDDHHmmss').format('YYYY.MM.DD HH:mm:ss')}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.payout.businessNumber')}</span>
<span className="v">{detail?.companyNo}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.payout.accountHolder')}</span>
<span className="v">{detail?.accountName}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.payout.bank')}</span>
<span className="v">{detail?.bankName}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.payout.accountNumber')}</span>
<span className="v">{detail?.accountNo}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.payout.depositor')}</span>
<span className="v">{detail?.depositName}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.payout.failureReason')}</span>
<span className="v">{detail?.failReason}</span>
</li>
</ul>
</div>
</div>
</div>
<DownloadTypeBottomSheet
bottomSheetOn={downloadTypeBottomSheetOn}
setBottomSheetOn={setDownloadTypeBottomSheetOn}
onSelectType={onSelectDownloadType}
/>
<EmailBottomSheet
bottomSheetOn={emailBottomSheetOn}
setBottomSheetOn={setEmailBottomSheetOn}
imageSave={false}
sendEmail={true}
sendRequest={onSendRequest}
/>
</motion.div>
</>
)
}

View File

@@ -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,

View File

@@ -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(
<ListDateGroup
additionalServiceCategory={additionalServiceCategory}
mid={mid}
key={date + '-' + i}
date={date}
items={list}
setDetailData={setDetailData}
></ListDateGroup>
);
}
date = itemDate;
list = [];
}
list.push(listItems[i] as any);
}
if (list.length > 0) {
rs.push(
<ListDateGroup
additionalServiceCategory={additionalServiceCategory}
mid={mid}
key={date + '-last'}
date={date}
items={list}
setDetailData={setDetailData}
></ListDateGroup>
);
}
return rs;
};
return (
<>
<section className="transaction-list">
{getListDateGroup()}
</section>
</>
)
}