From e125a73228eb8577a21dae998bc220efc993a305 Mon Sep 17 00:00:00 2001 From: HyeonJongKim Date: Tue, 28 Oct 2025 11:33:24 +0900 Subject: [PATCH] =?UTF-8?q?-=20=EC=95=88=EB=93=9C=EB=A1=9C=EC=9D=B4?= =?UTF-8?q?=EB=93=9C=20=EC=95=8C=EB=A6=BC=20=EC=84=A4=EC=A0=95=20AppBridge?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80=20-=20KeyIn=20Request=20=ED=95=84?= =?UTF-8?q?=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + .../additional-service/model/ars/types.ts | 4 +- .../model/key-in/constant.ts | 10 +- .../additional-service/model/key-in/types.ts | 59 +++++++---- .../filter/key-in-payment-filter.tsx | 4 +- .../ui/key-in-payment/key-in-payment-list.tsx | 12 +-- .../additional-service/ui/list-date-group.tsx | 6 ++ .../additional-service/ui/list-item.tsx | 5 +- src/hooks/useAppBridge.tsx | 53 ++++++++-- .../key-in-payment/key-in-payment-page.tsx | 32 +++--- .../key-in-payment/requeset-page.tsx | 77 ++++++++------- .../link-payment/link-payment-detail-page.tsx | 16 +-- src/pages/setting/setting-page.tsx | 99 +++++++++++++++++-- src/shared/ui/assets/css/style-fix.css | 10 ++ src/types/bridge.ts | 13 ++- src/utils/appBridge.ts | 10 ++ 16 files changed, 298 insertions(+), 113 deletions(-) diff --git a/package.json b/package.json index 52a92ba..f3856c6 100644 --- a/package.json +++ b/package.json @@ -105,6 +105,7 @@ "@tanstack/router-plugin": "^1.131.41", "@types/react": "^19.1.12", "@types/react-dom": "^19.1.9", + "@types/ua-parser-js": "^0.7.39", "@typescript-eslint/eslint-plugin": "^8.43.0", "@typescript-eslint/parser": "^8.43.0", "@vitejs/plugin-react": "^4.7.0", diff --git a/src/entities/additional-service/model/ars/types.ts b/src/entities/additional-service/model/ars/types.ts index f064c1f..7dd13b8 100644 --- a/src/entities/additional-service/model/ars/types.ts +++ b/src/entities/additional-service/model/ars/types.ts @@ -23,7 +23,9 @@ export interface ExtensionArsResendParams { mid: string; tid: string; }; -export interface ExtensionArsResendResponse {}; +export interface ExtensionArsResendResponse { + status: boolean; +}; export interface ExtensionArsListParams { mid?: string; moid?: string; diff --git a/src/entities/additional-service/model/key-in/constant.ts b/src/entities/additional-service/model/key-in/constant.ts index abb08437..89cb73a 100644 --- a/src/entities/additional-service/model/key-in/constant.ts +++ b/src/entities/additional-service/model/key-in/constant.ts @@ -1,11 +1,11 @@ -import { KeyInPaymentPaymentStatus } from "./types"; +import { KeyInPaymentTansactionType } from "./types"; // contant로 옮기기 export const keyInPaymentPaymentStatusBtnGroup = [ - { name: '전체', value: KeyInPaymentPaymentStatus.ALL }, - { name: '승인', value: KeyInPaymentPaymentStatus.APPROVAL }, - { name: '전취소', value: KeyInPaymentPaymentStatus.PRE_CANCEL }, - { name: '후취소', value: KeyInPaymentPaymentStatus.POST_CANCEL } + { name: '전체', value: KeyInPaymentTansactionType.ALL }, + { name: '승인', value: KeyInPaymentTansactionType.APPROVAL }, + { name: '전취소', value: KeyInPaymentTansactionType.FULL_CANCEL }, + { name: '후취소', value: KeyInPaymentTansactionType.PARTIAL_CANCEL } ]; export const getKeyInPaymentPaymentStatusName = (status?: string): string => { diff --git a/src/entities/additional-service/model/key-in/types.ts b/src/entities/additional-service/model/key-in/types.ts index 5049559..a090bd9 100644 --- a/src/entities/additional-service/model/key-in/types.ts +++ b/src/entities/additional-service/model/key-in/types.ts @@ -4,18 +4,30 @@ import { AdditionalServiceCategory, ExtensionRequestParams, FilterProps } from " // ======================================== // 키인결제 관련 타입들 // ======================================== -export enum KeyInPaymentPaymentStatus { +export enum KeyInPaymentTansactionType { ALL = 'ALL', APPROVAL = 'APPROVAL', - PRE_CANCEL = 'PRE_CANCEL', - POST_CANCEL = 'POST_CANCEL' + FULL_CANCEL = 'FULL_CANCEL', + PARTIAL_CANCEL = 'PARTIAL_CANCEL' +} + +export enum KeyInPaymentStatus { + ALL = 'ALL', + REGISTRED = 'REGISTRED', + WAITING = 'WAITING', + PROCESSING = 'PROCESSING', + COMPLETED = 'COMPLETED' } export interface KeyInPaymentListItem { + transactionDate?: string; + transactionTime?: string; + customerName?: string; + transactionCode?: string; tid?: string; - paymentDate?: string; - paymentStatus?: string; amount?: number; + statusLabel?: string; + transactionType?: string; } export interface KeyInPaymentListProps { @@ -28,13 +40,13 @@ export interface KeyInPaymentFilterProps extends FilterProps { mid: string, startDate: string; endDate: string; - transactionStatus: KeyInPaymentPaymentStatus; + transactionStatus: KeyInPaymentTansactionType; minAmount?: number; maxAmount?: number; setMid: (mid: string) => void; setStartDate: (startDate: string) => void; setEndDate: (endDate: string) => void; - setTransactionStatus: (transactionStatus: KeyInPaymentPaymentStatus) => void; + setTransactionStatus: (transactionStatus: KeyInPaymentTansactionType) => void; setMinAmount: (minAmount?: number) => void; setMaxAmount: (maxAmount?: number) => void; } @@ -42,19 +54,25 @@ export interface KeyInPaymentFilterProps extends FilterProps { // KEY-IN 결제 확장 서비스 // ======================================== export interface ExtensionKeyinListParams extends ExtensionRequestParams { - fromDate: string; - toDate: string; - paymentStatus: string; + startDate: string; + endDate: string; + transactionType: string; + status: string; minAmount?: number; maxAmount?: number; page?: DefaultRequestPagination; } export interface ExtensionKeyinListItemProps { + transactionDate: string; + transactionTime: string; + customerName: string; + transactionCode: string; tid: string; - paymentDate: string; - paymentStatus: string; amount: number; + statusLabel: string; + transactionType: string; + status: string; } export interface ExtensionKeyinListResponse extends DefaulResponsePagination { @@ -74,15 +92,16 @@ export interface ExtensionKeyinDownloadExcelResponse { } export interface ExtensionKeyinApplyParams extends ExtensionRequestParams { - goodsName: string; - amount: number; - buyerName: string; - email: string; - phoneNumber: string; cardNo: string; - cardExpirationDate: string; - instmntMonth: string; - moid: string; + expYear: string; + expMon: string; + instmnt: string; + amount: number; + productName: string; + orderNumber: string; + customerName: string; + phoneNumber: string; + email: string; } export interface ExtensionKeyinApplyResponse { diff --git a/src/entities/additional-service/ui/key-in-payment/filter/key-in-payment-filter.tsx b/src/entities/additional-service/ui/key-in-payment/filter/key-in-payment-filter.tsx index 1d3ff8e..25feff9 100644 --- a/src/entities/additional-service/ui/key-in-payment/filter/key-in-payment-filter.tsx +++ b/src/entities/additional-service/ui/key-in-payment/filter/key-in-payment-filter.tsx @@ -8,7 +8,7 @@ import { FilterButtonGroups } from '@/shared/ui/filter/button-groups'; import { FilterRangeAmount } from '@/shared/ui/filter/range-amount'; import { FilterMotionDuration, FilterMotionStyle, FilterMotionVariants } from '@/entities/common/model/constant'; import { useStore } from '@/shared/model/store'; -import { KeyInPaymentFilterProps, KeyInPaymentPaymentStatus } from '@/entities/additional-service/model/key-in/types'; +import { KeyInPaymentFilterProps, KeyInPaymentTansactionType } from '@/entities/additional-service/model/key-in/types'; import { keyInPaymentPaymentStatusBtnGroup } from '@/entities/additional-service/model/key-in/constant'; export const KeyInPaymentFilter = ({ @@ -31,7 +31,7 @@ export const KeyInPaymentFilter = ({ const [filterMid, setFilterMid] = useState(mid); const [filterStartDate, setFilterStartDate] = useState(startDate); const [filterEndDate, setFilterEndDate] = useState(endDate); - const [filterTransactionStatus, setFilterTransactionStatus] = useState(transactionStatus); + const [filterTransactionStatus, setFilterTransactionStatus] = useState(transactionStatus); const [filterMinAmount, setFilterMinAmount] = useState(minAmount); const [filterMaxAmount, setFilterMaxAmount] = useState(maxAmount); diff --git a/src/entities/additional-service/ui/key-in-payment/key-in-payment-list.tsx b/src/entities/additional-service/ui/key-in-payment/key-in-payment-list.tsx index 281a38a..ed63f5d 100644 --- a/src/entities/additional-service/ui/key-in-payment/key-in-payment-list.tsx +++ b/src/entities/additional-service/ui/key-in-payment/key-in-payment-list.tsx @@ -18,13 +18,13 @@ export const KeyInPaymentList = ({ for (let i = 0; i < listItems.length; i++) { let items = listItems[i]; if (!!items) { - let paymentDate = items?.paymentDate; - paymentDate = paymentDate?.substring(0, 8) - if (!!paymentDate) { + let transactionDate = items?.transactionDate; + transactionDate = transactionDate?.substring(0, 8) + if (!!transactionDate) { if (i === 0) { - date = paymentDate; + date = transactionDate; } - if (date !== paymentDate) { + if (date !== transactionDate) { if (list.length > 0) { rs.push( ); } - date = paymentDate; + date = transactionDate; list = []; } list.push(items); diff --git a/src/entities/additional-service/ui/list-date-group.tsx b/src/entities/additional-service/ui/list-date-group.tsx index 55ff20d..6e0d205 100644 --- a/src/entities/additional-service/ui/list-date-group.tsx +++ b/src/entities/additional-service/ui/list-date-group.tsx @@ -38,6 +38,12 @@ export const ListDateGroup = ({ resultStatus={ items[i]?.resultStatus } resultMessage={ items[i]?.resultMessage } applicationDate={ items[i]?.applicationDate } + transactionTime={ items[i]?.transactionTime } + transactionDate={ items[i]?.transactionDate } + transactionCode={ items[i]?.transactionCode } + transactionType={ items[i]?.transactionType } + customerName={ items[i]?.customerName } + statusLabel={ items[i]?.statusLabel } amount={ items[i]?.amount } sendDate={ items[i]?.sendDate } diff --git a/src/entities/additional-service/ui/list-item.tsx b/src/entities/additional-service/ui/list-item.tsx index 10ed1a9..34cd57c 100644 --- a/src/entities/additional-service/ui/list-item.tsx +++ b/src/entities/additional-service/ui/list-item.tsx @@ -24,7 +24,6 @@ export const ListItem = ({ accountName, submallId, settlementDate, companyName, - status: disbursementStatus, amount: disbursementAmount, orderStatus, arsPaymentMethod, @@ -452,7 +451,7 @@ export const ListItem = ({ else if (additionalServiceCategory === AdditionalServiceCategory.Payout) { rs.push(
- {getPayoutStatusText(disbursementStatus)} + {getPayoutStatusText(status)} | {submallId}
@@ -580,7 +579,7 @@ export const ListItem = ({ className="transaction-amount" > Promise; navigateTo: (path: string) => Promise; navigateToLogin: () => Promise; closeWebView: () => Promise; - + // 알림 showToast: (message: string, duration?: number) => Promise; showAlert: (title: string, message: string) => Promise; showConfirm: (title: string, message: string) => Promise; - + // 저장소 setStorage: (key: string, value: unknown) => Promise; // getStorage: (key: string) => Promise; removeStorage: (key: string) => Promise; - + /* // 미디어 openCamera: (options?: { quality?: number; allowEdit?: boolean }) => Promise; @@ -62,11 +62,15 @@ interface UseAppBridgeReturn { // 로그인 방식 설정 조회 getLoginType: () => Promise; + + getNotificationSetting: () => Promise; + + setNotificationSetting: (enabled: boolean) => Promise; } export const useAppBridge = (): UseAppBridgeReturn => { const [deviceInfo, setDeviceInfo] = useState(null); - + const isNativeEnvironment = appBridge.isNativeEnvironment(); const isAndroid = appBridge.isAndroid(); const isIOS = appBridge.isIOS(); @@ -124,7 +128,7 @@ export const useAppBridge = (): UseAppBridgeReturn => { toast.className = 'fixed top-4 right-4 bg-gray-800 text-white px-4 py-2 rounded-md z-50 animate-fade-in'; toast.textContent = message; document.body.appendChild(toast); - + setTimeout(() => { document.body.removeChild(toast); }, duration); @@ -207,7 +211,7 @@ export const useAppBridge = (): UseAppBridgeReturn => { } return appBridge.safeCall(() => appBridge.closeBiometricRegistrationPopup()); }, [isNativeEnvironment]); - + const shareContent = useCallback(async (content: ShareContent): Promise => { if (!isNativeEnvironment) { // 웹 환경에서는 Web Share API 사용 (지원되는 경우) @@ -261,6 +265,35 @@ export const useAppBridge = (): UseAppBridgeReturn => { return result || 'ID'; }, [isNativeEnvironment]); + const getNotificationSetting = useCallback(async (): Promise => { + if (!isAndroid) { + console.log('getNotificationSetting: Not Android, skipping'); + return true; + } + + try { + const result = await appBridge.safeCall(() => appBridge.getNotificationSetting(), { enabled: true }); + return result?.enabled ?? true; + } catch (error) { + console.error('Failed to get notification setting:', error); + return true; + } + }, [isAndroid]); + + const setNotificationSetting = useCallback(async (enabled: boolean): Promise => { + if (!isAndroid) { + console.log('setNotificationSetting: Not Android, skipping'); + return null; + } + try { + const result = await appBridge.safeCall(() => appBridge.setNotificationSetting(enabled)); + return result; + } catch (error) { + console.error('Failed to set notification setting:', error); + return null; + } + }, [isAndroid]); + return { isNativeEnvironment, isAndroid, @@ -284,6 +317,8 @@ export const useAppBridge = (): UseAppBridgeReturn => { closeBiometricRegistrationPopup, isPushNotificationEnabled, openAppSettings, - getLoginType + getLoginType, + getNotificationSetting, + setNotificationSetting }; }; \ No newline at end of file diff --git a/src/pages/additional-service/key-in-payment/key-in-payment-page.tsx b/src/pages/additional-service/key-in-payment/key-in-payment-page.tsx index 6956ae3..bbfac33 100644 --- a/src/pages/additional-service/key-in-payment/key-in-payment-page.tsx +++ b/src/pages/additional-service/key-in-payment/key-in-payment-page.tsx @@ -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(false); const [pageParam, setPageParam] = useState(DEFAULT_PAGE_PARAM); const [mid, setMid] = useState(userMid); - const [startDate, setStartDate] = useState(moment().format('YYYY-MM-DD')); - const [endDate, setEndDate] = useState(moment().format('YYYY-MM-DD')); - const [paymentStatus, setPaymentStatus] = useState(KeyInPaymentPaymentStatus.ALL) + const [startDate, setStartDate] = useState(moment().format('YYYYMMDD')); + const [endDate, setEndDate] = useState(moment().format('YYYYMMDD')); + const [transactionType, setTransactionType] = useState(KeyInPaymentTansactionType.ALL) + const [status, setStatus] = useState(KeyInPaymentStatus.ALL); const [minAmount, setMinAmount] = useState(); const [maxAmount, setMaxAmount] = useState(); const [emailBottomSheetOn, setEmailBottomSheetOn] = useState(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) => ( onClickToPaymentStatus(value.value)} >{value.name} )) @@ -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} > diff --git a/src/pages/additional-service/key-in-payment/requeset-page.tsx b/src/pages/additional-service/key-in-payment/requeset-page.tsx index 14956e0..8d3cd49 100644 --- a/src/pages/additional-service/key-in-payment/requeset-page.tsx +++ b/src/pages/additional-service/key-in-payment/requeset-page.tsx @@ -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(userMid || ''); - const [goodsName, setGoodsName] = useState(''); + const [productName, setProductName] = useState(''); const [amount, setAmount] = useState(0); - const [buyerName, setBuyerName] = useState(''); + const [customerName, setCustomerName] = useState(''); const [email, setEmail] = useState(''); const [phoneNumber, setPhoneNumber] = useState(''); const [cardNo1, setCardNo1] = useState(''); const [cardNo2, setCardNo2] = useState(''); const [cardNo3, setCardNo3] = useState(''); const [cardNo4, setCardNo4] = useState(''); - const [cardExpirationMonth, setCardExpirationMonth] = useState(''); - const [cardExpirationYear, setCardExpirationYear] = useState(''); - const [instmntMonth, setInstmntMonth] = useState('00'); - const [moid, setMoid] = useState(''); + const [expMon, setExpMon] = useState(''); + const [expYear, setExpYear] = useState(''); + const [instmnt, setInstmnt] = useState('00'); + const [orderNumber, setOrderNumber] = useState(''); 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 = () => {
) => setGoodsName(e.target.value)} + value={productName} + onChange={(e: ChangeEvent) => setProductName(e.target.value)} />
@@ -215,8 +216,8 @@ export const KeyInPaymentRequestPage = () => {
) => setBuyerName(e.target.value)} + value={customerName} + onChange={(e: ChangeEvent) => setCustomerName(e.target.value)} />
@@ -318,10 +319,10 @@ export const KeyInPaymentRequestPage = () => {
) => { 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 = () => { / ) => { 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 = () => {
) => setMoid(e.target.value)} + value={orderNumber} + onChange={(e: ChangeEvent) => setOrderNumber(e.target.value)} />
diff --git a/src/pages/additional-service/link-payment/link-payment-detail-page.tsx b/src/pages/additional-service/link-payment/link-payment-detail-page.tsx index e03b174..0b6f43e 100644 --- a/src/pages/additional-service/link-payment/link-payment-detail-page.tsx +++ b/src/pages/additional-service/link-payment/link-payment-detail-page.tsx @@ -154,21 +154,21 @@ export const LinkPaymentDetailPage = () => { additionalServiceCategory={AdditionalServiceCategory.LinkPaymentHistory} detailInfo={detailInfo} > +
+ +
- -
- {/*
-
*/} + diff --git a/src/pages/setting/setting-page.tsx b/src/pages/setting/setting-page.tsx index 9289f86..595cb27 100644 --- a/src/pages/setting/setting-page.tsx +++ b/src/pages/setting/setting-page.tsx @@ -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(false); + const [notificationSetting, setNotificationSetting] = useState(true); const [alarmSetting, setAlarmSetting] = useState>({ '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 ( <>
+ {/* ✅ Android일 때는 앱 내 설정, 아니면 시스템 권한 표시 */}
알림 수신 설정
-