This commit is contained in:
focp212@naver.com
2025-10-15 17:13:04 +09:00
20 changed files with 1171 additions and 136 deletions

View File

@@ -209,6 +209,7 @@ export const KeyInPaymentPage = () => {
<KeyInPaymentList
listItems={listItems}
additionalServiceCategory={AdditionalServiceCategory.KeyInPayment}
mid={mid}
></KeyInPaymentList>
</div>
</div>

View File

@@ -1,5 +1,6 @@
import { useState } from 'react';
import { ChangeEvent, useState } from 'react';
import { PATHS } from '@/shared/constants/paths';
import { useLocation } from 'react-router';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { IMAGE_ROOT } from '@/shared/constants/common';
import { HeaderType } from '@/entities/common/model/types';
@@ -10,10 +11,29 @@ import {
useSetFooterMode,
useSetOnBack
} from '@/widgets/sub-layout/use-sub-layout';
import { number } from 'framer-motion';
import { overlay } from 'overlay-kit';
import { Dialog } from '@/shared/ui/dialogs/dialog';
export const KeyInPaymentRequestPage = () => {
const { navigate } = useNavigate();
const location = useLocation();
const { mid: receivedMid } = location.state || {};
const [mid, setMid] = useState<string>(receivedMid || '');
const [goodsName, setGoodsName] = useState<string>('');
const [amount, setAmount] = useState<number>(0);
const [buyerName, setBuyerName] = useState<string>('');
const [email, setEmail] = useState<string>('');
const [phoneNumber, setPhoneNumber] = useState<string>('');
const [cardNo1, setCardNo1] = useState<string>('');
const [cardNo2, setCardNo2] = useState<string>('');
const [cardNo3, setCardNo3] = useState<string>('');
const [cardNo4, setCardNo4] = useState<string>('');
const [cardExpirationMonth, setCardExpirationMonth] = useState<string>('');
const [cardExpirationYear, setCardExpirationYear] = useState<string>('');
const [instmntMonth, setInstmntMonth] = useState<string>('00');
const [moid, setMoid] = useState<string>('');
const { mutateAsync: keyInApply } = useExtensionKeyinApplyMutation();
@@ -25,31 +45,99 @@ export const KeyInPaymentRequestPage = () => {
});
const callKeyInPaymentRequest = () => {
const cardNo = `${cardNo1}${cardNo2}${cardNo3}${cardNo4}`;
const cardExpirationDate = `${cardExpirationMonth}${cardExpirationYear}`;
let keyInApplyParams = {
mid: 'string',
goodsName: 'string',
amount: 0,
buyerName: 'string',
email: 'string',
phoneNumber: 'string',
cardNo: 'string',
cardExpirationDate: 'string',
instmntMonth: 'string',
moid: 'SMS',
mid: mid,
goodsName: goodsName,
amount: amount,
buyerName: buyerName,
email: email,
phoneNumber: phoneNumber,
cardNo: cardNo,
cardExpirationDate: cardExpirationDate,
instmntMonth: instmntMonth,
moid: moid,
};
keyInApply(keyInApplyParams).then((rs) => {
navigate(PATHS.additionalService.keyInPayment.requestSuccess);
console.log(rs)
}).catch(() => {
}).finally(() => {
console.log('결제 성공:', rs);
showSuccessDialog();
}).catch((error) => {
console.error('결제 실패:', error);
showErrorDialog(error?.message || '결제에 실패했습니다');
});
};
const showSuccessDialog = () => {
overlay.open(({ isOpen, close, unmount }) => {
return (
<Dialog
afterLeave={unmount}
open={isOpen}
onClose={close}
onConfirmClick={() => {
close();
navigate(PATHS.additionalService.keyInPayment.list);
}}
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}$/;
return phoneRegex.test(phone);
};
const isValidEmail = (email: string) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};
const isValidCardNumber = () => {
return cardNo1.length === 4 && cardNo2.length === 4 &&
cardNo3.length === 4 && cardNo4.length === 4;
};
const isValidCardExpiration = () => {
if (cardExpirationMonth.length !== 2 || cardExpirationYear.length !== 2) {
return false;
}
const month = parseInt(cardExpirationMonth);
return month >= 1 && month <= 12;
};
const isFormValid = () => {
return (
mid.trim() !== '' &&
goodsName.trim() !== '' &&
amount > 0 &&
buyerName.trim() !== '' &&
isValidEmail(email) &&
isValidPhoneNumber(phoneNumber) &&
isValidCardNumber() &&
isValidCardExpiration()
);
};
const onClickToRequest = () => {
callKeyInPaymentRequest();
@@ -65,11 +153,11 @@ export const KeyInPaymentRequestPage = () => {
<div className="billing-row">
<div className="billing-label"> <span>*</span></div>
<div className="billing-field">
<select
className="wid-100"
>
<option>nictest00m</option>
</select>
<input
type="text"
value={mid}
readOnly={true}
/>
</div>
</div>
@@ -78,7 +166,8 @@ export const KeyInPaymentRequestPage = () => {
<div className="billing-field">
<input
type="text"
value=""
value={goodsName}
onChange={(e: ChangeEvent<HTMLInputElement>) => setGoodsName(e.target.value)}
/>
</div>
</div>
@@ -88,7 +177,13 @@ export const KeyInPaymentRequestPage = () => {
<div className="billing-field">
<input
type="text"
value=""
value={amount}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
const onlyNumbers = e.target.value.replace(/[^0-9]/g, ''); // 숫자만 남김
setAmount(onlyNumbers === '' ? 0 : parseInt(onlyNumbers));
}}
inputMode="numeric" // 모바일 키보드 숫자 전용
pattern="[0-9]*" // 브라우저 기본 숫자만 유효하도록
/>
</div>
</div>
@@ -98,7 +193,8 @@ export const KeyInPaymentRequestPage = () => {
<div className="billing-field">
<input
type="text"
value=""
value={buyerName}
onChange={(e: ChangeEvent<HTMLInputElement>) => setBuyerName(e.target.value)}
/>
</div>
</div>
@@ -108,7 +204,10 @@ export const KeyInPaymentRequestPage = () => {
<div className="billing-field">
<input
type="email"
value=""
value={email}
placeholder='test@nicepay.co.kr'
onChange={(e: ChangeEvent<HTMLInputElement>) => setEmail(e.target.value)}
className={email && !isValidEmail(email) ? 'error' : ''}
/>
</div>
</div>
@@ -118,8 +217,16 @@ export const KeyInPaymentRequestPage = () => {
<div className="billing-field">
<input
type="tel"
value=""
placeholder=" '-' 제외하고 입력"
value={phoneNumber}
placeholder='01012345678'
onChange={(e: ChangeEvent<HTMLInputElement>) => {
const onlyNumbers = e.target.value.replace(/[^0-9]/g, '');
setPhoneNumber(onlyNumbers);
}}
className={phoneNumber && !isValidPhoneNumber(phoneNumber) ? 'error' : ''}
inputMode="numeric"
pattern="[0-9]*"
maxLength={11}
/>
</div>
</div>
@@ -129,36 +236,90 @@ export const KeyInPaymentRequestPage = () => {
<div className="billing-field">
<input
type="text"
value=""
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"
/>
</div>
<div className="billing-field">
<input
type="text"
value=""
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"
/>
</div>
<div className="billing-field">
<input
type="text"
value=""
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"
/>
</div>
<div className="billing-field">
<input
type="text"
value=""
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"
/>
</div>
</div>
<div className="billing-row">
<div className="billing-label">(/)<span>*</span></div>
<div className="billing-field">
<div className="billing-field" style={{display: 'flex', gap: '8px', alignItems: 'center'}}>
<input
type="text"
value=""
placeholder='MM/YY'
value={cardExpirationMonth}
onChange={(e: ChangeEvent<HTMLInputElement>) => {
const onlyNumbers = e.target.value.replace(/[^0-9]/g, '');
if (onlyNumbers.length <= 2) setCardExpirationMonth(onlyNumbers);
}}
inputMode="numeric"
pattern="[0-9]*"
maxLength={2}
placeholder='MM'
style={{flex: 1}}
/>
<span>/</span>
<input
type="text"
value={cardExpirationYear}
onChange={(e: ChangeEvent<HTMLInputElement>) => {
const onlyNumbers = e.target.value.replace(/[^0-9]/g, '');
if (onlyNumbers.length <= 2) setCardExpirationYear(onlyNumbers);
}}
inputMode="numeric"
pattern="[0-9]*"
maxLength={2}
placeholder='YY'
style={{flex: 1}}
/>
</div>
</div>
@@ -167,9 +328,26 @@ export const KeyInPaymentRequestPage = () => {
<div className="billing-label"> <span>*</span></div>
<div className="billing-field">
<select
className="wid-100"
disabled={amount < 50000}
value={instmntMonth}
onChange={(e: ChangeEvent<HTMLSelectElement>) => setInstmntMonth(e.target.value)}
>
<option></option>
<option value="00"> ()</option>
{amount >= 50000 && (
<>
<option value="02">2</option>
<option value="03">3</option>
<option value="04">4</option>
<option value="05">5</option>
<option value="06">6</option>
<option value="07">7</option>
<option value="08">8</option>
<option value="09">9</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
</>
)}
</select>
</div>
</div>
@@ -179,7 +357,8 @@ export const KeyInPaymentRequestPage = () => {
<div className="billing-field">
<input
type="text"
value=""
value={moid}
onChange={(e: ChangeEvent<HTMLInputElement>) => setMoid(e.target.value)}
/>
</div>
</div>
@@ -188,7 +367,8 @@ export const KeyInPaymentRequestPage = () => {
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={() => onClickToRequest() }
onClick={() => onClickToRequest()}
disabled={!isFormValid()}
> </button>
</div>
</div>