Merge branch 'main' of https://gitea.bpsoft.co.kr/nicepayments/nice-app-web
This commit is contained in:
@@ -13,6 +13,8 @@ import { DetailMotionDuration, DetailMotionStyle, DetailMotionVariants } from '@
|
|||||||
import { FullMenuClose } from '@/entities/common/ui/full-menu-close';
|
import { FullMenuClose } from '@/entities/common/ui/full-menu-close';
|
||||||
import { showAlert } from '@/widgets/show-alert';
|
import { showAlert } from '@/widgets/show-alert';
|
||||||
import { checkGrant } from '@/shared/lib/check-grant';
|
import { checkGrant } from '@/shared/lib/check-grant';
|
||||||
|
import { overlay } from 'overlay-kit';
|
||||||
|
import { Dialog } from '@/shared/ui/dialogs/dialog';
|
||||||
|
|
||||||
export interface FundAccountTransferDetailProps {
|
export interface FundAccountTransferDetailProps {
|
||||||
detailOn: boolean;
|
detailOn: boolean;
|
||||||
@@ -54,6 +56,27 @@ export const FundAccountTransferDetail = ({
|
|||||||
showAlert(t('common.nopermission'));
|
showAlert(t('common.nopermission'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let msg = t('additionalService.fundAccount.transferRequestMsg');
|
||||||
|
|
||||||
|
overlay.open(({
|
||||||
|
isOpen,
|
||||||
|
close,
|
||||||
|
unmount
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
afterLeave={unmount}
|
||||||
|
open={isOpen}
|
||||||
|
onClose={close}
|
||||||
|
onConfirmClick={() => transferReqeust()}
|
||||||
|
message={msg}
|
||||||
|
buttonLabel={[t('common.cancel'), t('common.confirm')]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const transferReqeust = () => {
|
||||||
let params: ExtensionFundAccountTransferRequestParams = {
|
let params: ExtensionFundAccountTransferRequestParams = {
|
||||||
seq: seq
|
seq: seq
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { LinkPaymentFormData, LinkPaymentSendMethod } from '@/entities/additiona
|
|||||||
import { NumericFormat } from 'react-number-format';
|
import { NumericFormat } from 'react-number-format';
|
||||||
import { useStore } from '@/shared/model/store';
|
import { useStore } from '@/shared/model/store';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
import { useKeyboardAware } from '@/shared/lib/hooks/use-keyboard-aware';
|
||||||
|
|
||||||
interface LinkPaymentStep1Props {
|
interface LinkPaymentStep1Props {
|
||||||
formData: LinkPaymentFormData;
|
formData: LinkPaymentFormData;
|
||||||
@@ -16,6 +17,7 @@ interface LinkPaymentStep1Props {
|
|||||||
export const LinkPaymentStep1 = ({ formData, setFormData }: LinkPaymentStep1Props) => {
|
export const LinkPaymentStep1 = ({ formData, setFormData }: LinkPaymentStep1Props) => {
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const { navigate } = useNavigate();
|
const { navigate } = useNavigate();
|
||||||
|
const { handleInputFocus, keyboardAwarePadding } = useKeyboardAware();
|
||||||
const midOptionsWithoutGids = useStore.getState().UserStore.selectOptionsMidsWithoutGids;
|
const midOptionsWithoutGids = useStore.getState().UserStore.selectOptionsMidsWithoutGids;
|
||||||
const isEnglish = i18n.language === 'en';
|
const isEnglish = i18n.language === 'en';
|
||||||
|
|
||||||
@@ -102,6 +104,7 @@ export const LinkPaymentStep1 = ({ formData, setFormData }: LinkPaymentStep1Prop
|
|||||||
placeholder=""
|
placeholder=""
|
||||||
value={formData.goodsName}
|
value={formData.goodsName}
|
||||||
onChange={(e) => handleInputChange('goodsName', e.target.value)}
|
onChange={(e) => handleInputChange('goodsName', e.target.value)}
|
||||||
|
onFocus={handleInputFocus}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -114,6 +117,7 @@ export const LinkPaymentStep1 = ({ formData, setFormData }: LinkPaymentStep1Prop
|
|||||||
allowNegative={false}
|
allowNegative={false}
|
||||||
displayType="input"
|
displayType="input"
|
||||||
thousandSeparator={true}
|
thousandSeparator={true}
|
||||||
|
onFocus={handleInputFocus}
|
||||||
onValueChange={(values) => {
|
onValueChange={(values) => {
|
||||||
const { floatValue } = values;
|
const { floatValue } = values;
|
||||||
setFormData({ ...formData, amount: floatValue ?? 0 });
|
setFormData({ ...formData, amount: floatValue ?? 0 });
|
||||||
@@ -130,11 +134,12 @@ export const LinkPaymentStep1 = ({ formData, setFormData }: LinkPaymentStep1Prop
|
|||||||
placeholder=""
|
placeholder=""
|
||||||
value={formData.moid}
|
value={formData.moid}
|
||||||
onChange={(e) => handleInputChange('moid', e.target.value)}
|
onChange={(e) => handleInputChange('moid', e.target.value)}
|
||||||
|
onFocus={handleInputFocus}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="issue-row gap-10">
|
<div className="issue-row gap-10" style={keyboardAwarePadding}>
|
||||||
<div className="issue-label">{t('additionalService.linkPayment.paymentValidDate')}</div>
|
<div className="issue-label">{t('additionalService.linkPayment.paymentValidDate')}</div>
|
||||||
<div className="issue-field">
|
<div className="issue-field">
|
||||||
<div className="link-apply-date">
|
<div className="link-apply-date">
|
||||||
|
|||||||
@@ -1060,6 +1060,7 @@
|
|||||||
"transferResult": "Transfer Result",
|
"transferResult": "Transfer Result",
|
||||||
"beneficiaryName": "Beneficiary Name",
|
"beneficiaryName": "Beneficiary Name",
|
||||||
"transferRequestButton": "Transfer Request",
|
"transferRequestButton": "Transfer Request",
|
||||||
|
"transferRequestMsg": "Do you want to request the transfer?",
|
||||||
"transferRequestSuccess": "Transfer request successful.",
|
"transferRequestSuccess": "Transfer request successful.",
|
||||||
"transferRequestFailed": "Transfer request failed.",
|
"transferRequestFailed": "Transfer request failed.",
|
||||||
"transferRequestError": "An error occurred during transfer request.",
|
"transferRequestError": "An error occurred during transfer request.",
|
||||||
|
|||||||
@@ -1060,6 +1060,7 @@
|
|||||||
"transferResult": "이체결과",
|
"transferResult": "이체결과",
|
||||||
"beneficiaryName": "수취인명",
|
"beneficiaryName": "수취인명",
|
||||||
"transferRequestButton": "이체 요청",
|
"transferRequestButton": "이체 요청",
|
||||||
|
"transferRequestMsg": "이체요청을 하시겠습니까?",
|
||||||
"transferRequestSuccess": "이체요청을 성공하였습니다.",
|
"transferRequestSuccess": "이체요청을 성공하였습니다.",
|
||||||
"transferRequestFailed": "이체요청이 실패하였습니다.",
|
"transferRequestFailed": "이체요청이 실패하였습니다.",
|
||||||
"transferRequestError": "이체요청 중 오류가 발생했습니다.",
|
"transferRequestError": "이체요청 중 오류가 발생했습니다.",
|
||||||
|
|||||||
@@ -160,13 +160,13 @@ export const AccountHolderSearchPage = () => {
|
|||||||
bankCode: bank,
|
bankCode: bank,
|
||||||
resultStatus: resultStatus
|
resultStatus: resultStatus
|
||||||
}).then((rs) => {
|
}).then((rs) => {
|
||||||
if (rs.status) {
|
// if (rs.status) {
|
||||||
setTimeout(() => {
|
// setTimeout(() => {
|
||||||
snackBar("다운로드가 완료되었습니다.");
|
// snackBar("다운로드가 완료되었습니다.");
|
||||||
}, 2000);
|
// }, 2000);
|
||||||
} else {
|
// } else {
|
||||||
snackBar("다운로드에 실패했습니다.")
|
// snackBar("다운로드에 실패했습니다.")
|
||||||
}
|
// }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
setEmailBottomSheetOn(false);
|
setEmailBottomSheetOn(false);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { useStore } from '@/shared/model/store';
|
|||||||
import { snackBar } from '@/shared/lib';
|
import { snackBar } from '@/shared/lib';
|
||||||
import { NumericFormat, PatternFormat } from 'react-number-format';
|
import { NumericFormat, PatternFormat } from 'react-number-format';
|
||||||
import { showAlert } from '@/widgets/show-alert';
|
import { showAlert } from '@/widgets/show-alert';
|
||||||
|
import { useKeyboardAware } from '@/shared/lib/hooks/use-keyboard-aware';
|
||||||
|
|
||||||
export const ArsRequestPage = () => {
|
export const ArsRequestPage = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -42,6 +43,8 @@ export const ArsRequestPage = () => {
|
|||||||
const [successPageOn, setSuccessPageOn] = useState<boolean>(false);
|
const [successPageOn, setSuccessPageOn] = useState<boolean>(false);
|
||||||
const [resultMessage, setResultMessage] = useState<string>('');
|
const [resultMessage, setResultMessage] = useState<string>('');
|
||||||
|
|
||||||
|
const { handleInputFocus, keyboardAwarePadding } = useKeyboardAware();
|
||||||
|
|
||||||
useSetHeaderTitle(t('additionalService.ars.paymentRequest'));
|
useSetHeaderTitle(t('additionalService.ars.paymentRequest'));
|
||||||
useSetHeaderType(HeaderType.LeftArrow);
|
useSetHeaderType(HeaderType.LeftArrow);
|
||||||
useSetFooterMode(false);
|
useSetFooterMode(false);
|
||||||
@@ -160,6 +163,7 @@ export const ArsRequestPage = () => {
|
|||||||
type="text"
|
type="text"
|
||||||
value={moid}
|
value={moid}
|
||||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setMoid(e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => setMoid(e.target.value)}
|
||||||
|
onFocus={handleInputFocus}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -171,6 +175,7 @@ export const ArsRequestPage = () => {
|
|||||||
type="text"
|
type="text"
|
||||||
value={goodsName}
|
value={goodsName}
|
||||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setGoodsName(e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => setGoodsName(e.target.value)}
|
||||||
|
onFocus={handleInputFocus}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -187,6 +192,7 @@ export const ArsRequestPage = () => {
|
|||||||
const { floatValue } = values;
|
const { floatValue } = values;
|
||||||
setAmount(floatValue ?? 0);
|
setAmount(floatValue ?? 0);
|
||||||
}}
|
}}
|
||||||
|
onFocus={handleInputFocus}
|
||||||
></NumericFormat>
|
></NumericFormat>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -211,6 +217,7 @@ export const ArsRequestPage = () => {
|
|||||||
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>
|
||||||
@@ -230,6 +237,7 @@ export const ArsRequestPage = () => {
|
|||||||
inputMode="numeric"
|
inputMode="numeric"
|
||||||
pattern="[0-9]*"
|
pattern="[0-9]*"
|
||||||
maxLength={11}
|
maxLength={11}
|
||||||
|
onFocus={handleInputFocus}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -243,12 +251,12 @@ export const ArsRequestPage = () => {
|
|||||||
placeholder='test@nicepay.co.kr'
|
placeholder='test@nicepay.co.kr'
|
||||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setEamil(e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => setEamil(e.target.value)}
|
||||||
className={email && !isValidEmail(email) ? 'error' : ''}
|
className={email && !isValidEmail(email) ? 'error' : ''}
|
||||||
|
onFocus={handleInputFocus}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="billing-row" style={{ paddingBottom: '60px' }}>
|
<div className="billing-row" style={keyboardAwarePadding}>
|
||||||
<div className="billing-label">{t('additionalService.ars.paymentMethod')} <span>*</span></div>
|
<div className="billing-label">{t('additionalService.ars.paymentMethod')} <span>*</span></div>
|
||||||
<div className="billing-field">
|
<div className="billing-field">
|
||||||
{getArsPaymentMethodBtns()}
|
{getArsPaymentMethodBtns()}
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ import { useStore } from '@/shared/model/store';
|
|||||||
import { snackBar } from '@/shared/lib';
|
import { snackBar } from '@/shared/lib';
|
||||||
import { useExtensionFundAccountTransferRegistMutation } from '@/entities/additional-service/api/fund-account/use-extension-fund-account-transfer-regist-mutation';
|
import { useExtensionFundAccountTransferRegistMutation } from '@/entities/additional-service/api/fund-account/use-extension-fund-account-transfer-regist-mutation';
|
||||||
import { NumericFormat } from 'react-number-format';
|
import { NumericFormat } from 'react-number-format';
|
||||||
import { useExtensionFundAccountTransferRequestMutation } from '@/entities/additional-service/api/fund-account/use-extension-fund-account-transfer-request-mutation';
|
|
||||||
import { showAlert } from '@/widgets/show-alert';
|
import { showAlert } from '@/widgets/show-alert';
|
||||||
|
import { useKeyboardAware } from '@/shared/lib/hooks/use-keyboard-aware';
|
||||||
|
|
||||||
|
|
||||||
export const FundAccountTransferRequestPage = () => {
|
export const FundAccountTransferRequestPage = () => {
|
||||||
@@ -32,6 +32,7 @@ export const FundAccountTransferRequestPage = () => {
|
|||||||
const [amount, setAmount] = useState<number>(0);
|
const [amount, setAmount] = useState<number>(0);
|
||||||
const [moid, setMoid] = useState<string>('');
|
const [moid, setMoid] = useState<string>('');
|
||||||
const [depositParameter, setDepositParameter] = useState<string>('');
|
const [depositParameter, setDepositParameter] = useState<string>('');
|
||||||
|
const { handleInputFocus, keyboardAwarePadding } = useKeyboardAware();
|
||||||
|
|
||||||
const { mutateAsync: extensionFundAccountRegist } = useExtensionFundAccountTransferRegistMutation();
|
const { mutateAsync: extensionFundAccountRegist } = useExtensionFundAccountTransferRegistMutation();
|
||||||
|
|
||||||
@@ -159,6 +160,7 @@ export const FundAccountTransferRequestPage = () => {
|
|||||||
return !value || value.length <= 14;
|
return !value || value.length <= 14;
|
||||||
}}
|
}}
|
||||||
onValueChange={(values) => setAccountNo(values.value)}
|
onValueChange={(values) => setAccountNo(values.value)}
|
||||||
|
onFocus={handleInputFocus}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -169,6 +171,7 @@ export const FundAccountTransferRequestPage = () => {
|
|||||||
type="text"
|
type="text"
|
||||||
value={accountName}
|
value={accountName}
|
||||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setAccountName(e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => setAccountName(e.target.value)}
|
||||||
|
onFocus={handleInputFocus}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -180,6 +183,7 @@ export const FundAccountTransferRequestPage = () => {
|
|||||||
allowNegative={false}
|
allowNegative={false}
|
||||||
thousandSeparator={true}
|
thousandSeparator={true}
|
||||||
displayType='input'
|
displayType='input'
|
||||||
|
onFocus={handleInputFocus}
|
||||||
onValueChange={(values) => {
|
onValueChange={(values) => {
|
||||||
const { floatValue } = values;
|
const { floatValue } = values;
|
||||||
setAmount(floatValue ?? 0);
|
setAmount(floatValue ?? 0);
|
||||||
@@ -194,16 +198,18 @@ export const FundAccountTransferRequestPage = () => {
|
|||||||
type="text"
|
type="text"
|
||||||
value={moid}
|
value={moid}
|
||||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setMoid(e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => setMoid(e.target.value)}
|
||||||
|
onFocus={handleInputFocus}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="billing-row">
|
<div className="billing-row" style={keyboardAwarePadding}>
|
||||||
<div className="billing-label">{t('additionalService.fundAccount.depositParameter')}</div>
|
<div className="billing-label">{t('additionalService.fundAccount.depositParameter')}</div>
|
||||||
<div className="billing-field">
|
<div className="billing-field">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={depositParameter}
|
value={depositParameter}
|
||||||
onChange={(e) => setDepositParameter(e.target.value)}
|
onChange={(e) => setDepositParameter(e.target.value)}
|
||||||
|
onFocus={handleInputFocus}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { ChangeEvent, useState } from 'react';
|
|||||||
import { PATHS } from '@/shared/constants/paths';
|
import { PATHS } from '@/shared/constants/paths';
|
||||||
import { useLocation } from 'react-router';
|
import { useLocation } from 'react-router';
|
||||||
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
||||||
import { IMAGE_ROOT } from '@/shared/constants/common';
|
|
||||||
import { HeaderType } from '@/entities/common/model/types';
|
import { HeaderType } from '@/entities/common/model/types';
|
||||||
import { useExtensionKeyinApplyMutation } from '@/entities/additional-service/api/use-extension-keyin-apply-mutation';
|
import { useExtensionKeyinApplyMutation } from '@/entities/additional-service/api/use-extension-keyin-apply-mutation';
|
||||||
import {
|
import {
|
||||||
@@ -11,13 +10,12 @@ import {
|
|||||||
useSetFooterMode,
|
useSetFooterMode,
|
||||||
useSetOnBack
|
useSetOnBack
|
||||||
} from '@/widgets/sub-layout/use-sub-layout';
|
} from '@/widgets/sub-layout/use-sub-layout';
|
||||||
import { overlay } from 'overlay-kit';
|
|
||||||
import { Dialog } from '@/shared/ui/dialogs/dialog';
|
|
||||||
import { useStore } from '@/shared/model/store';
|
import { useStore } from '@/shared/model/store';
|
||||||
import { snackBar } from '@/shared/lib';
|
import { snackBar } from '@/shared/lib';
|
||||||
import { NumericFormat, PatternFormat } from 'react-number-format';
|
import { NumericFormat, PatternFormat } from 'react-number-format';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { showAlert } from '@/widgets/show-alert';
|
import { showAlert } from '@/widgets/show-alert';
|
||||||
|
import { useKeyboardAware } from '@/shared/lib/hooks/use-keyboard-aware';
|
||||||
|
|
||||||
export const KeyInPaymentRequestPage = () => {
|
export const KeyInPaymentRequestPage = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -43,6 +41,7 @@ export const KeyInPaymentRequestPage = () => {
|
|||||||
const [orderNumber, setOrderNumber] = useState<string>('');
|
const [orderNumber, setOrderNumber] = useState<string>('');
|
||||||
|
|
||||||
const { mutateAsync: keyInApply } = useExtensionKeyinApplyMutation();
|
const { mutateAsync: keyInApply } = useExtensionKeyinApplyMutation();
|
||||||
|
const { handleInputFocus, keyboardAwarePadding } = useKeyboardAware();
|
||||||
|
|
||||||
useSetHeaderTitle(t('additionalService.keyIn.title'));
|
useSetHeaderTitle(t('additionalService.keyIn.title'));
|
||||||
useSetHeaderType(HeaderType.LeftArrow);
|
useSetHeaderType(HeaderType.LeftArrow);
|
||||||
@@ -191,6 +190,7 @@ export const KeyInPaymentRequestPage = () => {
|
|||||||
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>
|
||||||
@@ -218,6 +218,7 @@ export const KeyInPaymentRequestPage = () => {
|
|||||||
type="text"
|
type="text"
|
||||||
value={customerName}
|
value={customerName}
|
||||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setCustomerName(e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => setCustomerName(e.target.value)}
|
||||||
|
onFocus={handleInputFocus}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -230,6 +231,7 @@ export const KeyInPaymentRequestPage = () => {
|
|||||||
value={email}
|
value={email}
|
||||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setEmail(e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => setEmail(e.target.value)}
|
||||||
className={email && !isValidEmail(email) ? 'error' : ''}
|
className={email && !isValidEmail(email) ? 'error' : ''}
|
||||||
|
onFocus={handleInputFocus}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -249,6 +251,7 @@ export const KeyInPaymentRequestPage = () => {
|
|||||||
inputMode="numeric"
|
inputMode="numeric"
|
||||||
pattern="[0-9]*"
|
pattern="[0-9]*"
|
||||||
maxLength={11}
|
maxLength={11}
|
||||||
|
onFocus={handleInputFocus}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -262,6 +265,7 @@ export const KeyInPaymentRequestPage = () => {
|
|||||||
valueIsNumericString
|
valueIsNumericString
|
||||||
format="####"
|
format="####"
|
||||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setCardNo1(e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => setCardNo1(e.target.value)}
|
||||||
|
onFocus={handleInputFocus}
|
||||||
>
|
>
|
||||||
</PatternFormat>
|
</PatternFormat>
|
||||||
</div>
|
</div>
|
||||||
@@ -272,6 +276,7 @@ export const KeyInPaymentRequestPage = () => {
|
|||||||
valueIsNumericString
|
valueIsNumericString
|
||||||
format="####"
|
format="####"
|
||||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setCardNo2(e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => setCardNo2(e.target.value)}
|
||||||
|
onFocus={handleInputFocus}
|
||||||
>
|
>
|
||||||
</PatternFormat>
|
</PatternFormat>
|
||||||
</div>
|
</div>
|
||||||
@@ -282,6 +287,7 @@ export const KeyInPaymentRequestPage = () => {
|
|||||||
valueIsNumericString
|
valueIsNumericString
|
||||||
format="####"
|
format="####"
|
||||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setCardNo3(e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => setCardNo3(e.target.value)}
|
||||||
|
onFocus={handleInputFocus}
|
||||||
>
|
>
|
||||||
</PatternFormat>
|
</PatternFormat>
|
||||||
</div>
|
</div>
|
||||||
@@ -292,6 +298,7 @@ export const KeyInPaymentRequestPage = () => {
|
|||||||
valueIsNumericString
|
valueIsNumericString
|
||||||
format="####"
|
format="####"
|
||||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setCardNo4(e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => setCardNo4(e.target.value)}
|
||||||
|
onFocus={handleInputFocus}
|
||||||
>
|
>
|
||||||
</PatternFormat>
|
</PatternFormat>
|
||||||
</div>
|
</div>
|
||||||
@@ -315,6 +322,7 @@ export const KeyInPaymentRequestPage = () => {
|
|||||||
const { value } = values;
|
const { value } = values;
|
||||||
setExpMon(value);
|
setExpMon(value);
|
||||||
}}
|
}}
|
||||||
|
onFocus={handleInputFocus}
|
||||||
onBlur={() => {
|
onBlur={() => {
|
||||||
if (expMon.length === 1 && parseInt(expMon) >= 1 && parseInt(expMon) <= 9) {
|
if (expMon.length === 1 && parseInt(expMon) >= 1 && parseInt(expMon) <= 9) {
|
||||||
setExpMon(expMon.padStart(2, '0'));
|
setExpMon(expMon.padStart(2, '0'));
|
||||||
@@ -333,6 +341,7 @@ export const KeyInPaymentRequestPage = () => {
|
|||||||
const { value } = values;
|
const { value } = values;
|
||||||
setExpYear(value);
|
setExpYear(value);
|
||||||
}}
|
}}
|
||||||
|
onFocus={handleInputFocus}
|
||||||
style={{ flex: 1 }}
|
style={{ flex: 1 }}
|
||||||
inputMode="numeric"
|
inputMode="numeric"
|
||||||
/>
|
/>
|
||||||
@@ -367,13 +376,17 @@ export const KeyInPaymentRequestPage = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="billing-row">
|
<div
|
||||||
|
className="billing-row"
|
||||||
|
style={keyboardAwarePadding}
|
||||||
|
>
|
||||||
<div className="billing-label">{t('additionalService.keyIn.orderNumber')}<span>*</span></div>
|
<div className="billing-label">{t('additionalService.keyIn.orderNumber')}<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>
|
||||||
|
|||||||
@@ -2,4 +2,4 @@ export * from './use-navigate';
|
|||||||
export * from './use-fix-scroll-view-safari';
|
export * from './use-fix-scroll-view-safari';
|
||||||
export * from './use-navigate';
|
export * from './use-navigate';
|
||||||
export * from './use-router-listener';
|
export * from './use-router-listener';
|
||||||
|
export * from './use-keyboard-aware';
|
||||||
|
|||||||
88
src/shared/lib/hooks/use-keyboard-aware.ts
Normal file
88
src/shared/lib/hooks/use-keyboard-aware.ts
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
import { useEffect, useState, useMemo, CSSProperties } from 'react';
|
||||||
|
|
||||||
|
export interface UseKeyboardAwareOptions {
|
||||||
|
defaultPadding?: number;
|
||||||
|
heightRatio?: number;
|
||||||
|
maxPadding?: number;
|
||||||
|
transition?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useKeyboardAware = (options?: UseKeyboardAwareOptions) => {
|
||||||
|
const {
|
||||||
|
defaultPadding = 60,
|
||||||
|
heightRatio = 0.7,
|
||||||
|
maxPadding = 300,
|
||||||
|
transition = 'padding-bottom 0.2s ease'
|
||||||
|
} = options || {};
|
||||||
|
|
||||||
|
const [keyboardHeight, setKeyboardHeight] = useState<number>(0);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let focusedElement: HTMLInputElement | null = null;
|
||||||
|
let isKeyboardOpen = false;
|
||||||
|
|
||||||
|
// 네이티브에서 호출할 전역 함수 등록
|
||||||
|
(window as any).onKeyboardShow = (height: number) => {
|
||||||
|
console.log('Keyboard shown, height:', height);
|
||||||
|
const wasKeyboardOpen = isKeyboardOpen;
|
||||||
|
isKeyboardOpen = true;
|
||||||
|
setKeyboardHeight(height);
|
||||||
|
|
||||||
|
// 키보드가 새로 열릴 때만 스크롤 (이미 열려있으면 스크롤 안함)
|
||||||
|
if (!wasKeyboardOpen && focusedElement) {
|
||||||
|
setTimeout(() => {
|
||||||
|
focusedElement?.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||||
|
}, 250);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(window as any).onKeyboardHide = () => {
|
||||||
|
console.log('Keyboard hidden');
|
||||||
|
isKeyboardOpen = false;
|
||||||
|
setKeyboardHeight(0);
|
||||||
|
focusedElement = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
// focus된 요소를 추적하기 위한 함수
|
||||||
|
(window as any).setFocusedElement = (element: HTMLInputElement) => {
|
||||||
|
focusedElement = element;
|
||||||
|
|
||||||
|
// 키보드가 이미 열려있으면 즉시 스크롤
|
||||||
|
if (isKeyboardOpen) {
|
||||||
|
setTimeout(() => {
|
||||||
|
element.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
delete (window as any).onKeyboardShow;
|
||||||
|
delete (window as any).onKeyboardHide;
|
||||||
|
delete (window as any).setFocusedElement;
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// 모든 input에서 사용할 공통 핸들러
|
||||||
|
const handleInputFocus = (e: React.FocusEvent<HTMLInputElement>) => {
|
||||||
|
// focus된 요소를 저장
|
||||||
|
(window as any).setFocusedElement?.(e.target);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 동적 패딩 스타일 계산
|
||||||
|
const keyboardAwarePadding: CSSProperties = useMemo(() => {
|
||||||
|
const calculatedPadding = keyboardHeight > 0
|
||||||
|
? Math.min(keyboardHeight * heightRatio, maxPadding)
|
||||||
|
: defaultPadding;
|
||||||
|
|
||||||
|
return {
|
||||||
|
paddingBottom: `${calculatedPadding}px`,
|
||||||
|
transition
|
||||||
|
};
|
||||||
|
}, [keyboardHeight, defaultPadding, heightRatio, maxPadding, transition]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
keyboardHeight,
|
||||||
|
handleInputFocus,
|
||||||
|
keyboardAwarePadding
|
||||||
|
};
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user