- 수기발행,1:1문의 등록, 빌링 모바일 용 패딩 추가 로직 추가

This commit is contained in:
HyeonJongKim
2025-11-07 11:09:35 +09:00
parent da66206417
commit 21103232e9
5 changed files with 143 additions and 116 deletions

View File

@@ -5,6 +5,7 @@ import { useSetOnBack } from '@/widgets/sub-layout/use-sub-layout';
import { CashReceiptPurposeType } from '../model/types'; import { CashReceiptPurposeType } from '../model/types';
import { PatternFormat } from 'react-number-format'; import { PatternFormat } from 'react-number-format';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useKeyboardAware } from '@/shared/lib/hooks/use-keyboard-aware';
export interface CashReceiptHandWrittenIssuanceStep1Props { export interface CashReceiptHandWrittenIssuanceStep1Props {
businessNumber?: string; businessNumber?: string;
@@ -41,6 +42,7 @@ export const CashReceiptHandWrittenIssuanceStep1 = ({
}: CashReceiptHandWrittenIssuanceStep1Props) => { }: CashReceiptHandWrittenIssuanceStep1Props) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { navigate } = useNavigate(); const { navigate } = useNavigate();
const { handleInputFocus, keyboardAwarePadding } = useKeyboardAware();
useSetOnBack(() => { useSetOnBack(() => {
navigate(PATHS.transaction.cashReceipt.list); navigate(PATHS.transaction.cashReceipt.list);
@@ -55,8 +57,8 @@ export const CashReceiptHandWrittenIssuanceStep1 = ({
<input <input
className="error" className="error"
type="text" type="text"
value={ businessNumber } value={businessNumber}
readOnly={ true } readOnly={true}
/> />
</div> </div>
</div> </div>
@@ -66,14 +68,14 @@ export const CashReceiptHandWrittenIssuanceStep1 = ({
<div className="issue-field"> <div className="issue-field">
<div className="seg-buttons"> <div className="seg-buttons">
<button <button
className={ `btn-40 ${(purposeType === CashReceiptPurposeType.INCOME_DEDUCTION)? 'btn-blue': 'btn-white'}` } className={`btn-40 ${(purposeType === CashReceiptPurposeType.INCOME_DEDUCTION) ? 'btn-blue' : 'btn-white'}`}
type="button" type="button"
onClick={ () => setPurposeType(CashReceiptPurposeType.INCOME_DEDUCTION) } onClick={() => setPurposeType(CashReceiptPurposeType.INCOME_DEDUCTION)}
>{t('transaction.handWrittenIssuance.incomeDeduction')}</button> >{t('transaction.handWrittenIssuance.incomeDeduction')}</button>
<button <button
className={ `btn-40 ${(purposeType === CashReceiptPurposeType.EXPENSE_PROOF)? 'btn-blue': 'btn-white'}` } className={`btn-40 ${(purposeType === CashReceiptPurposeType.EXPENSE_PROOF) ? 'btn-blue' : 'btn-white'}`}
type="button" type="button"
onClick={ () => setPurposeType(CashReceiptPurposeType.EXPENSE_PROOF) } onClick={() => setPurposeType(CashReceiptPurposeType.EXPENSE_PROOF)}
>{t('transaction.handWrittenIssuance.expenseProof')}</button> >{t('transaction.handWrittenIssuance.expenseProof')}</button>
</div> </div>
</div> </div>
@@ -84,8 +86,9 @@ export const CashReceiptHandWrittenIssuanceStep1 = ({
<input <input
type="text" type="text"
placeholder={t('transaction.handWrittenIssuance.productNamePlaceholder')} placeholder={t('transaction.handWrittenIssuance.productNamePlaceholder')}
value={ productName } value={productName}
onChange={ (e: ChangeEvent<HTMLInputElement>) => setProductName(e.target.value) } onChange={(e: ChangeEvent<HTMLInputElement>) => setProductName(e.target.value)}
onFocus={handleInputFocus}
/> />
</div> </div>
</div> </div>
@@ -95,8 +98,9 @@ export const CashReceiptHandWrittenIssuanceStep1 = ({
<input <input
type="text" type="text"
placeholder={t('transaction.handWrittenIssuance.buyerNamePlaceholder')} placeholder={t('transaction.handWrittenIssuance.buyerNamePlaceholder')}
value={ buyerName } value={buyerName}
onChange={ (e: ChangeEvent<HTMLInputElement>) => setBuyerName(e.target.value) } onChange={(e: ChangeEvent<HTMLInputElement>) => setBuyerName(e.target.value)}
onFocus={handleInputFocus}
/> />
</div> </div>
</div> </div>
@@ -105,10 +109,11 @@ export const CashReceiptHandWrittenIssuanceStep1 = ({
<div className="issue-field"> <div className="issue-field">
<PatternFormat <PatternFormat
placeholder={t('transaction.handWrittenIssuance.issueNumberPlaceholder')} placeholder={t('transaction.handWrittenIssuance.issueNumberPlaceholder')}
value={ issueNumber } value={issueNumber}
valueIsNumericString valueIsNumericString
format="###########" format="###########"
onChange={ (e: ChangeEvent<HTMLInputElement>) => setIssueNumber(e.target.value) } onChange={(e: ChangeEvent<HTMLInputElement>) => setIssueNumber(e.target.value)}
onFocus={handleInputFocus}
></PatternFormat> ></PatternFormat>
</div> </div>
</div> </div>
@@ -118,20 +123,22 @@ export const CashReceiptHandWrittenIssuanceStep1 = ({
<input <input
type="email" type="email"
placeholder={t('transaction.handWrittenIssuance.emailPlaceholder')} placeholder={t('transaction.handWrittenIssuance.emailPlaceholder')}
value={ email } value={email}
onChange={ (e: ChangeEvent<HTMLInputElement>) => setEmail(e.target.value) } onChange={(e: ChangeEvent<HTMLInputElement>) => setEmail(e.target.value)}
onFocus={handleInputFocus}
/> />
</div> </div>
</div> </div>
<div className="issue-row"> <div className="issue-row" style={keyboardAwarePadding}>
<div className="issue-label">{t('account.phoneNumber')}</div> <div className="issue-label">{t('account.phoneNumber')}</div>
<div className="issue-field"> <div className="issue-field">
<PatternFormat <PatternFormat
placeholder={t('transaction.handWrittenIssuance.phoneNumberPlaceholder')} placeholder={t('transaction.handWrittenIssuance.phoneNumberPlaceholder')}
value={ phoneNumber } value={phoneNumber}
valueIsNumericString valueIsNumericString
format="###########" format="###########"
onChange={ (e: ChangeEvent<HTMLInputElement>) => setPhoneNumber(e.target.value) } onChange={(e: ChangeEvent<HTMLInputElement>) => setPhoneNumber(e.target.value)}
onFocus={handleInputFocus}
></PatternFormat> ></PatternFormat>
</div> </div>
</div> </div>

View File

@@ -3,6 +3,7 @@ import { useSetOnBack } from '@/widgets/sub-layout/use-sub-layout';
import { ProcessStep } from '../model/types'; import { ProcessStep } from '../model/types';
import { NumericFormat } from 'react-number-format'; import { NumericFormat } from 'react-number-format';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useKeyboardAware } from '@/shared/lib/hooks/use-keyboard-aware';
export interface CashReceiptHandWrittenIssuanceStep2Props { export interface CashReceiptHandWrittenIssuanceStep2Props {
setProcessStep: (processStep: ProcessStep) => void; setProcessStep: (processStep: ProcessStep) => void;
@@ -33,6 +34,7 @@ export const CashReceiptHandWrittenIssuanceStep2 = ({
onClickToVatCalculate onClickToVatCalculate
}: CashReceiptHandWrittenIssuanceStep2Props) => { }: CashReceiptHandWrittenIssuanceStep2Props) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { handleInputFocus, keyboardAwarePadding } = useKeyboardAware();
useSetOnBack(() => { useSetOnBack(() => {
setProcessStep(ProcessStep.One); setProcessStep(ProcessStep.One);
@@ -52,6 +54,7 @@ export const CashReceiptHandWrittenIssuanceStep2 = ({
allowNegative={ false } allowNegative={ false }
displayType="input" displayType="input"
onChange={ (e: ChangeEvent<HTMLInputElement>) => setIssueAmount(parseInt(e.target.value)) } onChange={ (e: ChangeEvent<HTMLInputElement>) => setIssueAmount(parseInt(e.target.value)) }
onFocus={handleInputFocus}
></NumericFormat> ></NumericFormat>
<button <button
className="btn-40 btn-white" className="btn-40 btn-white"
@@ -70,6 +73,7 @@ export const CashReceiptHandWrittenIssuanceStep2 = ({
allowNegative={ false } allowNegative={ false }
displayType="input" displayType="input"
onChange={ (e: ChangeEvent<HTMLInputElement>) => setSupplyAmount(parseInt(e.target.value)) } onChange={ (e: ChangeEvent<HTMLInputElement>) => setSupplyAmount(parseInt(e.target.value)) }
onFocus={handleInputFocus}
></NumericFormat> ></NumericFormat>
</div> </div>
</div> </div>
@@ -81,6 +85,7 @@ export const CashReceiptHandWrittenIssuanceStep2 = ({
allowNegative={ false } allowNegative={ false }
displayType="input" displayType="input"
onChange={ (e: ChangeEvent<HTMLInputElement>) => setVatAmount(parseInt(e.target.value)) } onChange={ (e: ChangeEvent<HTMLInputElement>) => setVatAmount(parseInt(e.target.value)) }
onFocus={handleInputFocus}
></NumericFormat> ></NumericFormat>
</div> </div>
</div> </div>
@@ -92,10 +97,11 @@ export const CashReceiptHandWrittenIssuanceStep2 = ({
allowNegative={ false } allowNegative={ false }
displayType="input" displayType="input"
onChange={ (e: ChangeEvent<HTMLInputElement>) => setTaxFreeAmount(parseInt(e.target.value)) } onChange={ (e: ChangeEvent<HTMLInputElement>) => setTaxFreeAmount(parseInt(e.target.value)) }
onFocus={handleInputFocus}
></NumericFormat> ></NumericFormat>
</div> </div>
</div> </div>
<div className="issue-row"> <div className="issue-row" style={keyboardAwarePadding}>
<div className="issue-label">{t('transaction.fields.serviceAmount')}</div> <div className="issue-label">{t('transaction.fields.serviceAmount')}</div>
<div className="issue-field"> <div className="issue-field">
<NumericFormat <NumericFormat
@@ -103,6 +109,7 @@ export const CashReceiptHandWrittenIssuanceStep2 = ({
allowNegative={ false } allowNegative={ false }
displayType="input" displayType="input"
onChange={ (e: ChangeEvent<HTMLInputElement>) => setServiceCharge(parseInt(e.target.value)) } onChange={ (e: ChangeEvent<HTMLInputElement>) => setServiceCharge(parseInt(e.target.value)) }
onFocus={handleInputFocus}
></NumericFormat> ></NumericFormat>
</div> </div>
</div> </div>

View File

@@ -4,9 +4,9 @@ import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { useQnaSaveMutation } from '@/entities/support/api/use-qna-save-mutation'; import { useQnaSaveMutation } from '@/entities/support/api/use-qna-save-mutation';
import { HeaderType } from '@/entities/common/model/types'; import { HeaderType } from '@/entities/common/model/types';
import { import {
useSetHeaderTitle, useSetHeaderTitle,
useSetHeaderType, useSetHeaderType,
useSetFooterMode, useSetFooterMode,
useSetOnBack useSetOnBack
} from '@/widgets/sub-layout/use-sub-layout'; } from '@/widgets/sub-layout/use-sub-layout';
import { useStore } from '@/shared/model/store'; import { useStore } from '@/shared/model/store';
@@ -16,6 +16,7 @@ import { overlay } from 'overlay-kit';
import { Dialog } from '@/shared/ui/dialogs/dialog'; import { Dialog } from '@/shared/ui/dialogs/dialog';
import { QnaSaveParams, QnaSaveResponse } from '@/entities/support/model/types'; import { QnaSaveParams, QnaSaveResponse } from '@/entities/support/model/types';
import { checkGrant } from '@/shared/lib/check-grant'; import { checkGrant } from '@/shared/lib/check-grant';
import { useKeyboardAware } from '@/shared/lib/hooks/use-keyboard-aware';
export enum QnaRegisterPropsName { export enum QnaRegisterPropsName {
Mid = 'Mid', Mid = 'Mid',
@@ -39,6 +40,7 @@ export const QnaRegisterPage = () => {
const [requestEmail, setRequestEmail] = useState<string>(''); const [requestEmail, setRequestEmail] = useState<string>('');
const [title, setTitle] = useState<string>(''); const [title, setTitle] = useState<string>('');
const [contents, setContents] = useState<string>(''); const [contents, setContents] = useState<string>('');
const { handleInputFocus, keyboardAwarePadding } = useKeyboardAware();
useSetHeaderTitle(t('support.qna.title')); useSetHeaderTitle(t('support.qna.title'));
useSetHeaderType(HeaderType.LeftArrow); useSetHeaderType(HeaderType.LeftArrow);
@@ -54,25 +56,25 @@ export const QnaRegisterPage = () => {
key: string key: string
) => { ) => {
let value = e.target.value; let value = e.target.value;
if(key === QnaRegisterPropsName.Mid){ if (key === QnaRegisterPropsName.Mid) {
setMid(value); setMid(value);
} }
else if(key === QnaRegisterPropsName.RequestType){ else if (key === QnaRegisterPropsName.RequestType) {
setRequestType(value); setRequestType(value);
} }
else if(key === QnaRegisterPropsName.RequestName){ else if (key === QnaRegisterPropsName.RequestName) {
setRequestName(value); setRequestName(value);
} }
else if(key === QnaRegisterPropsName.RequestTel){ else if (key === QnaRegisterPropsName.RequestTel) {
setRequestTel(value); setRequestTel(value);
} }
else if(key === QnaRegisterPropsName.RequestEmail){ else if (key === QnaRegisterPropsName.RequestEmail) {
setRequestEmail(value); setRequestEmail(value);
} }
else if(key === QnaRegisterPropsName.Title){ else if (key === QnaRegisterPropsName.Title) {
setTitle(value); setTitle(value);
} }
else if(key === QnaRegisterPropsName.Contents){ else if (key === QnaRegisterPropsName.Contents) {
setContents(value); setContents(value);
} }
}; };
@@ -87,7 +89,7 @@ export const QnaRegisterPage = () => {
afterLeave={unmount} afterLeave={unmount}
open={isOpen} open={isOpen}
onClose={close} onClose={close}
message={ msg } message={msg}
buttonLabel={[t('support.qna.confirmButton')]} buttonLabel={[t('support.qna.confirmButton')]}
/> />
); );
@@ -95,35 +97,35 @@ export const QnaRegisterPage = () => {
} }
const checkEmail = (email: string) => { const checkEmail = (email: string) => {
var re = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i; var re = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
if(email != '' && email != 'undefined' && re.test(email)){ if (email != '' && email != 'undefined' && re.test(email)) {
return true; return true;
} }
else{ else {
return false; return false;
} }
}; };
const callRegister = () => { const callRegister = () => {
if(!title){ if (!title) {
showAlert(t('support.qna.validation.title')); showAlert(t('support.qna.validation.title'));
return; return;
} }
else if(!requestType){ else if (!requestType) {
showAlert(t('support.qna.validation.requestType')); showAlert(t('support.qna.validation.requestType'));
return; return;
} }
else if(!requestName){ else if (!requestName) {
showAlert(t('support.qna.validation.requestName')); showAlert(t('support.qna.validation.requestName'));
return; return;
} }
else if(!requestTel){ else if (!requestTel) {
showAlert(t('support.qna.validation.requestTel')); showAlert(t('support.qna.validation.requestTel'));
return; return;
} }
else if(requestEmail && !checkEmail(requestEmail)){ else if (requestEmail && !checkEmail(requestEmail)) {
showAlert(t('support.qna.validation.requestEmail')); showAlert(t('support.qna.validation.requestEmail'));
return; return;
} }
else if(!contents){ else if (!contents) {
showAlert(t('support.qna.validation.contents')); showAlert(t('support.qna.validation.contents'));
return; return;
} }
@@ -140,7 +142,7 @@ export const QnaRegisterPage = () => {
alert(t('support.qna.successMessage')); alert(t('support.qna.successMessage'));
navigate(PATHS.support.qna.list); navigate(PATHS.support.qna.list);
}).catch((e: any) => { }).catch((e: any) => {
if(e.response?.data?.error?.message){ if (e.response?.data?.error?.message) {
showAlert(e.response?.data?.error?.message); showAlert(e.response?.data?.error?.message);
return; return;
} }
@@ -168,9 +170,10 @@ export const QnaRegisterPage = () => {
<div className="inq-control"> <div className="inq-control">
<input <input
type="text" type="text"
value={ title } value={title}
required= { true } required={true}
onChange={ (e: ChangeEvent<HTMLInputElement>) => setInputValue(e, QnaRegisterPropsName.Title) } onChange={(e: ChangeEvent<HTMLInputElement>) => setInputValue(e, QnaRegisterPropsName.Title)}
onFocus={handleInputFocus}
/> />
</div> </div>
</div> </div>
@@ -180,9 +183,9 @@ export const QnaRegisterPage = () => {
</div> </div>
<div className="inq-control"> <div className="inq-control">
<select <select
value={ requestType } value={requestType}
required= { true } required={true}
onChange={ (e: ChangeEvent<HTMLSelectElement>) => setInputValue(e, QnaRegisterPropsName.RequestType) } onChange={(e: ChangeEvent<HTMLSelectElement>) => setInputValue(e, QnaRegisterPropsName.RequestType)}
> >
<option value="">{t('support.qna.categories.choose')}</option> <option value="">{t('support.qna.categories.choose')}</option>
<option value="01">{t('support.qna.categories.01')}</option> <option value="01">{t('support.qna.categories.01')}</option>
@@ -202,9 +205,10 @@ export const QnaRegisterPage = () => {
<div className="inq-control"> <div className="inq-control">
<input <input
type="text" type="text"
value={ requestName } value={requestName}
required= { true } required={true}
onChange={ (e: ChangeEvent<HTMLInputElement>) => setInputValue(e, QnaRegisterPropsName.RequestName) } onChange={(e: ChangeEvent<HTMLInputElement>) => setInputValue(e, QnaRegisterPropsName.RequestName)}
onFocus={handleInputFocus}
/> />
</div> </div>
</div> </div>
@@ -215,10 +219,11 @@ export const QnaRegisterPage = () => {
<div className="inq-control"> <div className="inq-control">
<PatternFormat <PatternFormat
placeholder={t('support.qna.formLabels.phonePlaceholder')} placeholder={t('support.qna.formLabels.phonePlaceholder')}
value={ requestTel } value={requestTel}
valueIsNumericString valueIsNumericString
format="###########" format="###########"
onChange={ (e: ChangeEvent<HTMLInputElement>) => setInputValue(e, QnaRegisterPropsName.RequestTel) } onChange={(e: ChangeEvent<HTMLInputElement>) => setInputValue(e, QnaRegisterPropsName.RequestTel)}
onFocus={handleInputFocus}
></PatternFormat> ></PatternFormat>
</div> </div>
</div> </div>
@@ -228,20 +233,22 @@ export const QnaRegisterPage = () => {
<input <input
type="email" type="email"
placeholder={t('support.qna.formLabels.emailPlaceholder')} placeholder={t('support.qna.formLabels.emailPlaceholder')}
value={ requestEmail } value={requestEmail}
onChange={ (e: ChangeEvent<HTMLInputElement>) => setInputValue(e, QnaRegisterPropsName.RequestEmail) } onChange={(e: ChangeEvent<HTMLInputElement>) => setInputValue(e, QnaRegisterPropsName.RequestEmail)}
onFocus={handleInputFocus}
/> />
</div> </div>
</div> </div>
<div className="inq-text"> <div className="inq-text" style={keyboardAwarePadding}>
<div className="inq-text-label"> <div className="inq-text-label">
{t('support.qna.formLabels.inquiryContents')} <span className="red">{t('support.qna.formLabels.required')}</span> {t('support.qna.formLabels.inquiryContents')} <span className="red">{t('support.qna.formLabels.required')}</span>
</div> </div>
<div className="inq-text-body"> <div className="inq-text-body">
<textarea <textarea
value={ contents } value={contents}
required= { true } required={true}
onChange={ (e: ChangeEvent<HTMLTextAreaElement>) => setInputValue(e, QnaRegisterPropsName.Contents) } onChange={(e: ChangeEvent<HTMLTextAreaElement>) => setInputValue(e, QnaRegisterPropsName.Contents)}
onFocus={handleInputFocus}
></textarea> ></textarea>
</div> </div>
</div> </div>
@@ -249,7 +256,7 @@ export const QnaRegisterPage = () => {
<div className="apply-row"> <div className="apply-row">
<button <button
className="btn-50 btn-blue flex-1" className="btn-50 btn-blue flex-1"
onClick={ () => onClickToRegisterQna() } onClick={() => onClickToRegisterQna()}
>{t('support.qna.submitButton')}</button> >{t('support.qna.submitButton')}</button>
</div> </div>
</div> </div>

View File

@@ -17,6 +17,7 @@ import moment from 'moment';
import NiceCalendar from '@/shared/ui/calendar/nice-calendar'; import NiceCalendar from '@/shared/ui/calendar/nice-calendar';
import { notiBar, snackBar } from '@/shared/lib'; import { notiBar, snackBar } from '@/shared/lib';
import { BillingChargeParams, BillingChargeResponse } from '@/entities/transaction/model/types'; import { BillingChargeParams, BillingChargeResponse } from '@/entities/transaction/model/types';
import { useKeyboardAware } from '@/shared/lib/hooks/use-keyboard-aware';
export const BillingChargePage = () => { export const BillingChargePage = () => {
const { navigate } = useNavigate(); const { navigate } = useNavigate();
@@ -31,7 +32,7 @@ export const BillingChargePage = () => {
const [installmentMonth, setInstallmentMonth] = useState<string>('00'); const [installmentMonth, setInstallmentMonth] = useState<string>('00');
const [calendarOpen, setCalendarOpen] = useState<boolean>(false); const [calendarOpen, setCalendarOpen] = useState<boolean>(false);
const { handleInputFocus, keyboardAwarePadding } = useKeyboardAware();
useSetHeaderTitle(t('billing.charge')); useSetHeaderTitle(t('billing.charge'));
useSetHeaderType(HeaderType.RightClose); useSetHeaderType(HeaderType.RightClose);
@@ -51,26 +52,26 @@ export const BillingChargePage = () => {
}; };
const onClickToBillingCharge = () => { const onClickToBillingCharge = () => {
if(!billKey){ if (!billKey) {
showAlert('빌키는 필수 입력 항목입니다.'); showAlert('빌키는 필수 입력 항목입니다.');
return; return;
} }
else if(!productName){ else if (!productName) {
showAlert('상품명은 필수 입력 항목입니다.'); showAlert('상품명은 필수 입력 항목입니다.');
} }
else if(!productAmount){ else if (!productAmount) {
showAlert('상품금액은 필수 입력 항목입니다.'); showAlert('상품금액은 필수 입력 항목입니다.');
} }
else if(productAmount <= 0){ else if (productAmount <= 0) {
showAlert('상품금액은 0보다 커야 합니다.'); showAlert('상품금액은 0보다 커야 합니다.');
} }
else if(!orderNumber){ else if (!orderNumber) {
showAlert('주문번호는 필수 입력 항목입니다.'); showAlert('주문번호는 필수 입력 항목입니다.');
} }
else if(!buyerName){ else if (!buyerName) {
showAlert('구매자명은 필수 입력 항목입니다.'); showAlert('구매자명은 필수 입력 항목입니다.');
} }
let params: BillingChargeParams = { let params: BillingChargeParams = {
billKey: billKey, billKey: billKey,
productName: productName, productName: productName,
@@ -81,12 +82,12 @@ export const BillingChargePage = () => {
installmentMonth: installmentMonth installmentMonth: installmentMonth
}; };
billingCharge(params).then((rs: BillingChargeResponse) => { billingCharge(params).then((rs: BillingChargeResponse) => {
snackBar('결제 신청을 성공하였습니다.', function(){ snackBar('결제 신청을 성공하였습니다.', function () {
navigate(PATHS.transaction.billing.list); navigate(PATHS.transaction.billing.list);
}, 3000); }, 3000);
}).catch((e: any) => { }).catch((e: any) => {
if(e.response?.data?.error?.message){ if (e.response?.data?.error?.message) {
showAlert(e.response?.data?.error?.message); showAlert(e.response?.data?.error?.message);
return; return;
} }
@@ -95,32 +96,32 @@ export const BillingChargePage = () => {
const onChangeBillKey = (value: string) => { const onChangeBillKey = (value: string) => {
const pattern = /^[A-Za-z0-9]+$/; const pattern = /^[A-Za-z0-9]+$/;
if(pattern.test(value) || value === ''){ if (pattern.test(value) || value === '') {
setBillKey(value); setBillKey(value);
} }
}; };
const makeInstallmentMonthSelect = () => { const makeInstallmentMonthSelect = () => {
let rs = []; let rs = [];
rs.push( rs.push(
<option <option
key={ `key-installment` } key={`key-installment`}
value='' value=''
></option> ></option>
); );
rs.push( rs.push(
<option <option
key={ `key-installment-0` } key={`key-installment-0`}
value='00' value='00'
></option> ></option>
); );
for(let i=2;i<=24;i++){ for (let i = 2; i <= 24; i++) {
let val = (i < 10)? '0'+i: ''+i; let val = (i < 10) ? '0' + i : '' + i;
rs.push( rs.push(
<option <option
key={ `key-installment-${i}`} key={`key-installment-${i}`}
value={ val } value={val}
>{i}</option> >{i}</option>
); );
}; };
@@ -138,20 +139,22 @@ export const BillingChargePage = () => {
<div className="billing-row"> <div className="billing-row">
<div className="billing-label"> <span>*</span></div> <div className="billing-label"> <span>*</span></div>
<div className="billing-field"> <div className="billing-field">
<input <input
type="text" type="text"
value={ billKey } value={billKey}
onChange={ (e: ChangeEvent<HTMLInputElement>) => onChangeBillKey(e.target.value) } onChange={(e: ChangeEvent<HTMLInputElement>) => onChangeBillKey(e.target.value)}
onFocus={handleInputFocus}
/> />
</div> </div>
</div> </div>
<div className="billing-row"> <div className="billing-row">
<div className="billing-label"> <span>*</span></div> <div className="billing-label"> <span>*</span></div>
<div className="billing-field"> <div className="billing-field">
<input <input
type="text" type="text"
value={ productName } value={productName}
onChange={ (e: ChangeEvent<HTMLInputElement>) => setProductName(e.target.value) } onChange={(e: ChangeEvent<HTMLInputElement>) => setProductName(e.target.value)}
onFocus={handleInputFocus}
/> />
</div> </div>
</div> </div>
@@ -159,30 +162,33 @@ export const BillingChargePage = () => {
<div className="billing-label"> <span>*</span></div> <div className="billing-label"> <span>*</span></div>
<div className="billing-field"> <div className="billing-field">
<NumericFormat <NumericFormat
value={ productAmount } value={productAmount}
allowNegative={ false } allowNegative={false}
displayType="input" displayType="input"
onChange={ (e: ChangeEvent<HTMLInputElement>) => setProductAmount(parseInt(e.target.value)) } onChange={(e: ChangeEvent<HTMLInputElement>) => setProductAmount(parseInt(e.target.value))}
onFocus={handleInputFocus}
></NumericFormat> ></NumericFormat>
</div> </div>
</div> </div>
<div className="billing-row"> <div className="billing-row">
<div className="billing-label"> <span>*</span></div> <div className="billing-label"> <span>*</span></div>
<div className="billing-field"> <div className="billing-field">
<input <input
type="text" type="text"
value={ orderNumber } value={orderNumber}
onChange={ (e: ChangeEvent<HTMLInputElement>) => setOrderNumber(e.target.value) } onChange={(e: ChangeEvent<HTMLInputElement>) => setOrderNumber(e.target.value)}
onFocus={handleInputFocus}
/> />
</div> </div>
</div> </div>
<div className="billing-row"> <div className="billing-row">
<div className="billing-label"> <span>*</span></div> <div className="billing-label"> <span>*</span></div>
<div className="billing-field"> <div className="billing-field">
<input <input
type="text" type="text"
value={ buyerName } value={buyerName}
onChange={ (e: ChangeEvent<HTMLInputElement>) => setBuyerName(e.target.value) } onChange={(e: ChangeEvent<HTMLInputElement>) => setBuyerName(e.target.value)}
onFocus={handleInputFocus}
/> />
</div> </div>
</div> </div>
@@ -194,16 +200,16 @@ export const BillingChargePage = () => {
<input <input
type="text" type="text"
placeholder="날짜 선택" placeholder="날짜 선택"
value={ paymentRequestDate } value={paymentRequestDate}
readOnly={ true } readOnly={true}
/> />
<button <button
className="date-btn" className="date-btn"
type="button" type="button"
onClick={ () => onClickToOpenCalendar() } onClick={() => onClickToOpenCalendar()}
> >
<img <img
src={ IMAGE_ROOT + '/ico_date.svg' } src={IMAGE_ROOT + '/ico_date.svg'}
alt="clear" alt="clear"
/> />
</button> </button>
@@ -211,33 +217,33 @@ export const BillingChargePage = () => {
</div> </div>
</div> </div>
<div className="billing-row"> <div className="billing-row" style={keyboardAwarePadding}>
<div className="billing-label"> </div> <div className="billing-label"> </div>
<div className="billing-field"> <div className="billing-field">
<select <select
value={ installmentMonth } value={installmentMonth}
onChange={ (e: ChangeEvent<HTMLSelectElement>) => setBuyerName(e.target.value) } onChange={(e: ChangeEvent<HTMLSelectElement>) => setBuyerName(e.target.value)}
> >
{ makeInstallmentMonthSelect() } {makeInstallmentMonthSelect()}
</select> </select>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div className="apply-row"> <div className="apply-row">
<button <button
className="btn-50 btn-blue flex-1" className="btn-50 btn-blue flex-1"
onClick={ () => onClickToBillingCharge() } onClick={() => onClickToBillingCharge()}
> </button> > </button>
</div> </div>
</div> </div>
</div> </div>
</main> </main>
<NiceCalendar <NiceCalendar
calendarOpen={ calendarOpen } calendarOpen={calendarOpen}
setCalendarOpen={ setCalendarOpen } setCalendarOpen={setCalendarOpen}
calendarType={ CalendarType.Single } calendarType={CalendarType.Single}
setNewDate={ setNewDate } setNewDate={setNewDate}
></NiceCalendar> ></NiceCalendar>
</> </>
); );

View File

@@ -18,7 +18,7 @@ export const useKeyboardAware = (options?: UseKeyboardAwareOptions) => {
const [keyboardHeight, setKeyboardHeight] = useState<number>(0); const [keyboardHeight, setKeyboardHeight] = useState<number>(0);
useEffect(() => { useEffect(() => {
let focusedElement: HTMLInputElement | null = null; let focusedElement: HTMLElement | null = null;
let isKeyboardOpen = false; let isKeyboardOpen = false;
// 네이티브에서 호출할 전역 함수 등록 // 네이티브에서 호출할 전역 함수 등록
@@ -44,7 +44,7 @@ export const useKeyboardAware = (options?: UseKeyboardAwareOptions) => {
}; };
// focus된 요소를 추적하기 위한 함수 // focus된 요소를 추적하기 위한 함수
(window as any).setFocusedElement = (element: HTMLInputElement) => { (window as any).setFocusedElement = (element: HTMLElement) => {
focusedElement = element; focusedElement = element;
// 키보드가 이미 열려있으면 즉시 스크롤 // 키보드가 이미 열려있으면 즉시 스크롤
@@ -62,8 +62,8 @@ export const useKeyboardAware = (options?: UseKeyboardAwareOptions) => {
}; };
}, []); }, []);
// 모든 input에서 사용할 공통 핸들러 // input과 textarea 모두에서 사용할 공통 핸들러
const handleInputFocus = (e: React.FocusEvent<HTMLInputElement>) => { const handleInputFocus = (e: React.FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => {
// focus된 요소를 저장 // focus된 요소를 저장
(window as any).setFocusedElement?.(e.target); (window as any).setFocusedElement?.(e.target);
}; };