- 부가서비스 링크결제 : 기간연장,링크 중단 활성화,비활성화 조건 적용, 체크박스 Action 추가
This commit is contained in:
@@ -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) => {
|
||||
|
||||
@@ -157,7 +157,7 @@ export const LinkPaymentDetailPage = () => {
|
||||
<button
|
||||
className="btn-50 btn-blue flex-1"
|
||||
onClick={() => onClickToSeparateApproval()}
|
||||
disabled={false}
|
||||
disabled={detailExposure}
|
||||
>분리승인 상세</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -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 = () => {
|
||||
<div className="approval-cards-wrapper">
|
||||
{items.map((item, index) => {
|
||||
const itemId = item.subRequestId || `item-${index}`;
|
||||
const isDisabled = item.paymentStatus !== 'PENDING';
|
||||
return (
|
||||
<div key={itemId} className={`approval-card ${selectedItems.includes(itemId) ? 'selected' : ''}`}>
|
||||
<div className="card-header">
|
||||
<input
|
||||
type="checkbox"
|
||||
id={`checkbox-${itemId}`}
|
||||
name={`checkbox-${itemId}`}
|
||||
checked={selectedItems.includes(itemId)}
|
||||
onChange={() => handleCheckboxChange(itemId)}
|
||||
className="card-checkbox"
|
||||
/>
|
||||
<span className="card-tag">[{item.type}]</span>
|
||||
<span className="card-tid">{item.moid}</span>
|
||||
</div>
|
||||
<div className="card-body">
|
||||
<ul className="info-list">
|
||||
<li>
|
||||
<span className="label">• 거래금액:</span>
|
||||
<span className="value">{item.amount.toLocaleString()}</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className="label">• 결제상태:</span>
|
||||
<span className="value">{item.paymentStatusName}</span>
|
||||
</li>
|
||||
{item.type !== LinkPaymentSeparateType.MAIN && (
|
||||
<>
|
||||
<li>
|
||||
<span className="label">• 유효기간:</span>
|
||||
<span className="value">
|
||||
{item.paymentLimitDate
|
||||
? moment(item.paymentLimitDate, 'YYYYMMDD').format('YYYY/MM/DD')
|
||||
: '-'
|
||||
}
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className="label">• 연장횟수:</span>
|
||||
<span className="value">{item.paymentLimitCount}</span>
|
||||
</li>
|
||||
</>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="card-footer">
|
||||
<div className="period-selector">
|
||||
<label>연장기간</label>
|
||||
<select
|
||||
value={extendPeriods[itemId] || ''}
|
||||
onChange={(e) => handleExtendPeriodChange(itemId, e.target.value)}
|
||||
disabled={item.type === LinkPaymentSeparateType.MAIN}
|
||||
>
|
||||
<option value="">미설정</option>
|
||||
{[1, 2, 3, 4, 5, 6, 7].map(days => {
|
||||
const baseDate = moment(item.paymentLimitDate, 'YYYYMMDD');
|
||||
const targetDate = baseDate.clone().add(days, 'days').format('YYYY/MM/DD');
|
||||
return <option key={days} value={days.toString()}>{targetDate}</option>;
|
||||
})}
|
||||
</select>
|
||||
<div key={itemId} className={`approval-card ${selectedItems.includes(itemId) ? 'selected' : ''} ${isDisabled ? 'disabled' : ''}`}>
|
||||
<div className="card-header">
|
||||
<input
|
||||
type="checkbox"
|
||||
id={`checkbox-${itemId}`}
|
||||
name={`checkbox-${itemId}`}
|
||||
checked={selectedItems.includes(itemId)}
|
||||
onChange={() => handleCheckboxChange(itemId)}
|
||||
className="card-checkbox"
|
||||
disabled={item.paymentStatus !== 'PENDING'}
|
||||
/>
|
||||
<span className="card-tag">[{item.type}]</span>
|
||||
<span className="card-tid">{item.moid}</span>
|
||||
</div>
|
||||
<div className="card-body">
|
||||
<ul className="info-list">
|
||||
<li>
|
||||
<span className="label">• 거래금액:</span>
|
||||
<span className="value">{item.amount.toLocaleString()}</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className="label">• 결제상태:</span>
|
||||
<span className="value">{item.paymentStatusName}</span>
|
||||
</li>
|
||||
{item.type !== LinkPaymentSeparateType.MAIN && (
|
||||
<>
|
||||
<li>
|
||||
<span className="label">• 유효기간:</span>
|
||||
<span className="value">
|
||||
{item.paymentLimitDate
|
||||
? moment(item.paymentLimitDate, 'YYYYMMDD').format('YYYY/MM/DD')
|
||||
: '-'
|
||||
}
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className="label">• 연장횟수:</span>
|
||||
<span className="value">{item.paymentLimitCount}</span>
|
||||
</li>
|
||||
</>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="card-footer">
|
||||
<div className="period-selector">
|
||||
<label>연장기간</label>
|
||||
<select
|
||||
value={extendPeriods[itemId] || ''}
|
||||
onChange={(e) => handleExtendPeriodChange(itemId, e.target.value)}
|
||||
disabled={item.type === LinkPaymentSeparateType.MAIN || item.paymentStatus !== "PENDING" || !canExtendPeriod(item)}
|
||||
>
|
||||
<option value="">
|
||||
{item.type === LinkPaymentSeparateType.MAIN
|
||||
? '-'
|
||||
: !canExtendPeriod(item)
|
||||
? '-'
|
||||
: '미설정'}
|
||||
</option>
|
||||
{canExtendPeriod(item) && [1, 2, 3, 4, 5, 6, 7].map(days => {
|
||||
const baseDate = moment(item.paymentLimitDate, 'YYYYMMDD');
|
||||
const targetDate = baseDate.clone().add(days, 'days').format('YYYY/MM/DD');
|
||||
return <option key={days} value={days.toString()}>{targetDate}</option>;
|
||||
})}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
@@ -306,7 +425,7 @@ export const LinkPaymentSeparateApprovalPage = () => {
|
||||
<button
|
||||
className="btn-50 btn-blue flex-1"
|
||||
onClick={onClickToSendLink}
|
||||
disabled={selectedItems.length === 0}
|
||||
disabled={!isLinkBreadkEnabled()}
|
||||
>링크중단
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user