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

@@ -8,6 +8,7 @@ import { getAuthResultStatusText } from '@/entities/additional-service/model/fac
import { useTranslation } from 'react-i18next';
import { DetailMotionDuration, DetailMotionStyle, DetailMotionVariants } from '@/entities/common/model/constant';
import { FullMenuClose } from '@/entities/common/ui/full-menu-close';
import { showAlert } from '@/widgets/show-alert';
export interface AccountHolderAuthDetailProps {
detailOn: boolean;
@@ -33,7 +34,12 @@ export const AccountHolderAuthDetail = ({
tid: tid
}
accountHolderAuthDetail(accountHolderAuthDetailParams).then((rs: ExtensionAccountHolderAuthDetailResponse) => {
setDetail(rs);
setDetail(rs);
}).catch((e: any) => {
if (e.response?.data?.error?.message) {
showAlert(e.response?.data?.error?.message);
return;
}
});
};
const onClickToClose = () => {
@@ -45,77 +51,77 @@ export const AccountHolderAuthDetail = ({
};
useEffect(() => {
if(!!mid && !!tid){
if (!!mid && !!tid) {
callDetail();
}
}, [mid, tid]);
return (
<>
<motion.div
className="full-menu-modal"
<motion.div
className="full-menu-modal"
initial="hidden"
animate={ (detailOn)? 'visible': 'hidden' }
variants={ DetailMotionVariants }
transition={ DetailMotionDuration }
style={ DetailMotionStyle }
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.accountHolderAuth.detailTitle') }</div>
<div className="full-menu-title center">{t('additionalService.accountHolderAuth.detailTitle')}</div>
<div className="full-menu-actions">
<FullMenuClose
addClass="full-menu-close"
onClickToCallback={ onClickToClose }
onClickToCallback={onClickToClose}
></FullMenuClose>
</div>
</div>
<div className="pay-top">
<div className="num-amount">
<span className="amount">{detail?.accountName}</span>
</div>
<span className="num-store">{detail?.accountNo}</span>
<div className="num-day">{getDate(detail?.requestDate)}</div>
</div>
<div className="detail-divider"></div>
<div className="pay-detail">
<div className="detail-title">{t('transaction.sections.detailInfo')}</div>
<ul className="kv-list">
<li className="kv-row">
<span className="k">{t('transaction.fields.companyName')}</span>
<span className="v">{detail?.companyName}</span>
</li>
<li className="kv-row">
<span className="k">{t('transaction.fields.mid')}</span>
<span className="v">{detail?.mid}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.accountHolderAuth.requestDate')}</span>
<span className="v">{getDate(detail?.requestDate)}</span>
</li>
<li className="kv-row">
<span className="k">{t('transaction.fields.bank')}</span>
<span className="v">{detail?.bankName}</span>
</li>
<li className="kv-row">
<span className="k">{t('transaction.fields.accountNo')}</span>
<span className="v">{detail?.accountNo}</span>
</li>
<li className="kv-row">
<span className="k">{t('transaction.fields.accountHolder')}</span>
<span className="v">{detail?.accountName}</span>
</li>
<li className="kv-row">
<span className="k">{t('common.result')}</span>
<span className="v">{getAuthStatusText(t)(detail?.authStatus)}</span>
</li>
<li className="kv-row">
<span className="k">{t('transaction.fields.failureReason')}</span>
<span className="v">{detail?.failReason ? getAuthResultStatusText(t)(detail?.failReason) : '-' }</span>
</li>
</ul>
<div className="pay-top">
<div className="num-amount">
<span className="amount">{detail?.accountName}</span>
</div>
<span className="num-store">{detail?.accountNo}</span>
<div className="num-day">{getDate(detail?.requestDate)}</div>
</div>
<div className="detail-divider"></div>
<div className="pay-detail">
<div className="detail-title">{t('transaction.sections.detailInfo')}</div>
<ul className="kv-list">
<li className="kv-row">
<span className="k">{t('transaction.fields.companyName')}</span>
<span className="v">{detail?.companyName}</span>
</li>
<li className="kv-row">
<span className="k">{t('transaction.fields.mid')}</span>
<span className="v">{detail?.mid}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.accountHolderAuth.requestDate')}</span>
<span className="v">{getDate(detail?.requestDate)}</span>
</li>
<li className="kv-row">
<span className="k">{t('transaction.fields.bank')}</span>
<span className="v">{detail?.bankName}</span>
</li>
<li className="kv-row">
<span className="k">{t('transaction.fields.accountNo')}</span>
<span className="v">{detail?.accountNo}</span>
</li>
<li className="kv-row">
<span className="k">{t('transaction.fields.accountHolder')}</span>
<span className="v">{detail?.accountName}</span>
</li>
<li className="kv-row">
<span className="k">{t('common.result')}</span>
<span className="v">{getAuthStatusText(t)(detail?.authStatus)}</span>
</li>
<li className="kv-row">
<span className="k">{t('transaction.fields.failureReason')}</span>
<span className="v">{detail?.failReason ? getAuthResultStatusText(t)(detail?.failReason) : '-'}</span>
</li>
</ul>
</div>
</div>
</motion.div>
</>
);

View File

@@ -10,6 +10,7 @@ import { useExtensionArsDetailMutation } from '@/entities/additional-service/api
import { useExtensionArsResendMutation } from '@/entities/additional-service/api/ars/use-extension-ars-resend-mutation';
import { snackBar } from '@/shared/lib';
import { ArsResendSmsBottomSheet } from '../resend-sms-bottom-sheet';
import { showAlert } from '@/widgets/show-alert';
export interface ArsDetailProps {
detailOn: boolean;
@@ -39,6 +40,11 @@ export const ArsDetail = ({
};
extensionArsDetail(arsDetailParams).then((rs: ExtensionArsDetailResponse) => {
setDetail(rs);
}).catch((e: any) => {
if (e.response?.data?.error?.message) {
showAlert(e.response?.data?.error?.message);
return;
}
});
}
@@ -101,76 +107,76 @@ export const ArsDetail = ({
></FullMenuClose>
</div>
</div>
<div className="pay-top">
<div className="num-amount">
<span className="amount">
{t('home.money', { value: new Intl.NumberFormat('en-US').format(Number(detail?.amount) || 0) })}
</span>
</div>
<div className="num-store">{detail?.corpName}</div>
<div className="num-day">{getDate(detail?.paymentDate)}</div>
<div className="pay-top">
<div className="num-amount">
<span className="amount">
{t('home.money', { value: new Intl.NumberFormat('en-US').format(Number(detail?.amount) || 0) })}
</span>
</div>
<div className="detail-divider"></div>
<div className="pay-detail">
<div className="detail-title">{t('additionalService.ars.transactionInfo')}</div>
<ul className="kv-list">
<li className="kv-row">
<span className="k">{t('transaction.fields.mid')}</span>
<span className="v">{detail?.mid}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.ars.paymentMethod')}</span>
<span className="v">{detail?.arsPaymentMethod}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.ars.paymentStatus')}</span>
<span className="v">{getArsPaymentStatusName(t)(detail?.paymentStatus)}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.ars.orderStatus')}</span>
<span className="v">{getArsOrderStatusName(t)(detail?.orderStatus)}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.ars.orderDateTime')}</span>
<span className="v">{
detail?.paymentDate ? moment(detail.paymentDate, 'YYYYMMDDHHmmss').format('YYYY.MM.DD HH:mm:ss') : '-'
}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.ars.productName')}</span>
<span className="v">{detail?.goodsName}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.ars.orderNumber')}</span>
<span className="v">{detail?.tid}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.ars.buyer')}</span>
<span className="v">{detail?.buyerName}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.ars.phoneNumber')}</span>
<span className="v">{detail?.maskPhoneNumber}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.ars.email')}</span>
<span className="v">{detail?.email}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.ars.sendVerificationCode')}</span>
<span className="v">{detail?.smsVerificationCode}</span>
</li>
</ul>
<div className="num-store">{detail?.corpName}</div>
<div className="num-day">{getDate(detail?.paymentDate)}</div>
</div>
<div className="detail-divider"></div>
<div className="pay-detail">
<div className="detail-title">{t('additionalService.ars.transactionInfo')}</div>
<ul className="kv-list">
<li className="kv-row">
<span className="k">{t('transaction.fields.mid')}</span>
<span className="v">{detail?.mid}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.ars.paymentMethod')}</span>
<span className="v">{detail?.arsPaymentMethod}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.ars.paymentStatus')}</span>
<span className="v">{getArsPaymentStatusName(t)(detail?.paymentStatus)}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.ars.orderStatus')}</span>
<span className="v">{getArsOrderStatusName(t)(detail?.orderStatus)}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.ars.orderDateTime')}</span>
<span className="v">{
detail?.paymentDate ? moment(detail.paymentDate, 'YYYYMMDDHHmmss').format('YYYY.MM.DD HH:mm:ss') : '-'
}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.ars.productName')}</span>
<span className="v">{detail?.goodsName}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.ars.orderNumber')}</span>
<span className="v">{detail?.tid}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.ars.buyer')}</span>
<span className="v">{detail?.buyerName}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.ars.phoneNumber')}</span>
<span className="v">{detail?.maskPhoneNumber}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.ars.email')}</span>
<span className="v">{detail?.email}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.ars.sendVerificationCode')}</span>
<span className="v">{detail?.smsVerificationCode}</span>
</li>
</ul>
</div>
{detail?.arsPaymentMethod === ArsPaymentMethod.SMS && (
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={() => onClickToOpenResendBottomSheet()}
//disabled={ detail?.orderStatus !== OrderStatus.PENDING }
>{t('additionalService.ars.smsResend')}</button>
</div>
{detail?.arsPaymentMethod === ArsPaymentMethod.SMS && (
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={() => onClickToOpenResendBottomSheet()}
//disabled={ detail?.orderStatus !== OrderStatus.PENDING }
>{t('additionalService.ars.smsResend')}</button>
</div>
)}
)}
</div>
<ArsResendSmsBottomSheet
setBottomSheetOn={setBottomSheetOn}

View File

@@ -13,6 +13,7 @@ import { useExtensionFundAccountDownloadReceiptMutation } from '@/entities/addit
import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet';
import { DetailMotionDuration, DetailMotionStyle, DetailMotionVariants } from '@/entities/common/model/constant';
import { FullMenuClose } from '@/entities/common/ui/full-menu-close';
import { showAlert } from '@/widgets/show-alert';
export interface FundAccountResultDetailProps {
detailOn: boolean;
@@ -26,8 +27,8 @@ export const FundAccountResultDetail = ({
mid,
tid
}: FundAccountResultDetailProps) => {
const { t } = useTranslation();
const { t } = useTranslation();
const [detail, setDetail] = useState<ExtensionFundAccountResultDetailResponse>();
const [emailBottomSheetOn, setEmailBottomSheetOn] = useState<boolean>(false);
@@ -43,6 +44,11 @@ export const FundAccountResultDetail = ({
extensionFundAccountResultDetail(params).then((rs: ExtensionFundAccountResultDetailResponse) => {
console.log(rs.requestDate)
setDetail(rs);
}).catch((e: any) => {
if (e.response?.data?.error?.message) {
showAlert(e.response?.data?.error?.message);
return;
}
});
};
@@ -51,7 +57,7 @@ export const FundAccountResultDetail = ({
};
const onSendRequest = (selectedEmail?: string) => {
if(selectedEmail){
if (selectedEmail) {
let params: ExtensionFundAccountDownloadReceiptParams = {
mid: mid,
tid: tid,
@@ -63,107 +69,107 @@ export const FundAccountResultDetail = ({
}
setEmailBottomSheetOn(false);
};
const onClickToClose = () => {
setDetailOn(false);
};
useEffect(() => {
if(!!mid && !!tid){
if (!!mid && !!tid) {
callDetail();
}
}, [mid, tid]);
return (
<>
<motion.div
className="full-menu-modal"
<motion.div
className="full-menu-modal"
initial="hidden"
animate={ (detailOn)? 'visible': 'hidden' }
variants={ DetailMotionVariants }
transition={ DetailMotionDuration }
style={ DetailMotionStyle }
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.fundAccount.transferDetailTitle') }</div>
<div className="full-menu-title center">{t('additionalService.fundAccount.transferDetailTitle')}</div>
<div className="full-menu-actions">
<FullMenuClose
addClass="full-menu-close"
onClickToCallback={ onClickToClose }
onClickToCallback={onClickToClose}
></FullMenuClose>
</div>
</div>
<div className="pay-top">
<div className="num-amount">
<span className="amount">
{t('home.money', { value: new Intl.NumberFormat('en-US').format(detail?.amount || 0) })}
</span>
</div>
<div className="num-store">{detail?.accountName}({detail?.accountNo})</div>
{detail?.applicationDate && (
<div className="num-day"> {moment(detail?.applicationDate, 'YYYYMMDDHHmmss').format('YYYY.MM.DD HH:mm:ss')}</div>
)}
<div className="pay-top">
<div className="num-amount">
<span className="amount">
{t('home.money', { value: new Intl.NumberFormat('en-US').format(detail?.amount || 0) })}
</span>
</div>
{/* ✅ resultMessage가 "정상"일 때만 표시 */}
{detail?.resultMessage === '정상' && (
<div className="receipt-row">
<button
type="button"
className="receipt-btn"
onClick={ onClickToOpenEmailBottomSheet }
>
<span className="icon-24 download"></span>
<span>{t('additionalService.fundAccount.depositCertificate')}</span>
</button>
</div>
<div className="num-store">{detail?.accountName}({detail?.accountNo})</div>
{detail?.applicationDate && (
<div className="num-day"> {moment(detail?.applicationDate, 'YYYYMMDDHHmmss').format('YYYY.MM.DD HH:mm:ss')}</div>
)}
<div className="detail-divider"></div>
<div className="pay-detail">
<div className="detail-title">{t('additionalService.fundAccount.detailInfo')}</div>
<ul className="kv-list">
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.requestDateTime')}</span>
<span className="v">{moment(detail?.requestDate,'YYYYMMDDHHmmss').format('YYYY.MM.DD HH:mm:ss')}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.transferDateTime')}</span>
<span className="v">{detail?.applicationDate ? moment(detail?.applicationDate, 'YYYYMMDDHHmmss').format('YYYY.MM.DD HH:mm:ss') : '-'}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.transferResult')}</span>
<span className="v">{detail?.resultMessage || '-'}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.failureReason')}</span>
<span className="v">{detail?.failReason || '-'}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.beneficiaryName')}</span>
<span className="v">{detail?.accountName}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.bank')}</span>
<span className="v">{detail?.bankName}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.accountNumber')}</span>
<span className="v">{detail?.accountNo}</span>
</li>
<li className="kv-row">
<span className="k">MID</span>
<span className="v">{mid}</span>
</li>
<li className="kv-row">
<span className="k">{t('transaction.fields.orderNumber')}</span>
<span className="v">{detail?.moid}</span>
</li>
<li className="kv-row">
<span className="k">TID</span>
<span className="v">{detail?.tid}</span>
</li>
</ul>
</div>
{/* ✅ resultMessage가 "정상"일 때만 표시 */}
{detail?.resultMessage === '정상' && (
<div className="receipt-row">
<button
type="button"
className="receipt-btn"
onClick={onClickToOpenEmailBottomSheet}
>
<span className="icon-24 download"></span>
<span>{t('additionalService.fundAccount.depositCertificate')}</span>
</button>
</div>
)}
<div className="detail-divider"></div>
<div className="pay-detail">
<div className="detail-title">{t('additionalService.fundAccount.detailInfo')}</div>
<ul className="kv-list">
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.requestDateTime')}</span>
<span className="v">{moment(detail?.requestDate, 'YYYYMMDDHHmmss').format('YYYY.MM.DD HH:mm:ss')}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.transferDateTime')}</span>
<span className="v">{detail?.applicationDate ? moment(detail?.applicationDate, 'YYYYMMDDHHmmss').format('YYYY.MM.DD HH:mm:ss') : '-'}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.transferResult')}</span>
<span className="v">{detail?.resultMessage || '-'}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.failureReason')}</span>
<span className="v">{detail?.failReason || '-'}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.beneficiaryName')}</span>
<span className="v">{detail?.accountName}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.bank')}</span>
<span className="v">{detail?.bankName}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.accountNumber')}</span>
<span className="v">{detail?.accountNo}</span>
</li>
<li className="kv-row">
<span className="k">MID</span>
<span className="v">{mid}</span>
</li>
<li className="kv-row">
<span className="k">{t('transaction.fields.orderNumber')}</span>
<span className="v">{detail?.moid}</span>
</li>
<li className="kv-row">
<span className="k">TID</span>
<span className="v">{detail?.tid}</span>
</li>
</ul>
</div>
</div>
</motion.div>
<EmailBottomSheet

View File

@@ -11,6 +11,7 @@ import { snackBar } from '@/shared/lib';
import { useExtensionFundAccountTransferRequestMutation } from '@/entities/additional-service/api/fund-account/use-extension-fund-account-transfer-request-mutation';
import { DetailMotionDuration, DetailMotionStyle, DetailMotionVariants } from '@/entities/common/model/constant';
import { FullMenuClose } from '@/entities/common/ui/full-menu-close';
import { showAlert } from '@/widgets/show-alert';
export interface FundAccountTransferDetailProps {
detailOn: boolean;
@@ -39,27 +40,35 @@ export const FundAccountTransferDetail = ({
extensionFundAccountTransferDetail(params).then((rs: ExtensionFundAccountTransferDetailResponse) => {
setDetail(rs);
});
}).catch((e: any) => {
if (e.response?.data?.error?.message) {
showAlert(e.response?.data?.error?.message);
return;
}
});;
};
const onClickToRequest = () => {
let params: ExtensionFundAccountTransferRequestParams = {
seq: seq
};
extensionFundAccountTransferRequest(params).then((rs: ExtensionFundAccountTransferRequestResponse) => {
if(rs.status){
if (rs.status) {
callDetail();
snackBar(t('additionalService.fundAccount.transferRequestSuccess'))
}
else{
else {
const errorMessage = rs.error?.message || t('additionalService.fundAccount.transferRequestFailed');
snackBar(`[${t('common.failed')}] ${errorMessage}`);
}
}).catch((error) => {
const errorMessage = error?.response?.data?.error?.message ||
error?.message ||
t('additionalService.fundAccount.transferRequestError');
snackBar(`[${t('common.failed')}] ${errorMessage}`);
console.log(error);
const errorMessage = error?.response?.data?.error?.message || error?.message || t('additionalService.fundAccount.transferRequestError');
if (error.response?.data?.error?.root !== "SystemErrorCode") {
snackBar(`[${t('common.failed')}] ${error.response?.data?.error?.message}`)
} else {
showAlert(`[${t('common.failed')}] ${errorMessage}`);
}
});
};
@@ -68,92 +77,92 @@ export const FundAccountTransferDetail = ({
};
useEffect(() => {
if(!!seq){
if (!!seq) {
callDetail();
}
}, [seq]);
return (
<>
<motion.div
className="full-menu-modal"
<motion.div
className="full-menu-modal"
initial="hidden"
animate={ (detailOn)? 'visible': 'hidden' }
variants={ DetailMotionVariants }
transition={ DetailMotionDuration }
style={ DetailMotionStyle }
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.fundAccount.transferDetailTitle') }</div>
<div className="full-menu-title center">{t('additionalService.fundAccount.transferDetailTitle')}</div>
<div className="full-menu-actions">
<FullMenuClose
addClass="full-menu-close"
onClickToCallback={ onClickToClose }
onClickToCallback={onClickToClose}
></FullMenuClose>
</div>
</div>
<div className="pay-top">
<div className="num-amount">
<span className="amount">
{t('home.money', { value: new Intl.NumberFormat('en-US').format(detail?.amount || 0) })}
<div className="pay-top">
<div className="num-amount">
<span className="amount">
{t('home.money', { value: new Intl.NumberFormat('en-US').format(detail?.amount || 0) })}
</span>
</div>
<div className="num-store">{detail?.accountName}({detail?.accountNo})</div>
<div className="num-day">
{detail?.registDate ? moment(detail.registDate, 'YYYYMMDDHHmmss').format('YYYY.MM.DD HH:mm:ss') : '-'}
</div>
</div>
<div className="detail-divider"></div>
<div className="pay-detail">
<div className="detail-title">{t('additionalService.fundAccount.detailInfo')}</div>
<ul className="kv-list">
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.registrationDateTime')}</span>
<span className="v">
{detail?.registDate ? moment(detail.registDate, 'YYYYMMDDHHmmss').format('YYYY.MM.DD HH:mm:ss') : '-'}
</span>
</div>
<div className="num-store">{detail?.accountName}({detail?.accountNo})</div>
<div className="num-day">
{detail?.registDate ? moment(detail.registDate, 'YYYYMMDDHHmmss').format('YYYY.MM.DD HH:mm:ss') : '-'}
</div>
</div>
<div className="detail-divider"></div>
<div className="pay-detail">
<div className="detail-title">{t('additionalService.fundAccount.detailInfo')}</div>
<ul className="kv-list">
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.registrationDateTime')}</span>
<span className="v">
{detail?.registDate ? moment(detail.registDate, 'YYYYMMDDHHmmss').format('YYYY.MM.DD HH:mm:ss') : '-'}
</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.processingResult')}</span>
<span className="v">{getFundAccountStatusName(t)(detail?.resultStatus) || '-'}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.requestDate')}</span>
<span className="v">
{detail?.requestDate ? moment(detail.requestDate, 'YYYYMMDDHHmmss').format('YYYY.MM.DD') : '-'}
</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.transferResult')}</span>
<span className="v">{detail?.resultMessage || '-'}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.beneficiaryName')}</span>
<span className="v">{detail?.accountName}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.bank')}</span>
<span className="v">{detail?.bankCode || '-'} </span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.accountNumber')}</span>
<span className="v">{detail?.accountNo}</span>
</li>
<li className="kv-row">
<span className="k">MID</span>
<span className="v">{detail?.mid}</span>
</li>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.processingResult')}</span>
<span className="v">{getFundAccountStatusName(t)(detail?.resultStatus) || '-'}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.requestDate')}</span>
<span className="v">
{detail?.requestDate ? moment(detail.requestDate, 'YYYYMMDDHHmmss').format('YYYY.MM.DD') : '-'}
</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.transferResult')}</span>
<span className="v">{detail?.resultMessage || '-'}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.beneficiaryName')}</span>
<span className="v">{detail?.accountName}</span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.bank')}</span>
<span className="v">{detail?.bankCode || '-'} </span>
</li>
<li className="kv-row">
<span className="k">{t('additionalService.fundAccount.accountNumber')}</span>
<span className="v">{detail?.accountNo}</span>
</li>
<li className="kv-row">
<span className="k">MID</span>
<span className="v">{detail?.mid}</span>
</li>
</ul>
</div>
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={() => onClickToRequest()}
disabled={detail?.resultStatus !== FundAccountStatus.REGIST_COMPLETE}
>{t('additionalService.fundAccount.transferRequestButton')}</button>
</div>
</ul>
</div>
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={() => onClickToRequest()}
disabled={detail?.resultStatus !== FundAccountStatus.REGIST_COMPLETE}
>{t('additionalService.fundAccount.transferRequestButton')}</button>
</div>
</div>
</motion.div>
</>

View File

@@ -24,6 +24,7 @@ import moment from 'moment';
import { useTranslation } from 'react-i18next';
import { DetailMotionDuration, DetailMotionStyle, DetailMotionVariants } from '@/entities/common/model/constant';
import { FullMenuClose } from '@/entities/common/ui/full-menu-close';
import { showAlert } from '@/widgets/show-alert';
export interface LinkPaymentHistoryDetailProps {
detailOn: boolean;
@@ -66,7 +67,12 @@ export const LinkPaymentHistoryDetail = ({
setDetailInfo(rs.detailInfo)
setPaymentInfo(rs.paymentInfo)
setDetailExposure(rs.detailExposure ?? false)
})
}).catch((e: any) => {
if (e.response?.data?.error?.message) {
showAlert(e.response?.data?.error?.message);
return;
}
});
}
// Resend API
@@ -88,9 +94,15 @@ export const LinkPaymentHistoryDetail = ({
})
.catch((error) => {
const errorMessage = error?.response?.data?.error?.message ||
error?.message ||
t('additionalService.linkPayment.resendError');
snackBar(`[${t('common.failed')}] ${errorMessage}`);
error?.message ||
t('additionalService.linkPayment.resendError');
console.log(error)
if (error.response?.data?.error?.root !== "SystemErrorCode") {
snackBar(`[${t('common.failed')}] ${errorMessage}`);
}
else {
showAlert(`[${t('common.failed')}] ${errorMessage}`)
}
});
}
@@ -143,64 +155,64 @@ export const LinkPaymentHistoryDetail = ({
};
useEffect(() => {
if(!!mid && !!requestId){
if (!!mid && !!requestId) {
callDetail();
}
}, [mid, requestId, subReqId]);
return (
<>
<motion.div
className="full-menu-modal"
<motion.div
className="full-menu-modal"
initial="hidden"
animate={ (detailOn)? 'visible': 'hidden' }
variants={ DetailMotionVariants }
transition={ DetailMotionDuration }
style={ DetailMotionStyle }
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.linkPayment.detailTitle') }</div>
<div className="full-menu-title center">{t('additionalService.linkPayment.detailTitle')}</div>
<div className="full-menu-actions">
<FullMenuClose
addClass="full-menu-close"
onClickToCallback={ onClickToClose }
onClickToCallback={onClickToClose}
></FullMenuClose>
</div>
</div>
<div className="pay-top">
<TitleInfoWrap
additionalServiceCategory={AdditionalServiceCategory.LinkPaymentHistory}
titleInfo={titleInfo}
></TitleInfoWrap>
</div>
<div className="pay-detail">
<div className="detail-divider"></div>
<PaymentInfoWrap
additionalServiceCategory={AdditionalServiceCategory.LinkPaymentHistory}
paymentInfo={paymentInfo}
></PaymentInfoWrap>
<div className="detail-divider"></div>
<DetailInfoWrap
additionalServiceCategory={AdditionalServiceCategory.LinkPaymentHistory}
detailInfo={detailInfo}
></DetailInfoWrap>
<div className="detail-divider"></div>
<div className="link-payment-detail-button" style={{ paddingBottom: '100px' }}>
<button
className="btn-50 btn-blue flex-1"
onClick={() => onClickToSeparateApproval()}
disabled={detailExposure}
>{t('additionalService.linkPayment.separateApprovalDetail')}</button>
</div>
</div>
<div className="apply-row">
<div className="pay-top">
<TitleInfoWrap
additionalServiceCategory={AdditionalServiceCategory.LinkPaymentHistory}
titleInfo={titleInfo}
></TitleInfoWrap>
</div>
<div className="pay-detail">
<div className="detail-divider"></div>
<PaymentInfoWrap
additionalServiceCategory={AdditionalServiceCategory.LinkPaymentHistory}
paymentInfo={paymentInfo}
></PaymentInfoWrap>
<div className="detail-divider"></div>
<DetailInfoWrap
additionalServiceCategory={AdditionalServiceCategory.LinkPaymentHistory}
detailInfo={detailInfo}
></DetailInfoWrap>
<div className="detail-divider"></div>
<div className="link-payment-detail-button" style={{ paddingBottom: '100px' }}>
<button
className="btn-50 btn-blue flex-1"
onClick={() => onClickToResend()}
disabled={!isResendEnabled()}
>{t('additionalService.linkPayment.resend')}</button>
onClick={() => onClickToSeparateApproval()}
disabled={detailExposure}
>{t('additionalService.linkPayment.separateApprovalDetail')}</button>
</div>
</div>
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={() => onClickToResend()}
disabled={!isResendEnabled()}
>{t('additionalService.linkPayment.resend')}</button>
</div>
</div>
</motion.div>
</>
)

View File

@@ -12,6 +12,8 @@ import { snackBar } from '@/shared/lib';
import { useTranslation } from 'react-i18next';
import { DetailMotionDuration, DetailMotionStyle, DetailMotionVariants } from '@/entities/common/model/constant';
import { FullMenuClose } from '@/entities/common/ui/full-menu-close';
import { showAlert } from '@/widgets/show-alert';
import { P } from 'node_modules/framer-motion/dist/types.d-Cjd591yU';
export interface LinkPaymentWaitDetailProps {
detailOn: boolean;
@@ -38,12 +40,15 @@ export const LinkPaymentWaitDetail = ({
mid: mid,
requestId: requestId
}
linkPayWaitDetail(detailParam).then((rs: DetailResponse) => {
setTitleInfo(rs.titleInfo)
setPaymentInfo(rs.paymentInfo)
})
}).catch((e: any) => {
if (e.response?.data?.error?.message) {
showAlert(e.response?.data?.error?.message);
return;
}
});
}
const deletePayment = () => {
@@ -53,11 +58,21 @@ export const LinkPaymentWaitDetail = ({
}
linkPayWaitDelete(deleteParam)
.then((rs) => {
callDetail();
snackBar(t('additionalService.linkPayment.deleteSuccess'))
if (rs.status) {
callDetail();
snackBar(t('additionalService.linkPayment.deleteSuccess'))
} else {
const errorMessage = rs.error?.message || t('additionalService.linkPayment.deleteSuccess');
snackBar(`[${t('common.failed')}] ${errorMessage}`);
}
})
.catch((error) => {
snackBar(`[${t('common.failed')}] ${error?.response?.data?.message}`)
console.log(error)
if (error.response?.data?.error?.root !== "SystemErrorCode") {
snackBar(`[${t('common.failed')}] ${error?.response?.data?.error?.message}`)
} else {
showAlert(`[${t('common.failed')}] ${error?.response?.data?.error?.message}`)
}
});
}
@@ -89,52 +104,52 @@ export const LinkPaymentWaitDetail = ({
};
useEffect(() => {
if(!!mid && !!requestId){
if (!!mid && !!requestId) {
callDetail();
}
}, [mid, requestId]);
return (
<>
<motion.div
className="full-menu-modal"
<motion.div
className="full-menu-modal"
initial="hidden"
animate={ (detailOn)? 'visible': 'hidden' }
variants={ DetailMotionVariants }
transition={ DetailMotionDuration }
style={ DetailMotionStyle }
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.linkPayment.waitDetailTitle') }</div>
<div className="full-menu-title center">{t('additionalService.linkPayment.waitDetailTitle')}</div>
<div className="full-menu-actions">
<FullMenuClose
addClass="full-menu-close"
onClickToCallback={ onClickToClose }
onClickToCallback={onClickToClose}
></FullMenuClose>
</div>
</div>
<div className="pay-top">
<TitleInfoWrap
additionalServiceCategory={AdditionalServiceCategory.LinkPaymentWait}
titleInfo={titleInfo}
></TitleInfoWrap>
</div>
<div className="pay-detail">
<div className="detail-divider"></div>
<PaymentInfoWrap
additionalServiceCategory={AdditionalServiceCategory.LinkPaymentWait}
paymentInfo={paymentInfo}
></PaymentInfoWrap>
</div>
<div className="pay-top">
<TitleInfoWrap
additionalServiceCategory={AdditionalServiceCategory.LinkPaymentWait}
titleInfo={titleInfo}
></TitleInfoWrap>
</div>
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={() => onClickToCancel()}
disabled={paymentInfo?.processStatus !== LinkPaymentProcessStatus.SEND_REQUEST}
>{t('additionalService.linkPayment.delete')}</button>
<div className="pay-detail">
<div className="detail-divider"></div>
<PaymentInfoWrap
additionalServiceCategory={AdditionalServiceCategory.LinkPaymentWait}
paymentInfo={paymentInfo}
></PaymentInfoWrap>
</div>
</div>
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={() => onClickToCancel()}
disabled={paymentInfo?.processStatus !== LinkPaymentProcessStatus.SEND_REQUEST}
>{t('additionalService.linkPayment.delete')}</button>
</div>
</motion.div>
</>
)

View File

@@ -9,6 +9,7 @@ import { DetailMotionDuration, DetailMotionStyle, DetailMotionVariants } from '@
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';
import { showAlert } from '@/widgets/show-alert';
export interface PayoutDetailProps {
@@ -39,9 +40,13 @@ export const PayoutDetail = ({
tid: tid,
mid: mid,
};
extensionPayoutDetail(params).then((rs: ExtensionPayoutDetailResponse) => {
setDetail(rs);
}).catch((e: any) => {
if (e.response?.data?.error?.message) {
showAlert(e.response?.data?.error?.message);
return;
}
});
}
@@ -121,71 +126,71 @@ export const PayoutDetail = ({
></FullMenuClose>
</div>
</div>
<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 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="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 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>
<DownloadTypeBottomSheet
bottomSheetOn={downloadTypeBottomSheetOn}

View File

@@ -65,8 +65,8 @@ export const PayoutFilter = ({
const [filterMid, setFilterMid] = useState<string>(mid);
const [filterSearchDateType, setFilterSearchDateType] = useState<PayoutSearchDateType>(searchDateType);
const [filterFromDate, setFilterFromDate] = useState<string>(moment(fromDate).format('YYYY.MM.DD'));
const [filterToDate, setFilterToDate] = useState<string>(moment(toDate).format('YYYY.MM.DD'));
const [filterFromDate, setFilterFromDate] = useState<string>(moment(fromDate).format('YYYYMMDD'));
const [filterToDate, setFilterToDate] = useState<string>(moment(toDate).format('YYYYMMDD'));
const [filterStatus, setFilterStatus] = useState<PayoutDisbursementStatus>(status);
const [filterMinAmount, setFilterMinAmount] = useState<number | undefined>(minAmount);
const [filterMaxAmount, setFilterMaxAmount] = useState<number | undefined>(maxAmount);

View File

@@ -3,8 +3,8 @@ import { useTranslation } from 'react-i18next';
import { IMAGE_ROOT } from '@/shared/constants/common';
import { SmsPaymentDetailResendProps } from '../../../additional-service/model/sms-payment/types';
import { useExtensionSmsResendMutation } from '../../api/sms-payment/use-extension-sms-resend-mutation';
import appBridge from '@/shared/lib/appBridge';
import { snackBar } from '@/shared/lib';
import { showAlert } from '@/widgets/show-alert';
export const SmsPaymentDetailResend = ({
bottomSmsPaymentDetailResendOn,
@@ -19,7 +19,7 @@ export const SmsPaymentDetailResend = ({
visible: { y: '0%' },
};
const {mutateAsync : resendMessage } = useExtensionSmsResendMutation();
const { mutateAsync: resendMessage } = useExtensionSmsResendMutation();
const onClickResend = () => {
// sendMessage가 없으면 재발송 불가
@@ -37,9 +37,13 @@ export const SmsPaymentDetailResend = ({
} else {
snackBar(t('additionalService.sms.sendFailed', { message: rs.error?.message }))
}
}).catch((error) => {
snackBar(t('additionalService.sms.sendFailed', { message: error?.response?.data?.message || error?.response?.data?.error?.message }) || t('additionalService.sms.sendFailedGeneric'))
setBottomSmsPaymentDetailResendOn(false)
}).catch((e: any) => {
console.log(e)
if (e.response?.data?.error?.message) {
showAlert(e.response?.data?.error?.message);
setBottomSmsPaymentDetailResendOn(false)
return;
}
});
}
@@ -50,14 +54,14 @@ export const SmsPaymentDetailResend = ({
return (
<>
{ bottomSmsPaymentDetailResendOn &&
{bottomSmsPaymentDetailResendOn &&
<div className="bg-dim"></div>
}
<motion.div
<motion.div
className="bottomsheet"
initial="hidden"
animate={ (bottomSmsPaymentDetailResendOn)? 'visible': 'hidden' }
variants={ variants }
animate={(bottomSmsPaymentDetailResendOn) ? 'visible' : 'hidden'}
variants={variants}
transition={{ duration: 0.5 }}
>
<div className="bottomsheet-header">
@@ -68,9 +72,9 @@ export const SmsPaymentDetailResend = ({
type="button"
>
<img
src={ IMAGE_ROOT + '/ico_close.svg' }
src={IMAGE_ROOT + '/ico_close.svg'}
alt={t('common.close')}
onClick={ () => onClickToClose() }
onClick={() => onClickToClose()}
/>
</button>
</div>