- 부가서비스 각 요청 페이지 : SnackBar 추가, 양식 수정

This commit is contained in:
HyeonJongKim
2025-10-29 14:33:24 +09:00
parent 5888c2844b
commit 448cdcc9d2
17 changed files with 462 additions and 334 deletions

View File

@@ -15,12 +15,14 @@ import { overlay } from 'overlay-kit';
import { Dialog } from '@/shared/ui/dialogs/dialog';
import { useStore } from '@/shared/model/store';
import { snackBar } from '@/shared/lib';
import { NumericFormat, PatternFormat } from 'react-number-format';
export const KeyInPaymentRequestPage = () => {
const { navigate } = useNavigate();
const location = useLocation();
const userMid = useStore.getState().UserStore.mid;
const midOptions = useStore.getState().UserStore.selectOptionsMids
const [mid, setMid] = useState<string>(userMid || '');
const [productName, setProductName] = useState<string>('');
@@ -79,50 +81,24 @@ export const KeyInPaymentRequestPage = () => {
};
keyInApply(keyInApplyParams).then((rs) => {
console.log('결제 응답:', rs);
if (rs.status) {
if (rs.data?.success) {
// 성공: 화면 유지 & 입력 내용 초기화
snackBar("KEY-IN 결제 신청을 성공하였습니다.")
resetForm();
} else {
// 실패: 화면 유지 & 입력 내용 유지
showErrorDialog('결제에 실패했습니다. 입력 내용을 확인해주세요.');
const errorMessage = rs.data?.resultMessage || rs.error?.resultMessage || '결제 신청에 실패했습니다.';
// HTML 태그 제거
const cleanMessage = errorMessage.replace(/<br\s*\/?>/gi, ' ').trim();
snackBar(`[실패] ${cleanMessage}`);
}
}).catch((error) => {
console.error('결제 실패:', error);
showErrorDialog(error?.message || '결제 요청 중 오류가 발생했습니다');
const errorMessage = error?.response?.data?.error?.resultMessage || error?.message || '결제 요청 중 오류가 발생했습니다';
snackBar(`[실패] ${errorMessage}`);
});
};
const showSuccessDialog = () => {
overlay.open(({ isOpen, close, unmount }) => {
return (
<Dialog
afterLeave={unmount}
open={isOpen}
onClose={close}
onConfirmClick={close}
message="결제가 성공적으로 처리되었습니다"
buttonLabel={['확인']}
/>
);
});
};
const showErrorDialog = (errorMessage: string) => {
overlay.open(({ isOpen, close, unmount }) => {
return (
<Dialog
afterLeave={unmount}
open={isOpen}
onClose={close}
onConfirmClick={close}
message={errorMessage}
buttonLabel={['확인']}
/>
);
});
};
const isValidPhoneNumber = (phone: string) => {
const phoneRegex = /^01[0|1|6|7|8|9][0-9]{7,8}$/;
@@ -139,24 +115,17 @@ export const KeyInPaymentRequestPage = () => {
cardNo3.length === 4 && cardNo4.length === 4;
};
const isValidCardExpiration = () => {
if (expMon.length !== 2 || expYear.length !== 2) {
return false;
}
const month = parseInt(expMon);
return month >= 1 && month <= 12;
};
const isFormValid = () => {
return (
mid.trim() !== '' &&
productName.trim() !== '' &&
amount > 0 &&
customerName.trim() !== '' &&
expMon.trim() !== '' &&
expYear.trim() !== '' &&
isValidEmail(email) &&
isValidPhoneNumber(phoneNumber) &&
isValidCardNumber() &&
isValidCardExpiration()
isValidCardNumber()
);
};
@@ -174,11 +143,19 @@ export const KeyInPaymentRequestPage = () => {
<div className="billing-row">
<div className="billing-label"> <span>*</span></div>
<div className="billing-field">
<input
type="text"
<select
value={mid}
readOnly={true}
/>
onChange={(e: ChangeEvent<HTMLSelectElement>) => setMid(e.target.value)}
>
{
midOptions.map((value) => (
<option
key={value.value}
value={value.value}
>{value.name}</option>
))
}
</select>
</div>
</div>
@@ -196,17 +173,16 @@ export const KeyInPaymentRequestPage = () => {
<div className="billing-row">
<div className="billing-label"> <span>*</span></div>
<div className="billing-field">
<input
type="text"
value={amount === 0 ? '' : amount.toString()}
placeholder="금액을 입력하세요"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
const onlyNumbers = e.target.value.replace(/[^0-9]/g, ''); // 숫자만 남김
setAmount(onlyNumbers === '' ? 0 : parseInt(onlyNumbers, 10));
<NumericFormat
value={amount}
thousandSeparator={true}
allowNegative={false}
displayType="input"
onValueChange={(values) => {
const { floatValue} = values;
setAmount( floatValue ?? 0);
}}
inputMode="numeric" // 모바일 키보드 숫자 전용
pattern="[0-9]*" // 브라우저 기본 숫자만 유효하도록
/>
></NumericFormat>
</div>
</div>
@@ -227,7 +203,6 @@ export const KeyInPaymentRequestPage = () => {
<input
type="email"
value={email}
placeholder='test@nicepay.co.kr'
onChange={(e: ChangeEvent<HTMLInputElement>) => setEmail(e.target.value)}
className={email && !isValidEmail(email) ? 'error' : ''}
/>
@@ -240,7 +215,7 @@ export const KeyInPaymentRequestPage = () => {
<input
type="tel"
value={phoneNumber}
placeholder='01012345678'
placeholder='- 제외하고 입력'
onChange={(e: ChangeEvent<HTMLInputElement>) => {
const onlyNumbers = e.target.value.replace(/[^0-9]/g, '');
setPhoneNumber(onlyNumbers);
@@ -256,92 +231,85 @@ export const KeyInPaymentRequestPage = () => {
<div className="billing-row">
<div className="billing-label"> <span>*</span></div>
<div className="billing-field">
<input
type="text"
<PatternFormat
value={cardNo1}
onChange={(e: ChangeEvent<HTMLInputElement>) => {
const onlyNumbers = e.target.value.replace(/[^0-9]/g, '');
if (onlyNumbers.length <= 4) setCardNo1(onlyNumbers);
}}
inputMode="numeric"
pattern="[0-9]*"
maxLength={4}
placeholder="1234"
/>
allowEmptyFormatting
valueIsNumericString
format="####"
onChange={(e: ChangeEvent<HTMLInputElement>) => setCardNo1(e.target.value)}
>
</PatternFormat>
</div>
<div className="billing-field">
<input
type="text"
<PatternFormat
value={cardNo2}
onChange={(e: ChangeEvent<HTMLInputElement>) => {
const onlyNumbers = e.target.value.replace(/[^0-9]/g, '');
if (onlyNumbers.length <= 4) setCardNo2(onlyNumbers);
}}
inputMode="numeric"
pattern="[0-9]*"
maxLength={4}
placeholder="5678"
/>
allowEmptyFormatting
valueIsNumericString
format="####"
onChange={(e: ChangeEvent<HTMLInputElement>) => setCardNo2(e.target.value)}
>
</PatternFormat>
</div>
<div className="billing-field">
<input
type="text"
<PatternFormat
value={cardNo3}
onChange={(e: ChangeEvent<HTMLInputElement>) => {
const onlyNumbers = e.target.value.replace(/[^0-9]/g, '');
if (onlyNumbers.length <= 4) setCardNo3(onlyNumbers);
}}
inputMode="numeric"
pattern="[0-9]*"
maxLength={4}
placeholder="9012"
/>
allowEmptyFormatting
valueIsNumericString
format="####"
onChange={(e: ChangeEvent<HTMLInputElement>) => setCardNo3(e.target.value)}
>
</PatternFormat>
</div>
<div className="billing-field">
<input
type="text"
<PatternFormat
value={cardNo4}
onChange={(e: ChangeEvent<HTMLInputElement>) => {
const onlyNumbers = e.target.value.replace(/[^0-9]/g, '');
if (onlyNumbers.length <= 4) setCardNo4(onlyNumbers);
}}
inputMode="numeric"
pattern="[0-9]*"
maxLength={4}
placeholder="3456"
/>
allowEmptyFormatting
valueIsNumericString
format="####"
onChange={(e: ChangeEvent<HTMLInputElement>) => setCardNo4(e.target.value)}
>
</PatternFormat>
</div>
</div>
<div className="billing-row">
<div className="billing-label">(/)<span>*</span></div>
<div className="billing-field" style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>
<input
type="text"
value={expMon}
onChange={(e: ChangeEvent<HTMLInputElement>) => {
const onlyNumbers = e.target.value.replace(/[^0-9]/g, '');
if (onlyNumbers.length <= 2) setExpMon(onlyNumbers);
}}
inputMode="numeric"
pattern="[0-9]*"
maxLength={2}
<PatternFormat
placeholder='MM'
value={expMon}
valueIsNumericString
format='##'
isAllowed={(values) => {
const { value } = values;
if (!value) return true;
const numValue = parseInt(value);
return numValue >= 1 && numValue <= 12;
}}
onValueChange={(values) => {
const { value } = values;
setExpMon(value);
}}
onBlur={() => {
if (expMon.length === 1 && parseInt(expMon) >= 1 && parseInt(expMon) <= 9) {
setExpMon(expMon.padStart(2, '0'));
}
}}
style={{ flex: 1 }}
inputMode="numeric"
/>
<span>/</span>
<input
type="text"
value={expYear}
onChange={(e: ChangeEvent<HTMLInputElement>) => {
const onlyNumbers = e.target.value.replace(/[^0-9]/g, '');
if (onlyNumbers.length <= 2) setExpYear(onlyNumbers);
}}
inputMode="numeric"
pattern="[0-9]*"
maxLength={2}
<PatternFormat
placeholder='YY'
value={expYear}
valueIsNumericString
format='##'
onValueChange={(values) => {
const { value } = values;
setExpYear(value);
}}
style={{ flex: 1 }}
inputMode="numeric"
/>
</div>
</div>
@@ -354,8 +322,8 @@ export const KeyInPaymentRequestPage = () => {
value={instmnt}
onChange={(e: ChangeEvent<HTMLSelectElement>) => setInstmnt(e.target.value)}
>
<option value="00"> ()</option>
{amount >= 50000 && (
<option value="00"></option>
{/* {amount >= 50000 && (
<>
<option value="02">2개월</option>
<option value="03">3개월</option>
@@ -369,7 +337,7 @@ export const KeyInPaymentRequestPage = () => {
<option value="11">11개월</option>
<option value="12">12개월</option>
</>
)}
)} */}
</select>
</div>
</div>