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:
@@ -8,6 +8,7 @@ import { PATHS } from '@/shared/constants/paths';
|
||||
import { useExtensionLinkPayRequestMutation } from '@/entities/additional-service/api/link-payment/use-extension-link-pay-request-mutation';
|
||||
import { ExtensionLinkPayRequestParams, ExtensionLinkPayRequestResponse, LinkPaymentFormData } from '@/entities/additional-service/model/link-pay/types';
|
||||
import { snackBar } from '@/shared/lib';
|
||||
import { showAlert } from '@/widgets/show-alert';
|
||||
|
||||
export const LinkPaymentApplyConfirmPage = () => {
|
||||
const { t } = useTranslation();
|
||||
@@ -60,11 +61,14 @@ export const LinkPaymentApplyConfirmPage = () => {
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
// 네트워크 에러 등 예외 상황
|
||||
const errorMessage = error?.response?.data?.error?.message ||
|
||||
error?.message ||
|
||||
t('additionalService.linkPayment.requestError');
|
||||
snackBar(`[${t('common.failed')}] ${errorMessage}`);
|
||||
if (error.response?.data?.error?.root !== "SystemErrorCode") {
|
||||
snackBar(`[${t('common.failed')}] ${errorMessage}`);
|
||||
} else {
|
||||
showAlert(`[${t('common.failed')}] ${errorMessage}`)
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,179 +0,0 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { PATHS } from '@/shared/constants/paths';
|
||||
import { useLocation } from 'react-router';
|
||||
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
||||
import { HeaderType } from '@/entities/common/model/types';
|
||||
import {
|
||||
useSetOnBack,
|
||||
useSetHeaderTitle,
|
||||
useSetHeaderType,
|
||||
useSetFooterMode
|
||||
} from '@/widgets/sub-layout/use-sub-layout';
|
||||
import { overlay } from 'overlay-kit';
|
||||
import { Dialog } from '@/shared/ui/dialogs/dialog';
|
||||
import { useExtensionLinkPayHistoryDetailMutation } from '@/entities/additional-service/api/link-payment/use-extension-link-pay-history-detail-mutation';
|
||||
import { AdditionalServiceCategory, DetailInfo, DetailResponse, PaymentInfo, TitleInfo } from '@/entities/additional-service/model/types';
|
||||
import { TitleInfoWrap } from '@/entities/additional-service/ui/info-wrap/title-info-wrap';
|
||||
import { PaymentInfoWrap } from '@/entities/additional-service/ui/info-wrap/payment-info-wrap';
|
||||
import { DetailInfoWrap } from '@/entities/additional-service/ui/info-wrap/detail-info-wrap';
|
||||
import { useExtensionLinkPayHistoryResendMutation } from '@/entities/additional-service/api/link-payment/use-extension-link-pay-history-resend-mutation';
|
||||
import { ExtensionLinkPayHistoryDetailParams, ExtensionLinkPayHistoryResendParams } from '@/entities/additional-service/model/link-pay/types';
|
||||
import { snackBar } from '@/shared/lib';
|
||||
import moment from 'moment';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const LinkPaymentDetailPage = () => {
|
||||
const { t } = useTranslation();
|
||||
const { navigate } = useNavigate();
|
||||
const location = useLocation();
|
||||
|
||||
const { mid, tid, requestId, subReqId } = location.state || {};
|
||||
|
||||
const [titleInfo, setTitleInfo] = useState<TitleInfo>();
|
||||
const [detailInfo, setDetailInfo] = useState<DetailInfo>();
|
||||
const [paymentInfo, setPaymentInfo] = useState<PaymentInfo>();
|
||||
const [detailExposure, setDetailExposure] = useState<boolean>(false);
|
||||
const [showPayment, setShowPayment] = useState<boolean>(false);
|
||||
|
||||
useSetHeaderTitle(t('additionalService.linkPayment.detailTitle'));
|
||||
useSetHeaderType(HeaderType.RightClose);
|
||||
useSetOnBack(() => {
|
||||
navigate(-1); // Go back using browser history
|
||||
});
|
||||
useSetFooterMode(false);
|
||||
|
||||
const { mutateAsync: linkPayHistoryDetail } = useExtensionLinkPayHistoryDetailMutation();
|
||||
const { mutateAsync: linkPayHistoryResend } = useExtensionLinkPayHistoryResendMutation();
|
||||
|
||||
// Query detail information
|
||||
const callDetail = () => {
|
||||
let detailParam: ExtensionLinkPayHistoryDetailParams = {
|
||||
mid: mid,
|
||||
requestId: requestId,
|
||||
subReqId: subReqId
|
||||
}
|
||||
linkPayHistoryDetail(detailParam).then((rs: DetailResponse) => {
|
||||
console.log("Detail Info: ", rs)
|
||||
setTitleInfo(rs.titleInfo)
|
||||
setDetailInfo(rs.detailInfo)
|
||||
setPaymentInfo(rs.paymentInfo)
|
||||
setDetailExposure(rs.detailExposure ?? false)
|
||||
})
|
||||
}
|
||||
|
||||
// Resend API
|
||||
const resendPayment = () => {
|
||||
let resendParam: ExtensionLinkPayHistoryResendParams = {
|
||||
mid: mid,
|
||||
requestId: requestId,
|
||||
sendMethod: paymentInfo?.sendMethod
|
||||
}
|
||||
linkPayHistoryResend(resendParam)
|
||||
.then((response) => {
|
||||
if (response.status) {
|
||||
snackBar(t('additionalService.linkPayment.resendSuccess'));
|
||||
callDetail();
|
||||
} else {
|
||||
const errorMessage = response.error?.message || t('additionalService.linkPayment.resendFailed');
|
||||
snackBar(`[${t('common.failed')}] ${errorMessage}`);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
const errorMessage = error?.response?.data?.error?.message ||
|
||||
error?.message ||
|
||||
t('additionalService.linkPayment.resendError');
|
||||
snackBar(`[${t('common.failed')}] ${errorMessage}`);
|
||||
});
|
||||
}
|
||||
|
||||
const onClickToResend = () => {
|
||||
let msg = t('additionalService.linkPayment.resendConfirm');
|
||||
|
||||
overlay.open(({
|
||||
isOpen,
|
||||
close,
|
||||
unmount
|
||||
}) => {
|
||||
return (
|
||||
<Dialog
|
||||
afterLeave={unmount}
|
||||
open={isOpen}
|
||||
onClose={close}
|
||||
onConfirmClick={() => resendPayment()}
|
||||
message={msg}
|
||||
buttonLabel={[t('common.cancel'), t('common.confirm')]}
|
||||
/>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const onClickToSeparateApproval = () => {
|
||||
navigate(PATHS.additionalService.linkPayment.separateApproval, {
|
||||
state: { mid, requestId }
|
||||
});
|
||||
};
|
||||
|
||||
// Check if resend button should be enabled
|
||||
const isResendEnabled = () => {
|
||||
// paymentStatus must be "ACTIVE"
|
||||
if (paymentInfo?.paymentStatus !== 'ACTIVE') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// paymentLimitDate must not have passed today's date
|
||||
if (paymentInfo?.paymentLimitDate) {
|
||||
const limitDate = moment(paymentInfo.paymentLimitDate, 'YYYYMMDD');
|
||||
const today = moment().startOf('day');
|
||||
return limitDate.isSameOrAfter(today);
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
callDetail();
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<main>
|
||||
<div className="tab-content">
|
||||
<div className="tab-pane sub active">
|
||||
<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: '85px' }}>
|
||||
<button
|
||||
className="btn-50 btn-blue flex-1"
|
||||
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>
|
||||
</div>
|
||||
</main >
|
||||
</>
|
||||
)
|
||||
};
|
||||
@@ -1,124 +0,0 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { PATHS } from '@/shared/constants/paths';
|
||||
import { useLocation } from 'react-router';
|
||||
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
||||
import { HeaderType } from '@/entities/common/model/types';
|
||||
import {
|
||||
useSetOnBack,
|
||||
useSetHeaderTitle,
|
||||
useSetHeaderType,
|
||||
useSetFooterMode
|
||||
} from '@/widgets/sub-layout/use-sub-layout';
|
||||
import { overlay } from 'overlay-kit';
|
||||
import { Dialog } from '@/shared/ui/dialogs/dialog';
|
||||
import { TitleInfoWrap } from '@/entities/additional-service/ui/info-wrap/title-info-wrap';
|
||||
import { AdditionalServiceCategory, DetailResponse, PaymentInfo, TitleInfo } from '@/entities/additional-service/model/types';
|
||||
import { useExtensionLinkPayWaitDetailMutation, } from '@/entities/additional-service/api/link-payment/use-extension-link-pay-wait-detail-mutation';
|
||||
import { PaymentInfoWrap } from '@/entities/additional-service/ui/info-wrap/payment-info-wrap';
|
||||
import { useExtensionLinkPayWaitDeleteMutation } from '@/entities/additional-service/api/link-payment/use-extension-link-pay-wait-delete-mutation';
|
||||
import { ExtensionLinkPayWaitDeleteParams, ExtensionLinkPayWaitDetailParams, LinkPaymentProcessStatus } from '@/entities/additional-service/model/link-pay/types';
|
||||
import { snackBar } from '@/shared/lib';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const LinkPaymentWaitDetailPage = () => {
|
||||
const { t } = useTranslation();
|
||||
const { navigate } = useNavigate();
|
||||
const location = useLocation();
|
||||
const { mid, requestId } = location.state || {};
|
||||
const [titleInfo, setTitleInfo] = useState<TitleInfo>();
|
||||
const [paymentInfo, setPaymentInfo] = useState<PaymentInfo>();
|
||||
|
||||
useSetHeaderTitle(t('additionalService.linkPayment.waitDetailTitle'));
|
||||
useSetHeaderType(HeaderType.RightClose);
|
||||
useSetOnBack(() => {
|
||||
navigate(PATHS.additionalService.linkPayment.pendingSend);
|
||||
});
|
||||
useSetFooterMode(false);
|
||||
|
||||
const { mutateAsync: linkPayWaitDetail } = useExtensionLinkPayWaitDetailMutation();
|
||||
const { mutateAsync: linkPayWaitDelete } = useExtensionLinkPayWaitDeleteMutation();
|
||||
|
||||
const callDetail = () => {
|
||||
let detailParam: ExtensionLinkPayWaitDetailParams = {
|
||||
mid: mid,
|
||||
requestId: requestId
|
||||
}
|
||||
|
||||
linkPayWaitDetail(detailParam).then((rs: DetailResponse) => {
|
||||
setTitleInfo(rs.titleInfo)
|
||||
setPaymentInfo(rs.paymentInfo)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
const deletePayment = () => {
|
||||
let deleteParam: ExtensionLinkPayWaitDeleteParams = {
|
||||
mid: mid,
|
||||
requestId: requestId
|
||||
}
|
||||
linkPayWaitDelete(deleteParam)
|
||||
.then((rs) => {
|
||||
callDetail();
|
||||
snackBar(t('additionalService.linkPayment.deleteSuccess'))
|
||||
})
|
||||
.catch((error) => {
|
||||
snackBar(`[${t('common.failed')}] ${error?.response?.data?.message}`)
|
||||
});
|
||||
}
|
||||
|
||||
const onClickToCancel = () => {
|
||||
let msg = t('additionalService.linkPayment.deleteConfirm');
|
||||
|
||||
overlay.open(({
|
||||
isOpen,
|
||||
close,
|
||||
unmount
|
||||
}) => {
|
||||
return (
|
||||
<Dialog
|
||||
afterLeave={unmount}
|
||||
open={isOpen}
|
||||
onClose={close}
|
||||
onConfirmClick={() => deletePayment()}
|
||||
message={msg}
|
||||
buttonLabel={[t('common.cancel'), t('common.confirm')]}
|
||||
/>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
callDetail();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<main>
|
||||
<div className="tab-content">
|
||||
<div className="tab-pane sub active">
|
||||
<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>
|
||||
<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>
|
||||
</div>
|
||||
</main >
|
||||
</>
|
||||
)
|
||||
};
|
||||
Reference in New Issue
Block a user