diff --git a/src/pages/additional-service/link-payment/apply/link-payment-apply-confirm-page.tsx b/src/pages/additional-service/link-payment/apply/link-payment-apply-confirm-page.tsx index e6e011d..4381a08 100644 --- a/src/pages/additional-service/link-payment/apply/link-payment-apply-confirm-page.tsx +++ b/src/pages/additional-service/link-payment/apply/link-payment-apply-confirm-page.tsx @@ -52,17 +52,9 @@ export const LinkPaymentApplyConfirmPage = () => { if (rs.status) { navigate(PATHS.additionalService.linkPayment.confirmSuccess); } else { - // 응답은 성공했지만 status가 false인 경우 - const validationErrors = rs.error?.details?.validationErrors; - if (validationErrors) { - // validation 에러 메시지들을 수집 - const errorMessages = Object.values(validationErrors).join('\n'); - snackBar(`[실패] ${errorMessages}`); - } else { - // 일반 에러 메시지 - const errorMessage = rs.error?.message || '요청을 처리할 수 없습니다.'; - snackBar(`[실패] ${errorMessage}`); - } + // 일반 에러 메시지 + const errorMessage = rs.error?.message || '요청을 처리할 수 없습니다.'; + snackBar(`[실패] ${errorMessage}`); } }) .catch((error) => { diff --git a/src/pages/additional-service/link-payment/link-payment-detail-page.tsx b/src/pages/additional-service/link-payment/link-payment-detail-page.tsx index 61c66a9..e67cf12 100644 --- a/src/pages/additional-service/link-payment/link-payment-detail-page.tsx +++ b/src/pages/additional-service/link-payment/link-payment-detail-page.tsx @@ -157,7 +157,7 @@ export const LinkPaymentDetailPage = () => { diff --git a/src/pages/additional-service/link-payment/separate-approval/link-payment-separate-approval-page.tsx b/src/pages/additional-service/link-payment/separate-approval/link-payment-separate-approval-page.tsx index 57d96ad..6bb1e67 100644 --- a/src/pages/additional-service/link-payment/separate-approval/link-payment-separate-approval-page.tsx +++ b/src/pages/additional-service/link-payment/separate-approval/link-payment-separate-approval-page.tsx @@ -52,11 +52,63 @@ export const LinkPaymentSeparateApprovalPage = () => { const handleCheckboxChange = (subRequestId: string) => { setSelectedItems(prev => { - if (prev.includes(subRequestId)) { - return prev.filter(id => id !== subRequestId); - } else { - return [...prev, subRequestId]; + // 현재 클릭한 item 찾기 + const target = items.find(i => i.subRequestId === subRequestId) + || items.find((_, idx) => `item-${idx}` === subRequestId); + if (!target) return prev; + + // 동일한 requestId를 가진 MAIN, SUB 그룹 가져오기 + const sameRequestIdItems = items.filter(i => i.requestId === target.requestId); + const mainItem = sameRequestIdItems.find(i => i.type === LinkPaymentSeparateType.MAIN); + // PENDING 상태인 SUB만 필터링 + const subItems = sameRequestIdItems.filter(i => + i.type === LinkPaymentSeparateType.SUB && i.paymentStatus === 'PENDING' + ); + + const mainId = mainItem?.subRequestId || (mainItem ? `item-${items.indexOf(mainItem)}` : ''); + const subIds = subItems.map(i => i.subRequestId || `item-${items.indexOf(i)}`); + + // ----------------------------- + // MAIN 클릭 시 + // ----------------------------- + if (target.type === LinkPaymentSeparateType.MAIN) { + const isMainChecked = prev.includes(mainId); + if (isMainChecked) { + // MAIN 해제 → PENDING인 SUB만 해제 + return prev.filter(id => ![mainId, ...subIds].includes(id)); + } else { + // MAIN 체크 → PENDING인 SUB만 추가 + return [...new Set([...prev, mainId, ...subIds])]; + } } + + // ----------------------------- + // SUB 클릭 시 + // ----------------------------- + const isChecked = prev.includes(subRequestId); + let updated: string[] = []; + + if (isChecked) { + // SUB 해제 + updated = prev.filter(id => id !== subRequestId); + + // 해제 후 남은 PENDING SUB 중 하나라도 빠져 있으면 MAIN도 해제 + const allPendingSubsChecked = subIds.every(id => updated.includes(id)); + if (!allPendingSubsChecked && mainId) { + updated = updated.filter(id => id !== mainId); + } + } else { + // SUB 체크 + updated = [...prev, subRequestId]; + + // 모든 PENDING SUB 체크되면 MAIN도 자동 체크 + const allPendingSubsChecked = subIds.every(id => updated.includes(id)); + if (allPendingSubsChecked && mainId) { + updated = [...new Set([...updated, mainId])]; + } + } + + return updated; }); }; @@ -67,12 +119,60 @@ export const LinkPaymentSeparateApprovalPage = () => { })); }; - // 기간연장 버튼 활성화 조건: 선택된 항목이 있고, 모든 선택된 항목의 연장기간이 설정됨 - const isExtendButtonEnabled = () => { - if (selectedItems.length === 0) return false; - return selectedItems.every(id => extendPeriods[id] && extendPeriods[id] !== ''); + // 각 SUB 항목이 연장기간 설정 가능한지 체크 + const canExtendPeriod = (item: ExtensionLinkPaySeparateDetailItem) => { + const today = moment().format('YYYYMMDD'); + const paymentLimitDate = item.paymentLimitDate || ''; + const paymentLimitCount = item.paymentLimitCount || 0; + + // 연장횟수 < 3 이고 유효일자 >= 조회일자 + return paymentLimitCount < 3 && paymentLimitDate >= today; }; + // 각 SUB 항목이 링크중단 가능한지 체크 + const canLinkBreak = (item: ExtensionLinkPaySeparateDetailItem) => { + const today = moment().format('YYYYMMDD'); + const paymentLimitDate = item.paymentLimitDate || ''; + + // 유효일자 >= 조회일자 + return paymentLimitDate >= today; + }; + + const isExtendButtonEnabled = () => { + // MAIN 제외, 체크된 SUB 중에서 + const checkedSubs = items.filter((i, index) => { + const itemId = i.subRequestId || `item-${index}`; + return i.type === LinkPaymentSeparateType.SUB && + selectedItems.includes(itemId) && + i.paymentStatus === 'PENDING'; + }); + + // 체크된 SUB가 없으면 비활성화 + if (checkedSubs.length === 0) return false; + + // 모든 체크된 SUB가 연장 가능하고, 연장기간이 설정되어 있어야 함 + return checkedSubs.every((sub) => { + const itemId = sub.subRequestId || `item-${items.indexOf(sub)}`; + return canExtendPeriod(sub) && extendPeriods[itemId] && extendPeriods[itemId] !== ''; + }); + }; + + const isLinkBreadkEnabled = () => { + // MAIN 제외, 체크된 SUB 중에서 + const checkedSubs = items.filter((i, index) => { + const itemId = i.subRequestId || `item-${index}`; + return i.type === LinkPaymentSeparateType.SUB && + selectedItems.includes(itemId) && + i.paymentStatus === 'PENDING'; + }); + + // 체크된 SUB가 없으면 비활성화 + if (checkedSubs.length === 0) return false; + + // 모든 체크된 SUB가 링크중단 가능해야 함 + return checkedSubs.every(sub => canLinkBreak(sub)); + } + const onClickToValidityPeriod = () => { // 기간연장 바텀시트 열기 setExtendedPeriodBottomSheetOn(true); @@ -94,8 +194,13 @@ export const LinkPaymentSeparateApprovalPage = () => { return; } - // 모든 선택된 항목들의 연장 기간이 설정되었는지 확인 - const allHaveExtendPeriod = selectedItems.every(id => extendPeriods[id]); + // MAIN을 제외한 선택된 SUB 항목들의 연장 기간이 설정되었는지 확인 + const selectedSubItems = selectedItems.filter(id => { + const item = items.find(i => (i.subRequestId || `item-${items.indexOf(i)}`) === id); + return item && item.type === LinkPaymentSeparateType.SUB; + }); + + const allHaveExtendPeriod = selectedSubItems.every(id => extendPeriods[id]); if (!allHaveExtendPeriod) { setErrorMessage('모든 선택된 항목의 연장 기간을 선택해주세요.'); @@ -103,15 +208,15 @@ export const LinkPaymentSeparateApprovalPage = () => { return; } - // 첫 번째 선택된 항목의 연장 기간 사용 (모든 항목이 같은 기간으로 연장) - const firstSelectedId = selectedItems[0] as string; - const extendDays = extendPeriods[firstSelectedId] as string; + // 첫 번째 선택된 SUB 항목의 연장 기간 사용 (모든 항목이 같은 기간으로 연장) + const firstSelectedSubId = selectedSubItems[0] as string; + const extendDays = extendPeriods[firstSelectedSubId] as string; // 연장 날짜 계산 (오늘 날짜 + 연장일수) const extendDate = moment().add(parseInt(extendDays), 'days').format('YYYYMMDD'); - // selectedItems를 API 형식으로 변환 - const selectedItemsData = selectedItems.map(itemId => { + // MAIN을 제외한 SUB 항목만 API 형식으로 변환 + const selectedItemsData = selectedSubItems.map(itemId => { const item = items.find(i => (i.subRequestId || `item-${items.indexOf(i)}`) === itemId); return { type: item?.type || '', @@ -157,7 +262,13 @@ export const LinkPaymentSeparateApprovalPage = () => { return; } - const selectedItemsData = selectedItems.map(itemId => { + // MAIN을 제외한 SUB 항목만 필터링 + const selectedSubItems = selectedItems.filter(id => { + const item = items.find(i => (i.subRequestId || `item-${items.indexOf(i)}`) === id); + return item && item.type === LinkPaymentSeparateType.SUB; + }); + + const selectedItemsData = selectedSubItems.map(itemId => { const item = items.find(i => (i.subRequestId || `item-${items.indexOf(i)}`) === itemId); return { type: item?.type || '', @@ -230,67 +341,75 @@ export const LinkPaymentSeparateApprovalPage = () => {
{items.map((item, index) => { const itemId = item.subRequestId || `item-${index}`; + const isDisabled = item.paymentStatus !== 'PENDING'; return ( -
-
- handleCheckboxChange(itemId)} - className="card-checkbox" - /> - [{item.type}] - {item.moid} -
-
-
    -
  • - • 거래금액: - {item.amount.toLocaleString()} -
  • -
  • - • 결제상태: - {item.paymentStatusName} -
  • - {item.type !== LinkPaymentSeparateType.MAIN && ( - <> -
  • - • 유효기간: - - {item.paymentLimitDate - ? moment(item.paymentLimitDate, 'YYYYMMDD').format('YYYY/MM/DD') - : '-' - } - -
  • -
  • - • 연장횟수: - {item.paymentLimitCount} -
  • - - )} -
-
-
-
- - +
+
+ handleCheckboxChange(itemId)} + className="card-checkbox" + disabled={item.paymentStatus !== 'PENDING'} + /> + [{item.type}] + {item.moid} +
+
+
    +
  • + • 거래금액: + {item.amount.toLocaleString()} +
  • +
  • + • 결제상태: + {item.paymentStatusName} +
  • + {item.type !== LinkPaymentSeparateType.MAIN && ( + <> +
  • + • 유효기간: + + {item.paymentLimitDate + ? moment(item.paymentLimitDate, 'YYYYMMDD').format('YYYY/MM/DD') + : '-' + } + +
  • +
  • + • 연장횟수: + {item.paymentLimitCount} +
  • + + )} +
+
+
+
+ + +
-
); })}
@@ -306,7 +425,7 @@ export const LinkPaymentSeparateApprovalPage = () => {
diff --git a/src/pages/additional-service/link-payment/separate-approval/link-payment-separate-approval-success-page.tsx b/src/pages/additional-service/link-payment/separate-approval/link-payment-separate-approval-success-page.tsx index d5d5711..3699a61 100644 --- a/src/pages/additional-service/link-payment/separate-approval/link-payment-separate-approval-success-page.tsx +++ b/src/pages/additional-service/link-payment/separate-approval/link-payment-separate-approval-success-page.tsx @@ -1,6 +1,4 @@ import { motion } from 'framer-motion'; -import { useNavigate } from '@/shared/lib/hooks/use-navigate'; -import { PATHS } from "@/shared/constants/paths"; import { FilterMotionDuration, FilterMotionStyle, diff --git a/src/shared/ui/assets/css/style-fix.css b/src/shared/ui/assets/css/style-fix.css index 9b4648e..3e865ee 100644 --- a/src/shared/ui/assets/css/style-fix.css +++ b/src/shared/ui/assets/css/style-fix.css @@ -233,6 +233,29 @@ main.home-main{ box-shadow: 0 4px 12px rgba(62, 106, 252, 0.2); } +/* PENDING이 아닌 항목 비활성화 스타일 */ +.approval-card.disabled { + opacity: 0.5; + background: var(--color-F9F9F9); + pointer-events: none; +} + +.approval-card.disabled .card-checkbox { + cursor: not-allowed; + background-color: var(--color-E6E6E6); + border-color: var(--color-CCCCCC); +} + +.approval-card.disabled .card-tid, +.approval-card.disabled .info-list .value { + color: var(--color-999999); +} + +.approval-card.disabled .period-selector select { + background-color: var(--color-F3F3F3); + cursor: not-allowed; +} + .approval-card .card-checkbox { display: block !important; position: absolute;