- 안드로이드 알림 설정 AppBridge 추가
- KeyIn Request 필드 수정
This commit is contained in:
@@ -19,7 +19,7 @@ import { useExtensionKeyinListMutation } from '@/entities/additional-service/api
|
||||
import { DEFAULT_PAGE_PARAM } from '@/entities/common/model/constant';
|
||||
import { KeyInPaymentList } from '@/entities/additional-service/ui/key-in-payment/key-in-payment-list';
|
||||
import { useStore } from '@/shared/model/store';
|
||||
import { KeyInPaymentListItem, KeyInPaymentPaymentStatus } from '@/entities/additional-service/model/key-in/types';
|
||||
import { KeyInPaymentListItem, KeyInPaymentStatus, KeyInPaymentTansactionType } from '@/entities/additional-service/model/key-in/types';
|
||||
import { keyInPaymentPaymentStatusBtnGroup } from '@/entities/additional-service/model/key-in/constant';
|
||||
import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet';
|
||||
import { useExtensionAccessCheck } from '@/shared/lib/hooks/use-extension-access-check';
|
||||
@@ -40,9 +40,10 @@ export const KeyInPaymentPage = () => {
|
||||
const [filterOn, setFilterOn] = useState<boolean>(false);
|
||||
const [pageParam, setPageParam] = useState<DefaultRequestPagination>(DEFAULT_PAGE_PARAM);
|
||||
const [mid, setMid] = useState<string>(userMid);
|
||||
const [startDate, setStartDate] = useState(moment().format('YYYY-MM-DD'));
|
||||
const [endDate, setEndDate] = useState(moment().format('YYYY-MM-DD'));
|
||||
const [paymentStatus, setPaymentStatus] = useState<KeyInPaymentPaymentStatus>(KeyInPaymentPaymentStatus.ALL)
|
||||
const [startDate, setStartDate] = useState(moment().format('YYYYMMDD'));
|
||||
const [endDate, setEndDate] = useState(moment().format('YYYYMMDD'));
|
||||
const [transactionType, setTransactionType] = useState<KeyInPaymentTansactionType>(KeyInPaymentTansactionType.ALL)
|
||||
const [status, setStatus] = useState<KeyInPaymentStatus>(KeyInPaymentStatus.ALL);
|
||||
const [minAmount, setMinAmount] = useState<number>();
|
||||
const [maxAmount, setMaxAmount] = useState<number>();
|
||||
const [emailBottomSheetOn, setEmailBottomSheetOn] = useState<boolean>(false);
|
||||
@@ -72,13 +73,15 @@ export const KeyInPaymentPage = () => {
|
||||
onIntersect
|
||||
});
|
||||
|
||||
// 목록 조회
|
||||
const callList = (type?: string) => {
|
||||
setOnActionIntersect(false);
|
||||
let listParams = {
|
||||
mid: mid,
|
||||
fromDate: startDate,
|
||||
toDate: endDate,
|
||||
paymentStatus: paymentStatus,
|
||||
startDate: startDate,
|
||||
endDate: endDate,
|
||||
transactionType: transactionType,
|
||||
status: status,
|
||||
minAmount: minAmount,
|
||||
maxAmount: maxAmount,
|
||||
page: {
|
||||
@@ -131,13 +134,14 @@ export const KeyInPaymentPage = () => {
|
||||
setEmailBottomSheetOn(true);
|
||||
};
|
||||
|
||||
// 엑셀 다운로드
|
||||
const onSendRequest = (selectedEmail?: string) => {
|
||||
if (selectedEmail) {
|
||||
downloadExcel({
|
||||
mid: mid,
|
||||
fromDate: startDate,
|
||||
toDate: endDate,
|
||||
paymentStatus: paymentStatus,
|
||||
paymentStatus: transactionType,
|
||||
minAmount: minAmount,
|
||||
maxAmount: maxAmount,
|
||||
//email: selectedEmail
|
||||
@@ -152,8 +156,8 @@ export const KeyInPaymentPage = () => {
|
||||
setSortType(sort);
|
||||
};
|
||||
|
||||
const onClickToPaymentStatus = (val: KeyInPaymentPaymentStatus) => {
|
||||
setPaymentStatus(val);
|
||||
const onClickToPaymentStatus = (val: KeyInPaymentTansactionType) => {
|
||||
setTransactionType(val);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@@ -162,7 +166,7 @@ export const KeyInPaymentPage = () => {
|
||||
mid,
|
||||
startDate,
|
||||
endDate,
|
||||
paymentStatus,
|
||||
transactionType,
|
||||
minAmount,
|
||||
maxAmount,
|
||||
sortType
|
||||
@@ -222,7 +226,7 @@ export const KeyInPaymentPage = () => {
|
||||
keyInPaymentPaymentStatusBtnGroup.map((value, index) => (
|
||||
<span
|
||||
key={`key-service-code=${index}`}
|
||||
className={`keyword-tag ${(paymentStatus === value.value) ? 'active' : ''}`}
|
||||
className={`keyword-tag ${(transactionType === value.value) ? 'active' : ''}`}
|
||||
onClick={() => onClickToPaymentStatus(value.value)}
|
||||
>{value.name}</span>
|
||||
))
|
||||
@@ -245,13 +249,13 @@ export const KeyInPaymentPage = () => {
|
||||
mid={mid}
|
||||
startDate={startDate}
|
||||
endDate={endDate}
|
||||
transactionStatus={paymentStatus}
|
||||
transactionStatus={transactionType}
|
||||
minAmount={minAmount}
|
||||
maxAmount={maxAmount}
|
||||
setMid={setMid}
|
||||
setStartDate={setStartDate}
|
||||
setEndDate={setEndDate}
|
||||
setTransactionStatus={setPaymentStatus}
|
||||
setTransactionStatus={setTransactionType}
|
||||
setMinAmount={setMinAmount}
|
||||
setMaxAmount={setMaxAmount}
|
||||
></KeyInPaymentFilter>
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
import { overlay } from 'overlay-kit';
|
||||
import { Dialog } from '@/shared/ui/dialogs/dialog';
|
||||
import { useStore } from '@/shared/model/store';
|
||||
import { snackBar } from '@/shared/lib';
|
||||
|
||||
export const KeyInPaymentRequestPage = () => {
|
||||
const { navigate } = useNavigate();
|
||||
@@ -22,19 +23,19 @@ export const KeyInPaymentRequestPage = () => {
|
||||
const userMid = useStore.getState().UserStore.mid;
|
||||
|
||||
const [mid, setMid] = useState<string>(userMid || '');
|
||||
const [goodsName, setGoodsName] = useState<string>('');
|
||||
const [productName, setProductName] = useState<string>('');
|
||||
const [amount, setAmount] = useState<number>(0);
|
||||
const [buyerName, setBuyerName] = useState<string>('');
|
||||
const [customerName, setCustomerName] = 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 [expMon, setExpMon] = useState<string>('');
|
||||
const [expYear, setExpYear] = useState<string>('');
|
||||
const [instmnt, setInstmnt] = useState<string>('00');
|
||||
const [orderNumber, setOrderNumber] = useState<string>('');
|
||||
|
||||
const { mutateAsync: keyInApply } = useExtensionKeyinApplyMutation();
|
||||
|
||||
@@ -46,43 +47,43 @@ export const KeyInPaymentRequestPage = () => {
|
||||
});
|
||||
|
||||
const resetForm = () => {
|
||||
setGoodsName('');
|
||||
setProductName('');
|
||||
setAmount(0);
|
||||
setBuyerName('');
|
||||
setCustomerName('');
|
||||
setEmail('');
|
||||
setPhoneNumber('');
|
||||
setCardNo1('');
|
||||
setCardNo2('');
|
||||
setCardNo3('');
|
||||
setCardNo4('');
|
||||
setCardExpirationMonth('');
|
||||
setCardExpirationYear('');
|
||||
setInstmntMonth('00');
|
||||
setMoid('');
|
||||
setExpMon('');
|
||||
setExpYear('');
|
||||
setInstmnt('00');
|
||||
setOrderNumber('');
|
||||
};
|
||||
|
||||
const callKeyInPaymentRequest = () => {
|
||||
const cardNo = `${cardNo1}${cardNo2}${cardNo3}${cardNo4}`;
|
||||
const cardExpirationDate = `${cardExpirationMonth}${cardExpirationYear}`;
|
||||
|
||||
let keyInApplyParams = {
|
||||
mid: mid,
|
||||
goodsName: goodsName,
|
||||
amount: amount,
|
||||
buyerName: buyerName,
|
||||
email: email,
|
||||
phoneNumber: phoneNumber,
|
||||
cardNo: cardNo,
|
||||
cardExpirationDate: cardExpirationDate,
|
||||
instmntMonth: instmntMonth,
|
||||
moid: moid,
|
||||
expYear: expYear,
|
||||
expMon: expMon,
|
||||
instmnt: instmnt,
|
||||
amount: amount,
|
||||
productName: productName,
|
||||
orderNumber: orderNumber,
|
||||
customerName: customerName,
|
||||
phoneNumber: phoneNumber,
|
||||
email: email,
|
||||
};
|
||||
|
||||
keyInApply(keyInApplyParams).then((rs) => {
|
||||
console.log('결제 응답:', rs);
|
||||
if (rs.status) {
|
||||
// 성공: 화면 유지 & 입력 내용 초기화
|
||||
showSuccessDialog();
|
||||
snackBar("KEY-IN 결제 신청을 성공하였습니다.")
|
||||
resetForm();
|
||||
} else {
|
||||
// 실패: 화면 유지 & 입력 내용 유지
|
||||
@@ -140,19 +141,19 @@ export const KeyInPaymentRequestPage = () => {
|
||||
};
|
||||
|
||||
const isValidCardExpiration = () => {
|
||||
if (cardExpirationMonth.length !== 2 || cardExpirationYear.length !== 2) {
|
||||
if (expMon.length !== 2 || expYear.length !== 2) {
|
||||
return false;
|
||||
}
|
||||
const month = parseInt(cardExpirationMonth);
|
||||
const month = parseInt(expMon);
|
||||
return month >= 1 && month <= 12;
|
||||
};
|
||||
|
||||
const isFormValid = () => {
|
||||
return (
|
||||
mid.trim() !== '' &&
|
||||
goodsName.trim() !== '' &&
|
||||
productName.trim() !== '' &&
|
||||
amount > 0 &&
|
||||
buyerName.trim() !== '' &&
|
||||
customerName.trim() !== '' &&
|
||||
isValidEmail(email) &&
|
||||
isValidPhoneNumber(phoneNumber) &&
|
||||
isValidCardNumber() &&
|
||||
@@ -187,8 +188,8 @@ export const KeyInPaymentRequestPage = () => {
|
||||
<div className="billing-field">
|
||||
<input
|
||||
type="text"
|
||||
value={goodsName}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setGoodsName(e.target.value)}
|
||||
value={productName}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setProductName(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -215,8 +216,8 @@ export const KeyInPaymentRequestPage = () => {
|
||||
<div className="billing-field">
|
||||
<input
|
||||
type="text"
|
||||
value={buyerName}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setBuyerName(e.target.value)}
|
||||
value={customerName}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setCustomerName(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -318,10 +319,10 @@ export const KeyInPaymentRequestPage = () => {
|
||||
<div className="billing-field" style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>
|
||||
<input
|
||||
type="text"
|
||||
value={cardExpirationMonth}
|
||||
value={expMon}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) => {
|
||||
const onlyNumbers = e.target.value.replace(/[^0-9]/g, '');
|
||||
if (onlyNumbers.length <= 2) setCardExpirationMonth(onlyNumbers);
|
||||
if (onlyNumbers.length <= 2) setExpMon(onlyNumbers);
|
||||
}}
|
||||
inputMode="numeric"
|
||||
pattern="[0-9]*"
|
||||
@@ -332,10 +333,10 @@ export const KeyInPaymentRequestPage = () => {
|
||||
<span>/</span>
|
||||
<input
|
||||
type="text"
|
||||
value={cardExpirationYear}
|
||||
value={expYear}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) => {
|
||||
const onlyNumbers = e.target.value.replace(/[^0-9]/g, '');
|
||||
if (onlyNumbers.length <= 2) setCardExpirationYear(onlyNumbers);
|
||||
if (onlyNumbers.length <= 2) setExpYear(onlyNumbers);
|
||||
}}
|
||||
inputMode="numeric"
|
||||
pattern="[0-9]*"
|
||||
@@ -351,8 +352,8 @@ export const KeyInPaymentRequestPage = () => {
|
||||
<div className="billing-field">
|
||||
<select
|
||||
disabled={amount < 50000}
|
||||
value={instmntMonth}
|
||||
onChange={(e: ChangeEvent<HTMLSelectElement>) => setInstmntMonth(e.target.value)}
|
||||
value={instmnt}
|
||||
onChange={(e: ChangeEvent<HTMLSelectElement>) => setInstmnt(e.target.value)}
|
||||
>
|
||||
<option value="00">일시불 (무이자)</option>
|
||||
{amount >= 50000 && (
|
||||
@@ -379,8 +380,8 @@ export const KeyInPaymentRequestPage = () => {
|
||||
<div className="billing-field">
|
||||
<input
|
||||
type="text"
|
||||
value={moid}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setMoid(e.target.value)}
|
||||
value={orderNumber}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setOrderNumber(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -154,21 +154,21 @@ export const LinkPaymentDetailPage = () => {
|
||||
additionalServiceCategory={AdditionalServiceCategory.LinkPaymentHistory}
|
||||
detailInfo={detailInfo}
|
||||
></DetailInfoWrap>
|
||||
<div className="link-payment-detail-button">
|
||||
<button
|
||||
className="btn-50 btn-blue flex-1"
|
||||
onClick={() => onClickToSeparateApproval()}
|
||||
disabled={false}
|
||||
>분리승인 상세</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="apply-row">
|
||||
<button
|
||||
className="btn-50 btn-blue flex-1"
|
||||
onClick={() => onClickToSeparateApproval()}
|
||||
disabled={false}
|
||||
>분리승인 상세</button>
|
||||
</div>
|
||||
{/* <div className="apply-row">
|
||||
<button
|
||||
className="btn-50 btn-blue flex-1"
|
||||
onClick={() => onClickToResend()}
|
||||
disabled={!isResendEnabled()}
|
||||
>재발송</button>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main >
|
||||
|
||||
@@ -16,7 +16,15 @@ import { useAppBridge } from '@/hooks/useAppBridge';
|
||||
|
||||
export const SettingPage = () => {
|
||||
let userInfo = useStore.getState().UserStore.userInfo;
|
||||
const { isPushNotificationEnabled, openAppSettings, logout, getLoginType } = useAppBridge();
|
||||
const {
|
||||
isPushNotificationEnabled,
|
||||
openAppSettings,
|
||||
logout,
|
||||
getLoginType,
|
||||
getNotificationSetting,
|
||||
setNotificationSetting: updateNotificationSetting,
|
||||
isAndroid
|
||||
} = useAppBridge();
|
||||
|
||||
useSetHeaderTitle('설정');
|
||||
useSetHeaderType(HeaderType.LeftArrow);
|
||||
@@ -31,6 +39,7 @@ export const SettingPage = () => {
|
||||
const {mutateAsync: appAlarmConsent} = useAppAlarmConsentMutation();
|
||||
|
||||
const [pushNotificationEnabled, setPushNotificationEnabled] = useState<boolean>(false);
|
||||
const [notificationSetting, setNotificationSetting] = useState<boolean>(true);
|
||||
const [alarmSetting, setAlarmSetting] = useState<Record<string, boolean>>({
|
||||
'21': false,
|
||||
'11': false,
|
||||
@@ -65,7 +74,74 @@ export const SettingPage = () => {
|
||||
const onClickPushNotificationToggle = () => {
|
||||
openAppSettings();
|
||||
};
|
||||
|
||||
|
||||
// 알림 설정 로드 (Android만)
|
||||
const loadNotificationSetting = useCallback(async () => {
|
||||
if (!isAndroid) {
|
||||
console.log('[loadNotificationSetting] Not Android, skipping');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
console.log('[loadNotificationSetting] Calling getNotificationSetting()...');
|
||||
const enabled = await getNotificationSetting();
|
||||
console.log('[loadNotificationSetting] Received value from bridge:', enabled);
|
||||
console.log('[loadNotificationSetting] Type of enabled:', typeof enabled);
|
||||
|
||||
setNotificationSetting(enabled);
|
||||
console.log('[loadNotificationSetting] State updated to:', enabled);
|
||||
} catch (error) {
|
||||
console.error('[loadNotificationSetting] Failed to load notification setting:', error);
|
||||
}
|
||||
}, [isAndroid, getNotificationSetting]);
|
||||
|
||||
// 알림 설정 토글 핸들러 (Android만)
|
||||
const onClickNotificationSettingToggle = useCallback(async () => {
|
||||
if (!isAndroid) {
|
||||
console.log('[onClickNotificationSettingToggle] Not Android, skipping');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const newValue = !notificationSetting;
|
||||
console.log('[onClickNotificationSettingToggle] to save:', newValue);
|
||||
|
||||
const result = await updateNotificationSetting(newValue);
|
||||
console.log('[onClickNotificationSettingToggle] result:', result);
|
||||
|
||||
// ✅ needsPermission이 true이면 설정 화면으로 이동한 것
|
||||
if (result && typeof result === 'object' && 'needsPermission' in result && result.needsPermission) {
|
||||
console.log('[onClickNotificationSettingToggle] Permission needed - opened settings');
|
||||
// 설정이 변경되지 않았으므로 상태 유지
|
||||
return;
|
||||
}
|
||||
|
||||
// ✅ 성공한 경우에만 상태 업데이트
|
||||
if (result && typeof result === 'object' && 'enabled' in result) {
|
||||
setNotificationSetting(result.enabled);
|
||||
console.log('[onClickNotificationSettingToggle] State updated to:', result.enabled);
|
||||
} else {
|
||||
// Fallback
|
||||
setNotificationSetting(newValue);
|
||||
console.log('[onClickNotificationSettingToggle] State updated to (fallback):', newValue);
|
||||
}
|
||||
|
||||
// ✅ 저장 후 바로 다시 읽어서 확인
|
||||
console.log('[onClickNotificationSettingToggle] Verifying saved value...');
|
||||
const verifyValue = await getNotificationSetting();
|
||||
console.log('[onClickNotificationSettingToggle] Verified value:', verifyValue);
|
||||
|
||||
if (verifyValue !== result?.enabled && !result?.needsPermission) {
|
||||
console.error('[onClickNotificationSettingToggle] WARNING: Saved value != Verified value', {
|
||||
saved: result?.enabled,
|
||||
verified: verifyValue
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[onClickNotificationSettingToggle] Failed to update notification setting:', error);
|
||||
}
|
||||
}, [isAndroid, notificationSetting, updateNotificationSetting, getNotificationSetting]);
|
||||
|
||||
const callAppAlarmFind = () => {
|
||||
if(userInfo.usrid){
|
||||
let params: AppAlarmFindParams = {
|
||||
@@ -115,16 +191,19 @@ export const SettingPage = () => {
|
||||
callAppAlarmFind();
|
||||
checkPushNotificationStatus();
|
||||
loadLoginType();
|
||||
loadNotificationSetting(); // ✅ 추가
|
||||
|
||||
// 앱이 포어그라운드로 돌아올 때 푸시 알림 권한 상태 재확인
|
||||
const handleVisibilityChange = () => {
|
||||
if (document.visibilityState === 'visible') {
|
||||
checkPushNotificationStatus();
|
||||
loadNotificationSetting(); // ✅ 추가
|
||||
}
|
||||
};
|
||||
|
||||
const handleFocus = () => {
|
||||
checkPushNotificationStatus();
|
||||
loadNotificationSetting(); // ✅ 추가
|
||||
};
|
||||
|
||||
document.addEventListener('visibilitychange', handleVisibilityChange);
|
||||
@@ -134,20 +213,28 @@ export const SettingPage = () => {
|
||||
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
||||
window.removeEventListener('focus', handleFocus);
|
||||
};
|
||||
}, [checkPushNotificationStatus, loadLoginType]);
|
||||
}, [checkPushNotificationStatus, loadLoginType, loadNotificationSetting]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<main className="pop">
|
||||
<div className="sub-wrap">
|
||||
{/* ✅ Android일 때는 앱 내 설정, 아니면 시스템 권한 표시 */}
|
||||
<div className="settings-header">
|
||||
<div className="settings-title">알림 수신 설정</div>
|
||||
<label className="settings-switch" onClick={onClickPushNotificationToggle}>
|
||||
<label className="settings-switch">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={pushNotificationEnabled}
|
||||
checked={isAndroid ? notificationSetting : pushNotificationEnabled}
|
||||
readOnly
|
||||
onClick={(e) => e.preventDefault()}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
if (isAndroid) {
|
||||
onClickNotificationSettingToggle();
|
||||
} else {
|
||||
onClickPushNotificationToggle();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<span className="slider"></span>
|
||||
</label>
|
||||
|
||||
Reference in New Issue
Block a user