Refactor additional service details and fix various bugs

- Convert detail pages to modal components for better UX
- Fix seq type from string to number for ARS and Alimtalk
- Add seq field to list item types
- Fix validation for card number input (remove formatting chars)
- Fix SMS payment resend seq parameter issue
- Improve z-index handling for snackBar and dialogs
- Add useSetHeaderTitle to link payment history wrap
- Remove unused detail page files
- Update payout filter and various detail components

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
HyeonJongKim
2025-11-05 19:41:05 +09:00
parent 50f062b3cf
commit 24435e47d6
30 changed files with 790 additions and 1869 deletions

View File

@@ -1,190 +0,0 @@
import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { useTranslation } from 'react-i18next';
import { HeaderType } from '@/entities/common/model/types';
import {
useSetHeaderTitle,
useSetHeaderType,
useSetFooterMode,
useSetOnBack
} from '@/widgets/sub-layout/use-sub-layout';
import { useExtensionPayoutDetailMutation } from '@/entities/additional-service/api/payout/use-extension-payout-detail-mutation';
import { useLocation } from 'react-router';
import { ExtensionPayoutDetailDownloadCertificateParams, ExtensionPayoutDetailDownloadCertificateResponse, ExtensionPayoutDetailParams, ExtensionPayoutDetailResponse } from '@/entities/additional-service/model/payout/types';
import { useEffect, useState } from 'react';
import { NumericFormat } from 'react-number-format';
import { useExtensionPayoutDetailDownloadCertificateMutation } from '@/entities/additional-service/api/payout/use-extension-payout-detail-download-cetificate-mutation';
import moment from 'moment';
import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet';
import { DownloadTypeBottomSheet } from '@/entities/common/ui/download-type-bottom-sheet';
export const PayoutDetailPage = () => {
const { t, i18n } = useTranslation();
const { navigate } = useNavigate();
const location = useLocation();
const tid = location.state.tid;
const mid = location.state.mid;
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);
});
};
useSetHeaderTitle(t('additionalService.payout.detailTitle'));
useSetHeaderType(HeaderType.LeftArrow);
useSetFooterMode(false);
useSetOnBack(() => {
navigate(PATHS.additionalService.payout.list);
});
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);
};
useEffect(() => {
callDetail();
}, []);
return (
<>
<main className="full-height">
<div className="tab-content">
<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>
</main>
<DownloadTypeBottomSheet
bottomSheetOn={downloadTypeBottomSheetOn}
setBottomSheetOn={setDownloadTypeBottomSheetOn}
onSelectType={onSelectDownloadType}
/>
<EmailBottomSheet
bottomSheetOn={emailBottomSheetOn}
setBottomSheetOn={setEmailBottomSheetOn}
imageSave={false}
sendEmail={true}
sendRequest={onSendRequest}
/>
</>
);
};

View File

@@ -17,6 +17,7 @@ import moment from 'moment';
import { NumericFormat } from "react-number-format";
import { snackBar } from "@/shared/lib";
import { useTranslation } from 'react-i18next';
import { showAlert } from "@/widgets/show-alert";
export const PayoutRequestPage = () => {
const { t } = useTranslation();
@@ -53,10 +54,15 @@ export const PayoutRequestPage = () => {
snackBar(`[${t('common.failed')}] ${rs.error?.message}`)
}
})
.catch((error) => {
snackBar(`[${t('common.failed')}] ${error?.response?.data?.message} ` || `[${t('common.failed')}] ${t('additionalService.payout.requestFailed')}`)
})
;
.catch((e) => {
console.log(e)
if (e.response?.data?.error?.root !== "SystemErrorCode") {
snackBar(`[${t('common.failed')}] ${e.response?.data?.error?.message}`)
} else {
showAlert(`[${t('common.failed')}] ${e?.response?.data?.error?.message} ` || `[${t('common.failed')}] ${t('additionalService.payout.requestFailed')}`);
return;
}
});
};
const isFormValid = () => {