- 안드로이드 알림 설정 AppBridge 추가
- KeyIn Request 필드 수정
This commit is contained in:
@@ -105,6 +105,7 @@
|
|||||||
"@tanstack/router-plugin": "^1.131.41",
|
"@tanstack/router-plugin": "^1.131.41",
|
||||||
"@types/react": "^19.1.12",
|
"@types/react": "^19.1.12",
|
||||||
"@types/react-dom": "^19.1.9",
|
"@types/react-dom": "^19.1.9",
|
||||||
|
"@types/ua-parser-js": "^0.7.39",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.43.0",
|
"@typescript-eslint/eslint-plugin": "^8.43.0",
|
||||||
"@typescript-eslint/parser": "^8.43.0",
|
"@typescript-eslint/parser": "^8.43.0",
|
||||||
"@vitejs/plugin-react": "^4.7.0",
|
"@vitejs/plugin-react": "^4.7.0",
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ export interface ExtensionArsResendParams {
|
|||||||
mid: string;
|
mid: string;
|
||||||
tid: string;
|
tid: string;
|
||||||
};
|
};
|
||||||
export interface ExtensionArsResendResponse {};
|
export interface ExtensionArsResendResponse {
|
||||||
|
status: boolean;
|
||||||
|
};
|
||||||
export interface ExtensionArsListParams {
|
export interface ExtensionArsListParams {
|
||||||
mid?: string;
|
mid?: string;
|
||||||
moid?: string;
|
moid?: string;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { KeyInPaymentPaymentStatus } from "./types";
|
import { KeyInPaymentTansactionType } from "./types";
|
||||||
|
|
||||||
// contant로 옮기기
|
// contant로 옮기기
|
||||||
export const keyInPaymentPaymentStatusBtnGroup = [
|
export const keyInPaymentPaymentStatusBtnGroup = [
|
||||||
{ name: '전체', value: KeyInPaymentPaymentStatus.ALL },
|
{ name: '전체', value: KeyInPaymentTansactionType.ALL },
|
||||||
{ name: '승인', value: KeyInPaymentPaymentStatus.APPROVAL },
|
{ name: '승인', value: KeyInPaymentTansactionType.APPROVAL },
|
||||||
{ name: '전취소', value: KeyInPaymentPaymentStatus.PRE_CANCEL },
|
{ name: '전취소', value: KeyInPaymentTansactionType.FULL_CANCEL },
|
||||||
{ name: '후취소', value: KeyInPaymentPaymentStatus.POST_CANCEL }
|
{ name: '후취소', value: KeyInPaymentTansactionType.PARTIAL_CANCEL }
|
||||||
];
|
];
|
||||||
|
|
||||||
export const getKeyInPaymentPaymentStatusName = (status?: string): string => {
|
export const getKeyInPaymentPaymentStatusName = (status?: string): string => {
|
||||||
|
|||||||
@@ -4,18 +4,30 @@ import { AdditionalServiceCategory, ExtensionRequestParams, FilterProps } from "
|
|||||||
// ========================================
|
// ========================================
|
||||||
// 키인결제 관련 타입들
|
// 키인결제 관련 타입들
|
||||||
// ========================================
|
// ========================================
|
||||||
export enum KeyInPaymentPaymentStatus {
|
export enum KeyInPaymentTansactionType {
|
||||||
ALL = 'ALL',
|
ALL = 'ALL',
|
||||||
APPROVAL = 'APPROVAL',
|
APPROVAL = 'APPROVAL',
|
||||||
PRE_CANCEL = 'PRE_CANCEL',
|
FULL_CANCEL = 'FULL_CANCEL',
|
||||||
POST_CANCEL = 'POST_CANCEL'
|
PARTIAL_CANCEL = 'PARTIAL_CANCEL'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum KeyInPaymentStatus {
|
||||||
|
ALL = 'ALL',
|
||||||
|
REGISTRED = 'REGISTRED',
|
||||||
|
WAITING = 'WAITING',
|
||||||
|
PROCESSING = 'PROCESSING',
|
||||||
|
COMPLETED = 'COMPLETED'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface KeyInPaymentListItem {
|
export interface KeyInPaymentListItem {
|
||||||
|
transactionDate?: string;
|
||||||
|
transactionTime?: string;
|
||||||
|
customerName?: string;
|
||||||
|
transactionCode?: string;
|
||||||
tid?: string;
|
tid?: string;
|
||||||
paymentDate?: string;
|
|
||||||
paymentStatus?: string;
|
|
||||||
amount?: number;
|
amount?: number;
|
||||||
|
statusLabel?: string;
|
||||||
|
transactionType?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface KeyInPaymentListProps {
|
export interface KeyInPaymentListProps {
|
||||||
@@ -28,13 +40,13 @@ export interface KeyInPaymentFilterProps extends FilterProps {
|
|||||||
mid: string,
|
mid: string,
|
||||||
startDate: string;
|
startDate: string;
|
||||||
endDate: string;
|
endDate: string;
|
||||||
transactionStatus: KeyInPaymentPaymentStatus;
|
transactionStatus: KeyInPaymentTansactionType;
|
||||||
minAmount?: number;
|
minAmount?: number;
|
||||||
maxAmount?: number;
|
maxAmount?: number;
|
||||||
setMid: (mid: string) => void;
|
setMid: (mid: string) => void;
|
||||||
setStartDate: (startDate: string) => void;
|
setStartDate: (startDate: string) => void;
|
||||||
setEndDate: (endDate: string) => void;
|
setEndDate: (endDate: string) => void;
|
||||||
setTransactionStatus: (transactionStatus: KeyInPaymentPaymentStatus) => void;
|
setTransactionStatus: (transactionStatus: KeyInPaymentTansactionType) => void;
|
||||||
setMinAmount: (minAmount?: number) => void;
|
setMinAmount: (minAmount?: number) => void;
|
||||||
setMaxAmount: (maxAmount?: number) => void;
|
setMaxAmount: (maxAmount?: number) => void;
|
||||||
}
|
}
|
||||||
@@ -42,19 +54,25 @@ export interface KeyInPaymentFilterProps extends FilterProps {
|
|||||||
// KEY-IN 결제 확장 서비스
|
// KEY-IN 결제 확장 서비스
|
||||||
// ========================================
|
// ========================================
|
||||||
export interface ExtensionKeyinListParams extends ExtensionRequestParams {
|
export interface ExtensionKeyinListParams extends ExtensionRequestParams {
|
||||||
fromDate: string;
|
startDate: string;
|
||||||
toDate: string;
|
endDate: string;
|
||||||
paymentStatus: string;
|
transactionType: string;
|
||||||
|
status: string;
|
||||||
minAmount?: number;
|
minAmount?: number;
|
||||||
maxAmount?: number;
|
maxAmount?: number;
|
||||||
page?: DefaultRequestPagination;
|
page?: DefaultRequestPagination;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExtensionKeyinListItemProps {
|
export interface ExtensionKeyinListItemProps {
|
||||||
|
transactionDate: string;
|
||||||
|
transactionTime: string;
|
||||||
|
customerName: string;
|
||||||
|
transactionCode: string;
|
||||||
tid: string;
|
tid: string;
|
||||||
paymentDate: string;
|
|
||||||
paymentStatus: string;
|
|
||||||
amount: number;
|
amount: number;
|
||||||
|
statusLabel: string;
|
||||||
|
transactionType: string;
|
||||||
|
status: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExtensionKeyinListResponse extends DefaulResponsePagination {
|
export interface ExtensionKeyinListResponse extends DefaulResponsePagination {
|
||||||
@@ -74,15 +92,16 @@ export interface ExtensionKeyinDownloadExcelResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ExtensionKeyinApplyParams extends ExtensionRequestParams {
|
export interface ExtensionKeyinApplyParams extends ExtensionRequestParams {
|
||||||
goodsName: string;
|
|
||||||
amount: number;
|
|
||||||
buyerName: string;
|
|
||||||
email: string;
|
|
||||||
phoneNumber: string;
|
|
||||||
cardNo: string;
|
cardNo: string;
|
||||||
cardExpirationDate: string;
|
expYear: string;
|
||||||
instmntMonth: string;
|
expMon: string;
|
||||||
moid: string;
|
instmnt: string;
|
||||||
|
amount: number;
|
||||||
|
productName: string;
|
||||||
|
orderNumber: string;
|
||||||
|
customerName: string;
|
||||||
|
phoneNumber: string;
|
||||||
|
email: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExtensionKeyinApplyResponse {
|
export interface ExtensionKeyinApplyResponse {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { FilterButtonGroups } from '@/shared/ui/filter/button-groups';
|
|||||||
import { FilterRangeAmount } from '@/shared/ui/filter/range-amount';
|
import { FilterRangeAmount } from '@/shared/ui/filter/range-amount';
|
||||||
import { FilterMotionDuration, FilterMotionStyle, FilterMotionVariants } from '@/entities/common/model/constant';
|
import { FilterMotionDuration, FilterMotionStyle, FilterMotionVariants } from '@/entities/common/model/constant';
|
||||||
import { useStore } from '@/shared/model/store';
|
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';
|
import { keyInPaymentPaymentStatusBtnGroup } from '@/entities/additional-service/model/key-in/constant';
|
||||||
|
|
||||||
export const KeyInPaymentFilter = ({
|
export const KeyInPaymentFilter = ({
|
||||||
@@ -31,7 +31,7 @@ export const KeyInPaymentFilter = ({
|
|||||||
const [filterMid, setFilterMid] = useState<string>(mid);
|
const [filterMid, setFilterMid] = useState<string>(mid);
|
||||||
const [filterStartDate, setFilterStartDate] = useState<string>(startDate);
|
const [filterStartDate, setFilterStartDate] = useState<string>(startDate);
|
||||||
const [filterEndDate, setFilterEndDate] = useState<string>(endDate);
|
const [filterEndDate, setFilterEndDate] = useState<string>(endDate);
|
||||||
const [filterTransactionStatus, setFilterTransactionStatus] = useState<KeyInPaymentPaymentStatus>(transactionStatus);
|
const [filterTransactionStatus, setFilterTransactionStatus] = useState<KeyInPaymentTansactionType>(transactionStatus);
|
||||||
const [filterMinAmount, setFilterMinAmount] = useState<number | undefined>(minAmount);
|
const [filterMinAmount, setFilterMinAmount] = useState<number | undefined>(minAmount);
|
||||||
const [filterMaxAmount, setFilterMaxAmount] = useState<number | undefined>(maxAmount);
|
const [filterMaxAmount, setFilterMaxAmount] = useState<number | undefined>(maxAmount);
|
||||||
|
|
||||||
|
|||||||
@@ -18,13 +18,13 @@ export const KeyInPaymentList = ({
|
|||||||
for (let i = 0; i < listItems.length; i++) {
|
for (let i = 0; i < listItems.length; i++) {
|
||||||
let items = listItems[i];
|
let items = listItems[i];
|
||||||
if (!!items) {
|
if (!!items) {
|
||||||
let paymentDate = items?.paymentDate;
|
let transactionDate = items?.transactionDate;
|
||||||
paymentDate = paymentDate?.substring(0, 8)
|
transactionDate = transactionDate?.substring(0, 8)
|
||||||
if (!!paymentDate) {
|
if (!!transactionDate) {
|
||||||
if (i === 0) {
|
if (i === 0) {
|
||||||
date = paymentDate;
|
date = transactionDate;
|
||||||
}
|
}
|
||||||
if (date !== paymentDate) {
|
if (date !== transactionDate) {
|
||||||
if (list.length > 0) {
|
if (list.length > 0) {
|
||||||
rs.push(
|
rs.push(
|
||||||
<ListDateGroup
|
<ListDateGroup
|
||||||
@@ -35,7 +35,7 @@ export const KeyInPaymentList = ({
|
|||||||
></ListDateGroup>
|
></ListDateGroup>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
date = paymentDate;
|
date = transactionDate;
|
||||||
list = [];
|
list = [];
|
||||||
}
|
}
|
||||||
list.push(items);
|
list.push(items);
|
||||||
|
|||||||
@@ -38,6 +38,12 @@ export const ListDateGroup = ({
|
|||||||
resultStatus={ items[i]?.resultStatus }
|
resultStatus={ items[i]?.resultStatus }
|
||||||
resultMessage={ items[i]?.resultMessage }
|
resultMessage={ items[i]?.resultMessage }
|
||||||
applicationDate={ items[i]?.applicationDate }
|
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 }
|
amount={ items[i]?.amount }
|
||||||
sendDate={ items[i]?.sendDate }
|
sendDate={ items[i]?.sendDate }
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ export const ListItem = ({
|
|||||||
accountName,
|
accountName,
|
||||||
|
|
||||||
submallId, settlementDate, companyName,
|
submallId, settlementDate, companyName,
|
||||||
status: disbursementStatus, amount: disbursementAmount,
|
|
||||||
|
|
||||||
orderStatus, arsPaymentMethod,
|
orderStatus, arsPaymentMethod,
|
||||||
|
|
||||||
@@ -452,7 +451,7 @@ export const ListItem = ({
|
|||||||
else if (additionalServiceCategory === AdditionalServiceCategory.Payout) {
|
else if (additionalServiceCategory === AdditionalServiceCategory.Payout) {
|
||||||
rs.push(
|
rs.push(
|
||||||
<div className="transaction-details">
|
<div className="transaction-details">
|
||||||
<span>{getPayoutStatusText(disbursementStatus)}</span>
|
<span>{getPayoutStatusText(status)}</span>
|
||||||
<span className="separator">|</span>
|
<span className="separator">|</span>
|
||||||
<span>{submallId}</span>
|
<span>{submallId}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -580,7 +579,7 @@ export const ListItem = ({
|
|||||||
className="transaction-amount"
|
className="transaction-amount"
|
||||||
>
|
>
|
||||||
<NumericFormat
|
<NumericFormat
|
||||||
value={disbursementAmount}
|
value={amount}
|
||||||
thousandSeparator
|
thousandSeparator
|
||||||
displayType="text"
|
displayType="text"
|
||||||
suffix='원'
|
suffix='원'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useState, useEffect, useCallback } from 'react';
|
import { useState, useEffect, useCallback } from 'react';
|
||||||
import { appBridge } from '@/utils/appBridge';
|
import { appBridge } from '@/utils/appBridge';
|
||||||
import { DeviceInfo, ShareContent } from '@/types';
|
import { DeviceInfo, NotificationSettingResponse, ShareContent } from '@/types';
|
||||||
import { LoginResponse } from '@/entities/user/model/types';
|
import { LoginResponse } from '@/entities/user/model/types';
|
||||||
|
|
||||||
interface UseAppBridgeReturn {
|
interface UseAppBridgeReturn {
|
||||||
@@ -8,23 +8,23 @@ interface UseAppBridgeReturn {
|
|||||||
isAndroid: boolean;
|
isAndroid: boolean;
|
||||||
isIOS: boolean;
|
isIOS: boolean;
|
||||||
deviceInfo: DeviceInfo | null;
|
deviceInfo: DeviceInfo | null;
|
||||||
|
|
||||||
// 네비게이션
|
// 네비게이션
|
||||||
navigateBack: () => Promise<void>;
|
navigateBack: () => Promise<void>;
|
||||||
navigateTo: (path: string) => Promise<void>;
|
navigateTo: (path: string) => Promise<void>;
|
||||||
navigateToLogin: () => Promise<void>;
|
navigateToLogin: () => Promise<void>;
|
||||||
closeWebView: () => Promise<void>;
|
closeWebView: () => Promise<void>;
|
||||||
|
|
||||||
// 알림
|
// 알림
|
||||||
showToast: (message: string, duration?: number) => Promise<void>;
|
showToast: (message: string, duration?: number) => Promise<void>;
|
||||||
showAlert: (title: string, message: string) => Promise<void>;
|
showAlert: (title: string, message: string) => Promise<void>;
|
||||||
showConfirm: (title: string, message: string) => Promise<boolean>;
|
showConfirm: (title: string, message: string) => Promise<boolean>;
|
||||||
|
|
||||||
// 저장소
|
// 저장소
|
||||||
setStorage: (key: string, value: unknown) => Promise<void>;
|
setStorage: (key: string, value: unknown) => Promise<void>;
|
||||||
// getStorage: <T = unknown>(key: string) => Promise<T | null>;
|
// getStorage: <T = unknown>(key: string) => Promise<T | null>;
|
||||||
removeStorage: (key: string) => Promise<void>;
|
removeStorage: (key: string) => Promise<void>;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// 미디어
|
// 미디어
|
||||||
openCamera: (options?: { quality?: number; allowEdit?: boolean }) => Promise<string>;
|
openCamera: (options?: { quality?: number; allowEdit?: boolean }) => Promise<string>;
|
||||||
@@ -62,11 +62,15 @@ interface UseAppBridgeReturn {
|
|||||||
|
|
||||||
// 로그인 방식 설정 조회
|
// 로그인 방식 설정 조회
|
||||||
getLoginType: () => Promise<string>;
|
getLoginType: () => Promise<string>;
|
||||||
|
|
||||||
|
getNotificationSetting: () => Promise<boolean>;
|
||||||
|
|
||||||
|
setNotificationSetting: (enabled: boolean) => Promise<NotificationSettingResponse>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useAppBridge = (): UseAppBridgeReturn => {
|
export const useAppBridge = (): UseAppBridgeReturn => {
|
||||||
const [deviceInfo, setDeviceInfo] = useState<DeviceInfo | null>(null);
|
const [deviceInfo, setDeviceInfo] = useState<DeviceInfo | null>(null);
|
||||||
|
|
||||||
const isNativeEnvironment = appBridge.isNativeEnvironment();
|
const isNativeEnvironment = appBridge.isNativeEnvironment();
|
||||||
const isAndroid = appBridge.isAndroid();
|
const isAndroid = appBridge.isAndroid();
|
||||||
const isIOS = appBridge.isIOS();
|
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.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;
|
toast.textContent = message;
|
||||||
document.body.appendChild(toast);
|
document.body.appendChild(toast);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
document.body.removeChild(toast);
|
document.body.removeChild(toast);
|
||||||
}, duration);
|
}, duration);
|
||||||
@@ -207,7 +211,7 @@ export const useAppBridge = (): UseAppBridgeReturn => {
|
|||||||
}
|
}
|
||||||
return appBridge.safeCall(() => appBridge.closeBiometricRegistrationPopup());
|
return appBridge.safeCall(() => appBridge.closeBiometricRegistrationPopup());
|
||||||
}, [isNativeEnvironment]);
|
}, [isNativeEnvironment]);
|
||||||
|
|
||||||
const shareContent = useCallback(async (content: ShareContent): Promise<void> => {
|
const shareContent = useCallback(async (content: ShareContent): Promise<void> => {
|
||||||
if (!isNativeEnvironment) {
|
if (!isNativeEnvironment) {
|
||||||
// 웹 환경에서는 Web Share API 사용 (지원되는 경우)
|
// 웹 환경에서는 Web Share API 사용 (지원되는 경우)
|
||||||
@@ -261,6 +265,35 @@ export const useAppBridge = (): UseAppBridgeReturn => {
|
|||||||
return result || 'ID';
|
return result || 'ID';
|
||||||
}, [isNativeEnvironment]);
|
}, [isNativeEnvironment]);
|
||||||
|
|
||||||
|
const getNotificationSetting = useCallback(async (): Promise<boolean> => {
|
||||||
|
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<any> => {
|
||||||
|
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 {
|
return {
|
||||||
isNativeEnvironment,
|
isNativeEnvironment,
|
||||||
isAndroid,
|
isAndroid,
|
||||||
@@ -284,6 +317,8 @@ export const useAppBridge = (): UseAppBridgeReturn => {
|
|||||||
closeBiometricRegistrationPopup,
|
closeBiometricRegistrationPopup,
|
||||||
isPushNotificationEnabled,
|
isPushNotificationEnabled,
|
||||||
openAppSettings,
|
openAppSettings,
|
||||||
getLoginType
|
getLoginType,
|
||||||
|
getNotificationSetting,
|
||||||
|
setNotificationSetting
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -19,7 +19,7 @@ import { useExtensionKeyinListMutation } from '@/entities/additional-service/api
|
|||||||
import { DEFAULT_PAGE_PARAM } from '@/entities/common/model/constant';
|
import { DEFAULT_PAGE_PARAM } from '@/entities/common/model/constant';
|
||||||
import { KeyInPaymentList } from '@/entities/additional-service/ui/key-in-payment/key-in-payment-list';
|
import { KeyInPaymentList } from '@/entities/additional-service/ui/key-in-payment/key-in-payment-list';
|
||||||
import { useStore } from '@/shared/model/store';
|
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 { keyInPaymentPaymentStatusBtnGroup } from '@/entities/additional-service/model/key-in/constant';
|
||||||
import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet';
|
import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet';
|
||||||
import { useExtensionAccessCheck } from '@/shared/lib/hooks/use-extension-access-check';
|
import { useExtensionAccessCheck } from '@/shared/lib/hooks/use-extension-access-check';
|
||||||
@@ -40,9 +40,10 @@ export const KeyInPaymentPage = () => {
|
|||||||
const [filterOn, setFilterOn] = useState<boolean>(false);
|
const [filterOn, setFilterOn] = useState<boolean>(false);
|
||||||
const [pageParam, setPageParam] = useState<DefaultRequestPagination>(DEFAULT_PAGE_PARAM);
|
const [pageParam, setPageParam] = useState<DefaultRequestPagination>(DEFAULT_PAGE_PARAM);
|
||||||
const [mid, setMid] = useState<string>(userMid);
|
const [mid, setMid] = useState<string>(userMid);
|
||||||
const [startDate, setStartDate] = useState(moment().format('YYYY-MM-DD'));
|
const [startDate, setStartDate] = useState(moment().format('YYYYMMDD'));
|
||||||
const [endDate, setEndDate] = useState(moment().format('YYYY-MM-DD'));
|
const [endDate, setEndDate] = useState(moment().format('YYYYMMDD'));
|
||||||
const [paymentStatus, setPaymentStatus] = useState<KeyInPaymentPaymentStatus>(KeyInPaymentPaymentStatus.ALL)
|
const [transactionType, setTransactionType] = useState<KeyInPaymentTansactionType>(KeyInPaymentTansactionType.ALL)
|
||||||
|
const [status, setStatus] = useState<KeyInPaymentStatus>(KeyInPaymentStatus.ALL);
|
||||||
const [minAmount, setMinAmount] = useState<number>();
|
const [minAmount, setMinAmount] = useState<number>();
|
||||||
const [maxAmount, setMaxAmount] = useState<number>();
|
const [maxAmount, setMaxAmount] = useState<number>();
|
||||||
const [emailBottomSheetOn, setEmailBottomSheetOn] = useState<boolean>(false);
|
const [emailBottomSheetOn, setEmailBottomSheetOn] = useState<boolean>(false);
|
||||||
@@ -72,13 +73,15 @@ export const KeyInPaymentPage = () => {
|
|||||||
onIntersect
|
onIntersect
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 목록 조회
|
||||||
const callList = (type?: string) => {
|
const callList = (type?: string) => {
|
||||||
setOnActionIntersect(false);
|
setOnActionIntersect(false);
|
||||||
let listParams = {
|
let listParams = {
|
||||||
mid: mid,
|
mid: mid,
|
||||||
fromDate: startDate,
|
startDate: startDate,
|
||||||
toDate: endDate,
|
endDate: endDate,
|
||||||
paymentStatus: paymentStatus,
|
transactionType: transactionType,
|
||||||
|
status: status,
|
||||||
minAmount: minAmount,
|
minAmount: minAmount,
|
||||||
maxAmount: maxAmount,
|
maxAmount: maxAmount,
|
||||||
page: {
|
page: {
|
||||||
@@ -131,13 +134,14 @@ export const KeyInPaymentPage = () => {
|
|||||||
setEmailBottomSheetOn(true);
|
setEmailBottomSheetOn(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 엑셀 다운로드
|
||||||
const onSendRequest = (selectedEmail?: string) => {
|
const onSendRequest = (selectedEmail?: string) => {
|
||||||
if (selectedEmail) {
|
if (selectedEmail) {
|
||||||
downloadExcel({
|
downloadExcel({
|
||||||
mid: mid,
|
mid: mid,
|
||||||
fromDate: startDate,
|
fromDate: startDate,
|
||||||
toDate: endDate,
|
toDate: endDate,
|
||||||
paymentStatus: paymentStatus,
|
paymentStatus: transactionType,
|
||||||
minAmount: minAmount,
|
minAmount: minAmount,
|
||||||
maxAmount: maxAmount,
|
maxAmount: maxAmount,
|
||||||
//email: selectedEmail
|
//email: selectedEmail
|
||||||
@@ -152,8 +156,8 @@ export const KeyInPaymentPage = () => {
|
|||||||
setSortType(sort);
|
setSortType(sort);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onClickToPaymentStatus = (val: KeyInPaymentPaymentStatus) => {
|
const onClickToPaymentStatus = (val: KeyInPaymentTansactionType) => {
|
||||||
setPaymentStatus(val);
|
setTransactionType(val);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -162,7 +166,7 @@ export const KeyInPaymentPage = () => {
|
|||||||
mid,
|
mid,
|
||||||
startDate,
|
startDate,
|
||||||
endDate,
|
endDate,
|
||||||
paymentStatus,
|
transactionType,
|
||||||
minAmount,
|
minAmount,
|
||||||
maxAmount,
|
maxAmount,
|
||||||
sortType
|
sortType
|
||||||
@@ -222,7 +226,7 @@ export const KeyInPaymentPage = () => {
|
|||||||
keyInPaymentPaymentStatusBtnGroup.map((value, index) => (
|
keyInPaymentPaymentStatusBtnGroup.map((value, index) => (
|
||||||
<span
|
<span
|
||||||
key={`key-service-code=${index}`}
|
key={`key-service-code=${index}`}
|
||||||
className={`keyword-tag ${(paymentStatus === value.value) ? 'active' : ''}`}
|
className={`keyword-tag ${(transactionType === value.value) ? 'active' : ''}`}
|
||||||
onClick={() => onClickToPaymentStatus(value.value)}
|
onClick={() => onClickToPaymentStatus(value.value)}
|
||||||
>{value.name}</span>
|
>{value.name}</span>
|
||||||
))
|
))
|
||||||
@@ -245,13 +249,13 @@ export const KeyInPaymentPage = () => {
|
|||||||
mid={mid}
|
mid={mid}
|
||||||
startDate={startDate}
|
startDate={startDate}
|
||||||
endDate={endDate}
|
endDate={endDate}
|
||||||
transactionStatus={paymentStatus}
|
transactionStatus={transactionType}
|
||||||
minAmount={minAmount}
|
minAmount={minAmount}
|
||||||
maxAmount={maxAmount}
|
maxAmount={maxAmount}
|
||||||
setMid={setMid}
|
setMid={setMid}
|
||||||
setStartDate={setStartDate}
|
setStartDate={setStartDate}
|
||||||
setEndDate={setEndDate}
|
setEndDate={setEndDate}
|
||||||
setTransactionStatus={setPaymentStatus}
|
setTransactionStatus={setTransactionType}
|
||||||
setMinAmount={setMinAmount}
|
setMinAmount={setMinAmount}
|
||||||
setMaxAmount={setMaxAmount}
|
setMaxAmount={setMaxAmount}
|
||||||
></KeyInPaymentFilter>
|
></KeyInPaymentFilter>
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
import { overlay } from 'overlay-kit';
|
import { overlay } from 'overlay-kit';
|
||||||
import { Dialog } from '@/shared/ui/dialogs/dialog';
|
import { Dialog } from '@/shared/ui/dialogs/dialog';
|
||||||
import { useStore } from '@/shared/model/store';
|
import { useStore } from '@/shared/model/store';
|
||||||
|
import { snackBar } from '@/shared/lib';
|
||||||
|
|
||||||
export const KeyInPaymentRequestPage = () => {
|
export const KeyInPaymentRequestPage = () => {
|
||||||
const { navigate } = useNavigate();
|
const { navigate } = useNavigate();
|
||||||
@@ -22,19 +23,19 @@ export const KeyInPaymentRequestPage = () => {
|
|||||||
const userMid = useStore.getState().UserStore.mid;
|
const userMid = useStore.getState().UserStore.mid;
|
||||||
|
|
||||||
const [mid, setMid] = useState<string>(userMid || '');
|
const [mid, setMid] = useState<string>(userMid || '');
|
||||||
const [goodsName, setGoodsName] = useState<string>('');
|
const [productName, setProductName] = useState<string>('');
|
||||||
const [amount, setAmount] = useState<number>(0);
|
const [amount, setAmount] = useState<number>(0);
|
||||||
const [buyerName, setBuyerName] = useState<string>('');
|
const [customerName, setCustomerName] = useState<string>('');
|
||||||
const [email, setEmail] = useState<string>('');
|
const [email, setEmail] = useState<string>('');
|
||||||
const [phoneNumber, setPhoneNumber] = useState<string>('');
|
const [phoneNumber, setPhoneNumber] = useState<string>('');
|
||||||
const [cardNo1, setCardNo1] = useState<string>('');
|
const [cardNo1, setCardNo1] = useState<string>('');
|
||||||
const [cardNo2, setCardNo2] = useState<string>('');
|
const [cardNo2, setCardNo2] = useState<string>('');
|
||||||
const [cardNo3, setCardNo3] = useState<string>('');
|
const [cardNo3, setCardNo3] = useState<string>('');
|
||||||
const [cardNo4, setCardNo4] = useState<string>('');
|
const [cardNo4, setCardNo4] = useState<string>('');
|
||||||
const [cardExpirationMonth, setCardExpirationMonth] = useState<string>('');
|
const [expMon, setExpMon] = useState<string>('');
|
||||||
const [cardExpirationYear, setCardExpirationYear] = useState<string>('');
|
const [expYear, setExpYear] = useState<string>('');
|
||||||
const [instmntMonth, setInstmntMonth] = useState<string>('00');
|
const [instmnt, setInstmnt] = useState<string>('00');
|
||||||
const [moid, setMoid] = useState<string>('');
|
const [orderNumber, setOrderNumber] = useState<string>('');
|
||||||
|
|
||||||
const { mutateAsync: keyInApply } = useExtensionKeyinApplyMutation();
|
const { mutateAsync: keyInApply } = useExtensionKeyinApplyMutation();
|
||||||
|
|
||||||
@@ -46,43 +47,43 @@ export const KeyInPaymentRequestPage = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
setGoodsName('');
|
setProductName('');
|
||||||
setAmount(0);
|
setAmount(0);
|
||||||
setBuyerName('');
|
setCustomerName('');
|
||||||
setEmail('');
|
setEmail('');
|
||||||
setPhoneNumber('');
|
setPhoneNumber('');
|
||||||
setCardNo1('');
|
setCardNo1('');
|
||||||
setCardNo2('');
|
setCardNo2('');
|
||||||
setCardNo3('');
|
setCardNo3('');
|
||||||
setCardNo4('');
|
setCardNo4('');
|
||||||
setCardExpirationMonth('');
|
setExpMon('');
|
||||||
setCardExpirationYear('');
|
setExpYear('');
|
||||||
setInstmntMonth('00');
|
setInstmnt('00');
|
||||||
setMoid('');
|
setOrderNumber('');
|
||||||
};
|
};
|
||||||
|
|
||||||
const callKeyInPaymentRequest = () => {
|
const callKeyInPaymentRequest = () => {
|
||||||
const cardNo = `${cardNo1}${cardNo2}${cardNo3}${cardNo4}`;
|
const cardNo = `${cardNo1}${cardNo2}${cardNo3}${cardNo4}`;
|
||||||
const cardExpirationDate = `${cardExpirationMonth}${cardExpirationYear}`;
|
|
||||||
|
|
||||||
let keyInApplyParams = {
|
let keyInApplyParams = {
|
||||||
mid: mid,
|
mid: mid,
|
||||||
goodsName: goodsName,
|
|
||||||
amount: amount,
|
|
||||||
buyerName: buyerName,
|
|
||||||
email: email,
|
|
||||||
phoneNumber: phoneNumber,
|
|
||||||
cardNo: cardNo,
|
cardNo: cardNo,
|
||||||
cardExpirationDate: cardExpirationDate,
|
expYear: expYear,
|
||||||
instmntMonth: instmntMonth,
|
expMon: expMon,
|
||||||
moid: moid,
|
instmnt: instmnt,
|
||||||
|
amount: amount,
|
||||||
|
productName: productName,
|
||||||
|
orderNumber: orderNumber,
|
||||||
|
customerName: customerName,
|
||||||
|
phoneNumber: phoneNumber,
|
||||||
|
email: email,
|
||||||
};
|
};
|
||||||
|
|
||||||
keyInApply(keyInApplyParams).then((rs) => {
|
keyInApply(keyInApplyParams).then((rs) => {
|
||||||
console.log('결제 응답:', rs);
|
console.log('결제 응답:', rs);
|
||||||
if (rs.status) {
|
if (rs.status) {
|
||||||
// 성공: 화면 유지 & 입력 내용 초기화
|
// 성공: 화면 유지 & 입력 내용 초기화
|
||||||
showSuccessDialog();
|
snackBar("KEY-IN 결제 신청을 성공하였습니다.")
|
||||||
resetForm();
|
resetForm();
|
||||||
} else {
|
} else {
|
||||||
// 실패: 화면 유지 & 입력 내용 유지
|
// 실패: 화면 유지 & 입력 내용 유지
|
||||||
@@ -140,19 +141,19 @@ export const KeyInPaymentRequestPage = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const isValidCardExpiration = () => {
|
const isValidCardExpiration = () => {
|
||||||
if (cardExpirationMonth.length !== 2 || cardExpirationYear.length !== 2) {
|
if (expMon.length !== 2 || expYear.length !== 2) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const month = parseInt(cardExpirationMonth);
|
const month = parseInt(expMon);
|
||||||
return month >= 1 && month <= 12;
|
return month >= 1 && month <= 12;
|
||||||
};
|
};
|
||||||
|
|
||||||
const isFormValid = () => {
|
const isFormValid = () => {
|
||||||
return (
|
return (
|
||||||
mid.trim() !== '' &&
|
mid.trim() !== '' &&
|
||||||
goodsName.trim() !== '' &&
|
productName.trim() !== '' &&
|
||||||
amount > 0 &&
|
amount > 0 &&
|
||||||
buyerName.trim() !== '' &&
|
customerName.trim() !== '' &&
|
||||||
isValidEmail(email) &&
|
isValidEmail(email) &&
|
||||||
isValidPhoneNumber(phoneNumber) &&
|
isValidPhoneNumber(phoneNumber) &&
|
||||||
isValidCardNumber() &&
|
isValidCardNumber() &&
|
||||||
@@ -187,8 +188,8 @@ export const KeyInPaymentRequestPage = () => {
|
|||||||
<div className="billing-field">
|
<div className="billing-field">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={goodsName}
|
value={productName}
|
||||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setGoodsName(e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => setProductName(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -215,8 +216,8 @@ export const KeyInPaymentRequestPage = () => {
|
|||||||
<div className="billing-field">
|
<div className="billing-field">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={buyerName}
|
value={customerName}
|
||||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setBuyerName(e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => setCustomerName(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -318,10 +319,10 @@ export const KeyInPaymentRequestPage = () => {
|
|||||||
<div className="billing-field" style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>
|
<div className="billing-field" style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={cardExpirationMonth}
|
value={expMon}
|
||||||
onChange={(e: ChangeEvent<HTMLInputElement>) => {
|
onChange={(e: ChangeEvent<HTMLInputElement>) => {
|
||||||
const onlyNumbers = e.target.value.replace(/[^0-9]/g, '');
|
const onlyNumbers = e.target.value.replace(/[^0-9]/g, '');
|
||||||
if (onlyNumbers.length <= 2) setCardExpirationMonth(onlyNumbers);
|
if (onlyNumbers.length <= 2) setExpMon(onlyNumbers);
|
||||||
}}
|
}}
|
||||||
inputMode="numeric"
|
inputMode="numeric"
|
||||||
pattern="[0-9]*"
|
pattern="[0-9]*"
|
||||||
@@ -332,10 +333,10 @@ export const KeyInPaymentRequestPage = () => {
|
|||||||
<span>/</span>
|
<span>/</span>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={cardExpirationYear}
|
value={expYear}
|
||||||
onChange={(e: ChangeEvent<HTMLInputElement>) => {
|
onChange={(e: ChangeEvent<HTMLInputElement>) => {
|
||||||
const onlyNumbers = e.target.value.replace(/[^0-9]/g, '');
|
const onlyNumbers = e.target.value.replace(/[^0-9]/g, '');
|
||||||
if (onlyNumbers.length <= 2) setCardExpirationYear(onlyNumbers);
|
if (onlyNumbers.length <= 2) setExpYear(onlyNumbers);
|
||||||
}}
|
}}
|
||||||
inputMode="numeric"
|
inputMode="numeric"
|
||||||
pattern="[0-9]*"
|
pattern="[0-9]*"
|
||||||
@@ -351,8 +352,8 @@ export const KeyInPaymentRequestPage = () => {
|
|||||||
<div className="billing-field">
|
<div className="billing-field">
|
||||||
<select
|
<select
|
||||||
disabled={amount < 50000}
|
disabled={amount < 50000}
|
||||||
value={instmntMonth}
|
value={instmnt}
|
||||||
onChange={(e: ChangeEvent<HTMLSelectElement>) => setInstmntMonth(e.target.value)}
|
onChange={(e: ChangeEvent<HTMLSelectElement>) => setInstmnt(e.target.value)}
|
||||||
>
|
>
|
||||||
<option value="00">일시불 (무이자)</option>
|
<option value="00">일시불 (무이자)</option>
|
||||||
{amount >= 50000 && (
|
{amount >= 50000 && (
|
||||||
@@ -379,8 +380,8 @@ export const KeyInPaymentRequestPage = () => {
|
|||||||
<div className="billing-field">
|
<div className="billing-field">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={moid}
|
value={orderNumber}
|
||||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setMoid(e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => setOrderNumber(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -154,21 +154,21 @@ export const LinkPaymentDetailPage = () => {
|
|||||||
additionalServiceCategory={AdditionalServiceCategory.LinkPaymentHistory}
|
additionalServiceCategory={AdditionalServiceCategory.LinkPaymentHistory}
|
||||||
detailInfo={detailInfo}
|
detailInfo={detailInfo}
|
||||||
></DetailInfoWrap>
|
></DetailInfoWrap>
|
||||||
|
<div className="link-payment-detail-button">
|
||||||
|
<button
|
||||||
|
className="btn-50 btn-blue flex-1"
|
||||||
|
onClick={() => onClickToSeparateApproval()}
|
||||||
|
disabled={false}
|
||||||
|
>분리승인 상세</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="apply-row">
|
<div className="apply-row">
|
||||||
<button
|
|
||||||
className="btn-50 btn-blue flex-1"
|
|
||||||
onClick={() => onClickToSeparateApproval()}
|
|
||||||
disabled={false}
|
|
||||||
>분리승인 상세</button>
|
|
||||||
</div>
|
|
||||||
{/* <div className="apply-row">
|
|
||||||
<button
|
<button
|
||||||
className="btn-50 btn-blue flex-1"
|
className="btn-50 btn-blue flex-1"
|
||||||
onClick={() => onClickToResend()}
|
onClick={() => onClickToResend()}
|
||||||
disabled={!isResendEnabled()}
|
disabled={!isResendEnabled()}
|
||||||
>재발송</button>
|
>재발송</button>
|
||||||
</div> */}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main >
|
</main >
|
||||||
|
|||||||
@@ -16,7 +16,15 @@ import { useAppBridge } from '@/hooks/useAppBridge';
|
|||||||
|
|
||||||
export const SettingPage = () => {
|
export const SettingPage = () => {
|
||||||
let userInfo = useStore.getState().UserStore.userInfo;
|
let userInfo = useStore.getState().UserStore.userInfo;
|
||||||
const { isPushNotificationEnabled, openAppSettings, logout, getLoginType } = useAppBridge();
|
const {
|
||||||
|
isPushNotificationEnabled,
|
||||||
|
openAppSettings,
|
||||||
|
logout,
|
||||||
|
getLoginType,
|
||||||
|
getNotificationSetting,
|
||||||
|
setNotificationSetting: updateNotificationSetting,
|
||||||
|
isAndroid
|
||||||
|
} = useAppBridge();
|
||||||
|
|
||||||
useSetHeaderTitle('설정');
|
useSetHeaderTitle('설정');
|
||||||
useSetHeaderType(HeaderType.LeftArrow);
|
useSetHeaderType(HeaderType.LeftArrow);
|
||||||
@@ -31,6 +39,7 @@ export const SettingPage = () => {
|
|||||||
const {mutateAsync: appAlarmConsent} = useAppAlarmConsentMutation();
|
const {mutateAsync: appAlarmConsent} = useAppAlarmConsentMutation();
|
||||||
|
|
||||||
const [pushNotificationEnabled, setPushNotificationEnabled] = useState<boolean>(false);
|
const [pushNotificationEnabled, setPushNotificationEnabled] = useState<boolean>(false);
|
||||||
|
const [notificationSetting, setNotificationSetting] = useState<boolean>(true);
|
||||||
const [alarmSetting, setAlarmSetting] = useState<Record<string, boolean>>({
|
const [alarmSetting, setAlarmSetting] = useState<Record<string, boolean>>({
|
||||||
'21': false,
|
'21': false,
|
||||||
'11': false,
|
'11': false,
|
||||||
@@ -65,7 +74,74 @@ export const SettingPage = () => {
|
|||||||
const onClickPushNotificationToggle = () => {
|
const onClickPushNotificationToggle = () => {
|
||||||
openAppSettings();
|
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 = () => {
|
const callAppAlarmFind = () => {
|
||||||
if(userInfo.usrid){
|
if(userInfo.usrid){
|
||||||
let params: AppAlarmFindParams = {
|
let params: AppAlarmFindParams = {
|
||||||
@@ -115,16 +191,19 @@ export const SettingPage = () => {
|
|||||||
callAppAlarmFind();
|
callAppAlarmFind();
|
||||||
checkPushNotificationStatus();
|
checkPushNotificationStatus();
|
||||||
loadLoginType();
|
loadLoginType();
|
||||||
|
loadNotificationSetting(); // ✅ 추가
|
||||||
|
|
||||||
// 앱이 포어그라운드로 돌아올 때 푸시 알림 권한 상태 재확인
|
// 앱이 포어그라운드로 돌아올 때 푸시 알림 권한 상태 재확인
|
||||||
const handleVisibilityChange = () => {
|
const handleVisibilityChange = () => {
|
||||||
if (document.visibilityState === 'visible') {
|
if (document.visibilityState === 'visible') {
|
||||||
checkPushNotificationStatus();
|
checkPushNotificationStatus();
|
||||||
|
loadNotificationSetting(); // ✅ 추가
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFocus = () => {
|
const handleFocus = () => {
|
||||||
checkPushNotificationStatus();
|
checkPushNotificationStatus();
|
||||||
|
loadNotificationSetting(); // ✅ 추가
|
||||||
};
|
};
|
||||||
|
|
||||||
document.addEventListener('visibilitychange', handleVisibilityChange);
|
document.addEventListener('visibilitychange', handleVisibilityChange);
|
||||||
@@ -134,20 +213,28 @@ export const SettingPage = () => {
|
|||||||
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
||||||
window.removeEventListener('focus', handleFocus);
|
window.removeEventListener('focus', handleFocus);
|
||||||
};
|
};
|
||||||
}, [checkPushNotificationStatus, loadLoginType]);
|
}, [checkPushNotificationStatus, loadLoginType, loadNotificationSetting]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<main className="pop">
|
<main className="pop">
|
||||||
<div className="sub-wrap">
|
<div className="sub-wrap">
|
||||||
|
{/* ✅ Android일 때는 앱 내 설정, 아니면 시스템 권한 표시 */}
|
||||||
<div className="settings-header">
|
<div className="settings-header">
|
||||||
<div className="settings-title">알림 수신 설정</div>
|
<div className="settings-title">알림 수신 설정</div>
|
||||||
<label className="settings-switch" onClick={onClickPushNotificationToggle}>
|
<label className="settings-switch">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={pushNotificationEnabled}
|
checked={isAndroid ? notificationSetting : pushNotificationEnabled}
|
||||||
readOnly
|
readOnly
|
||||||
onClick={(e) => e.preventDefault()}
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (isAndroid) {
|
||||||
|
onClickNotificationSettingToggle();
|
||||||
|
} else {
|
||||||
|
onClickPushNotificationToggle();
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<span className="slider"></span>
|
<span className="slider"></span>
|
||||||
</label>
|
</label>
|
||||||
|
|||||||
@@ -403,4 +403,14 @@ main.home-main{
|
|||||||
}
|
}
|
||||||
.auth-list{
|
.auth-list{
|
||||||
padding-bottom: 0px;
|
padding-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 링크 결제 상세 페이지 */
|
||||||
|
.link-payment-detail-button {
|
||||||
|
padding: 16px 0px 16px 0px;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-payment-detail-button button {
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
@@ -74,7 +74,11 @@ export enum BridgeMessageType {
|
|||||||
OPEN_APP_SETTINGS = 'openAppSettings',
|
OPEN_APP_SETTINGS = 'openAppSettings',
|
||||||
|
|
||||||
// 로그인 방식 설정
|
// 로그인 방식 설정
|
||||||
GET_LOGIN_TYPE = 'getLoginType'
|
GET_LOGIN_TYPE = 'getLoginType',
|
||||||
|
|
||||||
|
// 알림 수신 설정 (Android only)
|
||||||
|
GET_NOTIFICATION_SETTING = 'getNotificationSetting',
|
||||||
|
SET_NOTIFICATION_SETTING = 'setNotificationSetting'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DeviceInfo {
|
export interface DeviceInfo {
|
||||||
@@ -103,4 +107,11 @@ export interface ShareContent {
|
|||||||
text: string;
|
text: string;
|
||||||
url?: string;
|
url?: string;
|
||||||
image?: string;
|
image?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NotificationSettingResponse {
|
||||||
|
success: boolean;
|
||||||
|
enabled: boolean;
|
||||||
|
needsPermission?: boolean;
|
||||||
|
message?: string;
|
||||||
}
|
}
|
||||||
@@ -210,6 +210,16 @@ class AppBridge {
|
|||||||
return this.sendMessage(BridgeMessageType.GET_LOGIN_TYPE);
|
return this.sendMessage(BridgeMessageType.GET_LOGIN_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 알림 수신 설정 가져오기 (Android only)
|
||||||
|
async getNotificationSetting(): Promise<{ enabled: boolean }> {
|
||||||
|
return this.sendMessage(BridgeMessageType.GET_NOTIFICATION_SETTING);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 알림 수신 설정 저장하기 (Android only)
|
||||||
|
async setNotificationSetting(enabled: boolean): Promise<any> {
|
||||||
|
return this.sendMessage(BridgeMessageType.SET_NOTIFICATION_SETTING, { enabled });
|
||||||
|
}
|
||||||
|
|
||||||
// 네이티브 환경 체크
|
// 네이티브 환경 체크
|
||||||
isNativeEnvironment(): boolean {
|
isNativeEnvironment(): boolean {
|
||||||
return !!(
|
return !!(
|
||||||
|
|||||||
Reference in New Issue
Block a user