From b10376e171cffe945d8a87fafdabbe3f1ab36227 Mon Sep 17 00:00:00 2001 From: HyeonJongKim Date: Fri, 24 Oct 2025 20:45:24 +0900 Subject: [PATCH] =?UTF-8?q?-=20=EB=B6=80=EA=B0=80=EC=84=9C=EB=B9=84?= =?UTF-8?q?=EC=8A=A4=20=EC=86=8C=EA=B0=9C=20List,=20=EA=B6=8C=ED=95=9C=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EC=B6=94=EA=B0=80=20-=20=EA=B0=81=20API?= =?UTF-8?q?=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/use-extension-check-mutation.ts | 31 +++ .../model/alimtalk/constant.ts | 8 +- .../model/alimtalk/types.ts | 4 +- .../model/payout/constant.ts | 14 +- .../additional-service/model/payout/types.ts | 15 +- .../model/sms-payment/types.ts | 1 + .../additional-service/model/types.ts | 29 ++- .../filter/account-holder-auth-filter.tsx | 5 +- .../additional-service/ui/list-date-group.tsx | 3 +- .../additional-service/ui/list-item.tsx | 51 ++--- .../common/ui/download-type-bottom-sheet.tsx | 90 ++++++++ .../account-holder-auth-page.tsx | 10 + .../account-holder-auth/detail-page.tsx | 2 +- .../account-holder-search-page.tsx | 10 + .../account-holder-search/request-page.tsx | 2 +- .../alimtalk/detail-page.tsx | 6 +- .../additional-service/alimtalk/list-page.tsx | 10 + .../alimtalk/setting-page.tsx | 4 +- .../additional-service/ars/list-page.tsx | 13 +- .../face-auth/face-auth-page.tsx | 18 +- .../fund-account/transfer-list-page.tsx | 22 +- .../fund-account/transfer-request-page.tsx | 4 +- .../key-in-payment/key-in-payment-page.tsx | 11 + .../link-payment-history-page.tsx | 10 + .../link-payment-wait-detail-page.tsx | 10 +- src/pages/additional-service/list-page.tsx | 193 ++++++++---------- .../additional-service/payout/detail-page.tsx | 74 +++++-- .../additional-service/payout/list-page.tsx | 125 ++++++------ .../payout/request-page.tsx | 49 +++-- .../sms-payment/sms-payment-page.tsx | 11 +- src/shared/api/api-url-additional-service.ts | 6 +- .../lib/hooks/use-extension-access-check.tsx | 97 +++++++++ src/shared/ui/dialogs/dialog.tsx | 3 +- 33 files changed, 657 insertions(+), 284 deletions(-) create mode 100644 src/entities/additional-service/api/use-extension-check-mutation.ts create mode 100644 src/entities/common/ui/download-type-bottom-sheet.tsx create mode 100644 src/shared/lib/hooks/use-extension-access-check.tsx diff --git a/src/entities/additional-service/api/use-extension-check-mutation.ts b/src/entities/additional-service/api/use-extension-check-mutation.ts new file mode 100644 index 0000000..127aefb --- /dev/null +++ b/src/entities/additional-service/api/use-extension-check-mutation.ts @@ -0,0 +1,31 @@ +import axios from 'axios'; +import { API_URL_ADDITIONAL_SERVICE } from '@/shared/api/api-url-additional-service'; +import { resultify } from '@/shared/lib/resultify'; +import { CBDCAxiosError } from '@/shared/@types/error'; +import { + ExtensionCheckParams, + ExtensionCheckResponse, + ExtensionListParams, + ExtensionListResponse +} from '../model/types'; +import { + useMutation, + UseMutationOptions +} from '@tanstack/react-query'; + +export const extensionCheck = (params: ExtensionCheckParams) => { + return resultify( + axios.post(API_URL_ADDITIONAL_SERVICE.extensionCheck(), params), + ); +}; + +export const useExtensionCheckMutation = (options?: UseMutationOptions) => { + const mutation = useMutation({ + ...options, + mutationFn: (params: ExtensionCheckParams) => extensionCheck(params), + }); + + return { + ...mutation, + }; +}; \ No newline at end of file diff --git a/src/entities/additional-service/model/alimtalk/constant.ts b/src/entities/additional-service/model/alimtalk/constant.ts index ae8eead..c70ef47 100644 --- a/src/entities/additional-service/model/alimtalk/constant.ts +++ b/src/entities/additional-service/model/alimtalk/constant.ts @@ -81,10 +81,10 @@ export const getAlimtalkServiceCodeText = (status?: string): string => { if (!status) return ''; const serviceCodeMap: Record = { - '01': '카드', - '02': '신용카드', - '03': '가상계좌', - '05': '휴대폰' + 'CARD': '신용카드', + 'BANK': '계좌이체', + 'VBANK': '가상계좌', + 'PHONE': '휴대폰' } return serviceCodeMap[status] || status; diff --git a/src/entities/additional-service/model/alimtalk/types.ts b/src/entities/additional-service/model/alimtalk/types.ts index 12f0b39..d59f622 100644 --- a/src/entities/additional-service/model/alimtalk/types.ts +++ b/src/entities/additional-service/model/alimtalk/types.ts @@ -126,14 +126,14 @@ export interface ExtensionAlimtalkDetailParams { export interface ExtensionAlimtalkDetailResponse { receiverName: string; - merchantName: string; + companyName: string; sendDate: string; mid: string; tid: string; extensionServiceName: string; sendType: AlimtalkSendType; senderName: string; - paymentMethod: string; + serviceCode: string; alimCl: AlimtalkAlimCl; sendCl: AlimTalkSendCl; }; diff --git a/src/entities/additional-service/model/payout/constant.ts b/src/entities/additional-service/model/payout/constant.ts index 80e69cd..d6921b3 100644 --- a/src/entities/additional-service/model/payout/constant.ts +++ b/src/entities/additional-service/model/payout/constant.ts @@ -9,4 +9,16 @@ export const PayoutDisbursementStatusBtnGroup = [ {name: '요청', value: PayoutDisbursementStatus.REQUEST}, {name: '성공', value: PayoutDisbursementStatus.SUCCESS}, {name: '실패', value: PayoutDisbursementStatus.FAIL}, -]; \ No newline at end of file +]; + +export const getPayoutStatusText = (status?: string): string => { + if (!status) return ''; + + const statusMap: Record = { + "REQUEST" : "요청", + "SUCCESS" : "성공", + "FAIL" : "실패" + } + + return statusMap[status] || status; +} \ No newline at end of file diff --git a/src/entities/additional-service/model/payout/types.ts b/src/entities/additional-service/model/payout/types.ts index 976bb59..56c7a8a 100644 --- a/src/entities/additional-service/model/payout/types.ts +++ b/src/entities/additional-service/model/payout/types.ts @@ -6,7 +6,9 @@ export interface ExtensionPayoutRequestParams { disbursementAmount: number; settlementDate: string; }; -export interface ExtensionPayoutRequestResponse {}; +export interface ExtensionPayoutRequestResponse { + status: boolean; +}; export enum PayoutSearchDateType { REQUEST_DATE = 'REQUEST_DATE', SETTLEMENT_DATE = 'SETTLEMENT_DATE', @@ -36,10 +38,15 @@ export interface PayoutContent { requestDate?: string; settlementDate?: string; companyName?: string; - disbursementStatus?: PayoutDisbursementStatus; - disbursementAmount?: number; + status?: PayoutDisbursementStatus; + amount?: number; +}; +export interface ExtensionPayoutExcelParams { + mid: string; + email: string; + fromDate: string; + toDate: string; }; -export interface ExtensionPayoutExcelParams extends ExtensionPayoutListParams {}; export interface ExtensionPayoutExcelResponse {} diff --git a/src/entities/additional-service/model/sms-payment/types.ts b/src/entities/additional-service/model/sms-payment/types.ts index 51b9dee..62e5b78 100644 --- a/src/entities/additional-service/model/sms-payment/types.ts +++ b/src/entities/additional-service/model/sms-payment/types.ts @@ -117,6 +117,7 @@ export interface ExtensionSmsDownloadExcelParams extends ExtensionRequestParams fromDate: string; toDate: string; smsCl: string; + } export interface ExtensionSmsDownloadExcelResponse { diff --git a/src/entities/additional-service/model/types.ts b/src/entities/additional-service/model/types.ts index a90dede..d689c04 100644 --- a/src/entities/additional-service/model/types.ts +++ b/src/entities/additional-service/model/types.ts @@ -10,6 +10,8 @@ import { AccountHolderSearchListItem } from './account-holder-search/types'; import { KeyInPaymentListItem } from './key-in/types'; import { AccountHolderAuthListItem, AccountHolderAuthStatus } from './account-holder-auth/types'; import { LinkContentType, LinkPaymentHistoryListItem, LinkPaymentSendMethod, LinkPaymentWaitListItem } from './link-pay/types'; +import { IMAGE_ROOT } from '@/shared/constants/common'; +import { PATHS } from '@/shared/constants/paths'; // ======================================== // 공통 Enums 및 타입들 @@ -47,6 +49,20 @@ export enum Language { EN = "EN" } +export const SERVICE_MAP = [ + { code: 'SMS', serviceName: 'SMS 결제 통보', serviceDesc: '입금 요청부터 완료까지 SMS 자동 전송', icon: IMAGE_ROOT + '/icon_ing03.svg', path: PATHS.additionalService.smsPaymentNotification }, + { code: 'ARS', serviceName: '신용카드 ARS 결제', serviceDesc: '전화 한 통으로 결제 성공 편리하고 안전한 서비스', icon: IMAGE_ROOT + '/icon_ing01.svg', path: PATHS.additionalService.ars.list }, + { code: 'KEYIN', serviceName: 'KEY-IN 결제', serviceDesc: '상담 중 카드정보 입력으로 간편한 결제 지원', icon: IMAGE_ROOT + '/icon_ing02.svg', path: PATHS.additionalService.keyInPayment.list }, + { code: 'SEARCH_ACCOUNT_NAME', serviceName: '계좌성명조회', serviceDesc: '예금주 정보 입력으로 즉시 예금주 확인', icon: IMAGE_ROOT + '/icon_ing04.svg', path: PATHS.additionalService.accountHolderSearch.list }, + { code: 'PAYOUT', serviceName: '지급대행', serviceDesc: '하위 가맹점에 빠른 정산금 지급 지급대행 서비스', icon: IMAGE_ROOT + '/icon_ing05.svg', path: PATHS.additionalService.payout.list }, + { code: 'SETTLEMENT', serviceName: '정산대행', serviceDesc: '하위 가맹점 정산금 계산부터 지급까지 자동 해결 서비스', icon: IMAGE_ROOT + '/icon_ing06.svg', path: PATHS.additionalService.settlementAgency.manage }, + { code: 'LINKPAY', serviceName: '링크 결제', serviceDesc: '결제 링크 전송만으로 어디서든 결제 가능 서비스', icon: IMAGE_ROOT + '/icon_ing07.svg', path: PATHS.additionalService.linkPayment.shippingHistory }, + { code: 'FUND_ACCOUNT', serviceName: '자금이체', serviceDesc: '예치금으로 즉시 송금, 파일 등록만으로 다중 송금 가능', icon: IMAGE_ROOT + '/icon_ing08.svg', path: PATHS.additionalService.fundAccount.transferList }, + { code: 'ACCOUNT_AUTH', serviceName: '계좌점유인증', serviceDesc: '1원 송금으로 실제 계좌 점유 확인 여부', icon: IMAGE_ROOT + '/icon_ing09.svg', path: PATHS.additionalService.accountHolderAuth.list }, + { code: 'ALIMTALK', serviceName: '알림톡 결제통보', serviceDesc: '결제 상태를 알림톡으로 쉽고 빠른 안내', icon: IMAGE_ROOT + '/icon_ing10.svg', path: PATHS.additionalService.alimtalk.list }, + { code: 'FACE_AUTH', serviceName: '얼굴인증', serviceDesc: '얼굴 인식으로 간편 본인확인과 결제 가능한 안전 결제 서비스', icon: IMAGE_ROOT + '/icon_ing11.svg', path: PATHS.additionalService.faceAuth.list }, +]; + // ======================================== // 상세정보 Interface // ======================================== @@ -223,8 +239,17 @@ export interface ExtensionListItemProps { availableExtensionList: Array; } -export interface ExtensionListResponse extends DefaulResponsePagination { - content: Array +export interface ExtensionListResponse { + activeExtensionList: string[]; + availableExtensionList: string[]; +} + +export interface ExtensionCheckParams { + extensionCode: string; +} + +export interface ExtensionCheckResponse { + checkResult: boolean; } // ======================================== diff --git a/src/entities/additional-service/ui/account-holder-auth/filter/account-holder-auth-filter.tsx b/src/entities/additional-service/ui/account-holder-auth/filter/account-holder-auth-filter.tsx index 58d4dbd..e350c96 100644 --- a/src/entities/additional-service/ui/account-holder-auth/filter/account-holder-auth-filter.tsx +++ b/src/entities/additional-service/ui/account-holder-auth/filter/account-holder-auth-filter.tsx @@ -1,7 +1,7 @@ import moment from 'moment'; import { IMAGE_ROOT } from '@/shared/constants/common'; import { motion } from 'framer-motion'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { FilterSelect } from '@/shared/ui/filter/select'; import { FilterCalendar } from '@/shared/ui/filter/calendar'; import { FilterButtonGroups } from '@/shared/ui/filter/button-groups'; @@ -42,6 +42,9 @@ export const AccountHolderAuthFilter = ({ onClickToClose(); }; + useEffect(() => { + setFilterAuthStatus(authStatus); + }, [authStatus]); return ( <> { const { navigate } = useNavigate(); @@ -89,7 +90,7 @@ export const ListItem = ({ } } else if (additionalServiceCategory === AdditionalServiceCategory.Alimtalk) { - if (sendCl === "SUCCESS" || "REQUEST") { + if (sendCl === "SUCCESS" || sendCl === "REQUEST") { rs = 'blue'; } else { rs = 'gray'; @@ -104,20 +105,13 @@ export const ListItem = ({ } } else if (additionalServiceCategory === AdditionalServiceCategory.LinkPaymentHistory) { - if (paymentStatus === "PAYMENT_COMPLETE") { + if (paymentStatus === "0" || paymentStatus === "1" || paymentStatus === "2") { rs = 'blue'; } - - else if (paymentStatus === "ACTIVE") { - rs = 'blue'; + else if (paymentStatus === "3") { + rs = 'gray'; } - else if (paymentStatus === "DEPOSIT_REQUEST") { - rs = 'blue'; - } - else if (paymentStatus === "PAYMENT_FAIL") { - rs = 'blue'; - } - else if (paymentStatus === "INACTIVE") { + else if (paymentStatus === '4') { rs = 'gray'; } } else if (additionalServiceCategory === AdditionalServiceCategory.LinkPaymentWait) { @@ -144,6 +138,12 @@ export const ListItem = ({ } else if (resultStatus === "FAIL") { rs = 'gray'; } + } else if (additionalServiceCategory === AdditionalServiceCategory.Payout) { + if (status === "SUCCESS" || status === "REQUEST") { + rs = 'blue'; + } else if (status === "FAIL") { + rs = 'gray'; + } } return rs; @@ -286,7 +286,7 @@ export const ListItem = ({ if (applicationDate && applicationDate.length >= 12) { timeStr = applicationDate.substring(8, 10) + ':' + applicationDate.substring(10, 12); } else { - timeStr = requestDate?.substring(8,10) + ':' + requestDate?.substring(10, 12); + timeStr = requestDate?.substring(8, 10) + ':' + requestDate?.substring(10, 12); } } else if (additionalServiceCategory === AdditionalServiceCategory.Ars) { @@ -349,9 +349,10 @@ export const ListItem = ({ else if (additionalServiceCategory === AdditionalServiceCategory.FaceAuth) { str = `${userMallId}(${mid})`; } - else if (additionalServiceCategory === AdditionalServiceCategory.LinkPaymentHistory || - additionalServiceCategory === AdditionalServiceCategory.LinkPaymentWait + else if (additionalServiceCategory === AdditionalServiceCategory.LinkPaymentHistory ) { + str = `${buyerName}`; + } else if (additionalServiceCategory === AdditionalServiceCategory.LinkPaymentWait) { str = `${buyerName}(${receiverInfo})`; } else if (additionalServiceCategory === AdditionalServiceCategory.Payout) { @@ -451,7 +452,7 @@ export const ListItem = ({ else if (additionalServiceCategory === AdditionalServiceCategory.Payout) { rs.push(
- {disbursementStatus} + {getPayoutStatusText(disbursementStatus)} | {submallId}
@@ -498,7 +499,7 @@ export const ListItem = ({ ); } else if (additionalServiceCategory === AdditionalServiceCategory.Alimtalk) { - console.log(serviceCode) + console.log(serviceCode) rs.push(
{getTime()} diff --git a/src/entities/common/ui/download-type-bottom-sheet.tsx b/src/entities/common/ui/download-type-bottom-sheet.tsx new file mode 100644 index 0000000..3fe6421 --- /dev/null +++ b/src/entities/common/ui/download-type-bottom-sheet.tsx @@ -0,0 +1,90 @@ +import { BottomSheetMotionDuration, BottomSheetMotionVaiants } from '@/entities/common/model/constant'; +import { IMAGE_ROOT } from '@/shared/constants/common'; +import { motion } from 'framer-motion'; + +export interface DownloadTypeBottomSheetProps { + bottomSheetOn: boolean; + setBottomSheetOn: (bottomSheetOn: boolean) => void; + onSelectType: (type: 'IMAGE' | 'EMAIL') => void; +} + +export const DownloadTypeBottomSheet = ({ + bottomSheetOn, + setBottomSheetOn, + onSelectType +}: DownloadTypeBottomSheetProps) => { + + const onClickToClose = () => { + setBottomSheetOn(false); + }; + + const handleSelectType = (type: 'IMAGE' | 'EMAIL') => { + onSelectType(type); + setBottomSheetOn(false); + }; + + return ( + <> + { (bottomSheetOn) && +
+ } + +
+
+

다운로드 방식을 선택하세요

+ +
+
+ +
+
+
handleSelectType('IMAGE')} + style={{ cursor: 'pointer' }} + > +
+
+ 이미지 +
+ 이미지 저장 +
+ +
handleSelectType('EMAIL')} + style={{ cursor: 'pointer' }} + > +
+
+ 메일 +
+ 메일로 받기 +
+
+
+
+ + ); +}; diff --git a/src/pages/additional-service/account-holder-auth/account-holder-auth-page.tsx b/src/pages/additional-service/account-holder-auth/account-holder-auth-page.tsx index bbeebdf..d9d46a3 100644 --- a/src/pages/additional-service/account-holder-auth/account-holder-auth-page.tsx +++ b/src/pages/additional-service/account-holder-auth/account-holder-auth-page.tsx @@ -22,12 +22,18 @@ import { useStore } from '@/shared/model/store'; import { AccountHolderAuthListItem, AccountHolderAuthStatus, ExtensionAccountHolderAuthContentItem, ExtensionAccountHolderAuthDownloadExcelParams, ExtensionAccountHolderAuthDownloadExcelResponse } from '@/entities/additional-service/model/account-holder-auth/types'; import { AdditionalServiceCategory } from '@/entities/additional-service/model/types'; import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet'; +import { useExtensionAccessCheck } from '@/shared/lib/hooks/use-extension-access-check'; export const AccountHolderAuthPage = () => { const { navigate } = useNavigate(); const userMid = useStore.getState().UserStore.mid; + // 권한 체크 + const { hasAccess, AccessDeniedDialog } = useExtensionAccessCheck({ + extensionCode: 'ACCOUNT_AUTH' + }); + const [sortType, setSortType] = useState(SortTypeKeys.LATEST); const [listItems, setListItems] = useState>([]); const [filterOn, setFilterOn] = useState(false); @@ -115,6 +121,10 @@ export const AccountHolderAuthPage = () => { authStatus ]); + if (!hasAccess) { + return ; + } + return ( <>
diff --git a/src/pages/additional-service/account-holder-auth/detail-page.tsx b/src/pages/additional-service/account-holder-auth/detail-page.tsx index 08e20b5..d8eef8f 100644 --- a/src/pages/additional-service/account-holder-auth/detail-page.tsx +++ b/src/pages/additional-service/account-holder-auth/detail-page.tsx @@ -83,7 +83,7 @@ export const AccountHolderAuthDetailPage = () => {
  • 계좌번호 - {detail?.bankName} + {detail?.accountNo}
  • 예금주 diff --git a/src/pages/additional-service/account-holder-search/account-holder-search-page.tsx b/src/pages/additional-service/account-holder-search/account-holder-search-page.tsx index 93fa299..fcbbc6a 100644 --- a/src/pages/additional-service/account-holder-search/account-holder-search-page.tsx +++ b/src/pages/additional-service/account-holder-search/account-holder-search-page.tsx @@ -22,12 +22,18 @@ import { useStore } from '@/shared/model/store'; import { AccountHolderSearchListItem, AccountHolderSearchCl, AccountHolderResultStatus } from '@/entities/additional-service/model/account-holder-search/types'; import { resultStatusBtnGroup } from '@/entities/additional-service/model/account-holder-search/constant'; import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet'; +import { useExtensionAccessCheck } from '@/shared/lib/hooks/use-extension-access-check'; export const AccountHolderSearchPage = () => { const { navigate } = useNavigate(); const userMid = useStore.getState().UserStore.mid; + // 권한 체크 + const { hasAccess, AccessDeniedDialog } = useExtensionAccessCheck({ + extensionCode: 'SEARCH_ACCOUNT_NAME' + }); + const [sortType, setSortType] = useState(SortTypeKeys.LATEST); const [listItems, setListItems] = useState>([]); const [pageParam, setPageParam] = useState(DEFAULT_PAGE_PARAM); @@ -125,6 +131,10 @@ export const AccountHolderSearchPage = () => { resultStatus ]); + if (!hasAccess) { + return ; + } + return ( <>
    diff --git a/src/pages/additional-service/account-holder-search/request-page.tsx b/src/pages/additional-service/account-holder-search/request-page.tsx index 4bb1a0b..f3da068 100644 --- a/src/pages/additional-service/account-holder-search/request-page.tsx +++ b/src/pages/additional-service/account-holder-search/request-page.tsx @@ -18,7 +18,7 @@ export const AccountHolderSearchRequestPage = () => { const midOptions = useStore.getState().UserStore.selectOptionsMids const bankList = useStore.getState().CommonStore.bankList - useSetHeaderTitle('계좌성명조회_신청'); + useSetHeaderTitle('계좌성명조회 신청'); useSetHeaderType(HeaderType.LeftArrow); useSetFooterMode(false); useSetOnBack(() => { diff --git a/src/pages/additional-service/alimtalk/detail-page.tsx b/src/pages/additional-service/alimtalk/detail-page.tsx index 96864b1..efdbef7 100644 --- a/src/pages/additional-service/alimtalk/detail-page.tsx +++ b/src/pages/additional-service/alimtalk/detail-page.tsx @@ -12,7 +12,7 @@ import { useEffect, useState } from 'react'; import { ExtensionAlimtalkDetailParams, ExtensionAlimtalkDetailResponse } from '@/entities/additional-service/model/alimtalk/types'; import { useExtensionAlimtalkDetailMutation } from '@/entities/additional-service/api/alimtalk/use-extansion-alimtalk-detail-mutation'; import moment from 'moment'; -import { getAlimtalkAlimClText, getAlimtalkSendClTypeText, getAlimtalkSendTypeText } from '@/entities/additional-service/model/alimtalk/constant'; +import { getAlimtalkAlimClText, getAlimtalkSendClTypeText, getAlimtalkSendTypeText, getAlimtalkServiceCodeText } from '@/entities/additional-service/model/alimtalk/constant'; export const AlimtalkDetailPage = () => { const { navigate } = useNavigate(); @@ -60,7 +60,7 @@ export const AlimtalkDetailPage = () => {
    { detail?.receiverName }
    -
    { detail?.merchantName }
    +
    { detail?.companyName }
    { getDate(detail?.sendDate) }
  • @@ -89,7 +89,7 @@ export const AlimtalkDetailPage = () => {
  • 결제서비스 - { detail?.paymentMethod } + { getAlimtalkServiceCodeText(detail?.serviceCode) }
  • 알림구분 diff --git a/src/pages/additional-service/alimtalk/list-page.tsx b/src/pages/additional-service/alimtalk/list-page.tsx index 7e50ab4..3633b9b 100644 --- a/src/pages/additional-service/alimtalk/list-page.tsx +++ b/src/pages/additional-service/alimtalk/list-page.tsx @@ -31,11 +31,17 @@ import { useStore } from '@/shared/model/store'; import { snackBar } from '@/shared/lib'; import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet'; import { AlimtalkFilter } from '@/entities/additional-service/ui/filter/alimtalk-filter'; +import { useExtensionAccessCheck } from '@/shared/lib/hooks/use-extension-access-check'; export const AlimtalkListPage = () => { const { navigate } = useNavigate(); const userMid = useStore.getState().UserStore.mid; + // 권한 체크 + const { hasAccess, AccessDeniedDialog } = useExtensionAccessCheck({ + extensionCode: 'ALIMTALK' + }); + const [sortType, setSortType] = useState(SortTypeKeys.LATEST); const [listItems, setListItems] = useState>([]); const [filterOn, setFilterOn] = useState(false); @@ -182,6 +188,10 @@ export const AlimtalkListPage = () => { sendCl ]); + if (!hasAccess) { + return ; + } + return ( <>
    diff --git a/src/pages/additional-service/alimtalk/setting-page.tsx b/src/pages/additional-service/alimtalk/setting-page.tsx index 2ebcfe6..bdd9c0c 100644 --- a/src/pages/additional-service/alimtalk/setting-page.tsx +++ b/src/pages/additional-service/alimtalk/setting-page.tsx @@ -165,9 +165,9 @@ export const AlimtalkSettingPage = () => { > { const { navigate } = useNavigate(); const userMid = useStore.getState().UserStore.mid; + // 권한 체크 + const { hasAccess, AccessDeniedDialog } = useExtensionAccessCheck({ + extensionCode: 'ARS' + }); + const [sortType, setSortType] = useState(SortTypeKeys.LATEST); const [listItems, setListItems] = useState>([]); const [filterOn, setFilterOn] = useState(false); @@ -119,9 +125,6 @@ export const ArsListPage = () => { setPaymentStatus(val); }; - useEffect(() => { - callList(); - }, []); useEffect(() => { callList(); }, [ @@ -181,6 +184,10 @@ export const ArsListPage = () => { return rs; } + // if (!hasAccess) { + // return ; + // } + return ( <>
    diff --git a/src/pages/additional-service/face-auth/face-auth-page.tsx b/src/pages/additional-service/face-auth/face-auth-page.tsx index daa70c6..d4d444a 100644 --- a/src/pages/additional-service/face-auth/face-auth-page.tsx +++ b/src/pages/additional-service/face-auth/face-auth-page.tsx @@ -22,11 +22,17 @@ import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet'; import { useExtensionFaceAuthListtMutation } from '@/entities/additional-service/api/face-auth/use-extension-face-auth-list-mutation'; import { useExtensionFaceAuthDownloadExcelMutation } from '@/entities/additional-service/api/face-auth/use-extension-face-auth-download-excel-mutation'; import { ListDateGroup } from '@/entities/additional-service/ui/list-date-group'; +import { useExtensionAccessCheck } from '@/shared/lib/hooks/use-extension-access-check'; export const FaceAuthPage = () => { const { navigate } = useNavigate(); const userMid = useStore.getState().UserStore.mid; + // 권한 체크 + const { hasAccess, AccessDeniedDialog } = useExtensionAccessCheck({ + extensionCode: 'FACE_AUTH' + }); + const [sortType, setSortType] = useState(SortTypeKeys.LATEST); const [listItems, setListItems] = useState>([]); const [filterOn, setFilterOn] = useState(false); @@ -54,7 +60,7 @@ export const FaceAuthPage = () => { authResult?: FaceAuthResult }) => { let params: ExtensionFaceAuthListParams = { - mid: mid, + mid: "faceauth0m", userMallId: userMallId, fromDate: fromDate, toDate: toDate, @@ -80,7 +86,7 @@ export const FaceAuthPage = () => { const onSendRequest = (selectedEmail?: string) => { if (selectedEmail) { const params: ExtensionFaceAuthExcelDownlaodPrams = { - mid: mid, + mid: "faceauth0m", email: selectedEmail, fromDate: fromDate, toDate: toDate @@ -106,9 +112,9 @@ export const FaceAuthPage = () => { }; const getListDateGroup = () => { - let rs= []; + let rs = []; let date = ''; - let list= []; + let list = []; for (let i = 0; i < listItems.length; i++) { let item = listItems[i]; if (!!item) { @@ -155,6 +161,10 @@ export const FaceAuthPage = () => { callList(); }, [mid, userMallId, fromDate, toDate, transType, authResult]); + // if (!hasAccess) { + // return ; + // } + return ( <>
    diff --git a/src/pages/additional-service/fund-account/transfer-list-page.tsx b/src/pages/additional-service/fund-account/transfer-list-page.tsx index 00f71a2..e523a8d 100644 --- a/src/pages/additional-service/fund-account/transfer-list-page.tsx +++ b/src/pages/additional-service/fund-account/transfer-list-page.tsx @@ -1,20 +1,24 @@ import { useState } from 'react'; import { PATHS } from '@/shared/constants/paths'; import { useNavigate } from '@/shared/lib/hooks/use-navigate'; -import { FundAccountTab } from '@/entities/additional-service/ui/fund-account/tab'; +import { FundAccountTab } from '@/entities/additional-service/ui/fund-account/tab'; import { FundAccountTransferListWrap } from '@/entities/additional-service/ui/fund-account/transfer-list-wrap'; import { FundAccountTabKeys } from '@/entities/additional-service/model/fund-account/types'; import { HeaderType } from '@/entities/common/model/types'; -import { - useSetHeaderTitle, - useSetHeaderType, - useSetFooterMode, +import { + useSetHeaderTitle, + useSetHeaderType, + useSetFooterMode, useSetOnBack } from '@/widgets/sub-layout/use-sub-layout'; +import { useExtensionAccessCheck } from '@/shared/lib/hooks/use-extension-access-check'; export const FundAccountTransferListPage = () => { const { navigate } = useNavigate(); - + // 권한 체크 + const { hasAccess, AccessDeniedDialog } = useExtensionAccessCheck({ + extensionCode: 'FUND_ACCOUNT' + }); const [activeTab, setActiveTab] = useState(FundAccountTabKeys.TransferList); useSetHeaderTitle('자금이체'); @@ -24,12 +28,16 @@ export const FundAccountTransferListPage = () => { navigate(PATHS.home); }); + if (!hasAccess) { + return ; + } + return ( <>
    - +
    diff --git a/src/pages/additional-service/fund-account/transfer-request-page.tsx b/src/pages/additional-service/fund-account/transfer-request-page.tsx index d4f359b..2948874 100644 --- a/src/pages/additional-service/fund-account/transfer-request-page.tsx +++ b/src/pages/additional-service/fund-account/transfer-request-page.tsx @@ -138,7 +138,7 @@ export const FundAccountTransferRequestPage = () => { setAccountName(e.target.value)} + onChange={(e: ChangeEvent) => setAccountName(e.target.value) } /> @@ -159,7 +159,7 @@ export const FundAccountTransferRequestPage = () => { setMoid(e.target.value)} + onChange={(e: ChangeEvent) => setMoid(e.target.value)} /> 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 b5e2040..c507392 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 @@ -22,11 +22,17 @@ import { useStore } from '@/shared/model/store'; import { KeyInPaymentListItem, KeyInPaymentPaymentStatus } 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'; export const KeyInPaymentPage = () => { const { navigate } = useNavigate(); const userMid = useStore.getState().UserStore.mid; + // 권한 체크 + const { hasAccess, AccessDeniedDialog } = useExtensionAccessCheck({ + extensionCode: 'KEYIN' + }); + const [sortType, setSortType] = useState(SortTypeKeys.LATEST); const [listItems, setListItems] = useState>([]); const [filterOn, setFilterOn] = useState(false); @@ -136,6 +142,11 @@ export const KeyInPaymentPage = () => { maxAmount ]); + // if (!hasAccess) { + // return ; + // } + + return ( <>
    diff --git a/src/pages/additional-service/link-payment/link-payment-history-page.tsx b/src/pages/additional-service/link-payment/link-payment-history-page.tsx index 7fc156c..42c3446 100644 --- a/src/pages/additional-service/link-payment/link-payment-history-page.tsx +++ b/src/pages/additional-service/link-payment/link-payment-history-page.tsx @@ -12,6 +12,7 @@ import { useSetOnBack } from '@/widgets/sub-layout/use-sub-layout'; import { LinkPaymentTabKeys } from '@/entities/additional-service/model/link-pay/types'; +import { useExtensionAccessCheck } from '@/shared/lib/hooks/use-extension-access-check'; /** * 발송내역 탭 화면 @@ -20,6 +21,11 @@ import { LinkPaymentTabKeys } from '@/entities/additional-service/model/link-pay export const LinkPaymentHistoryPage = () => { const { navigate } = useNavigate(); + // 권한 체크 + const { hasAccess, AccessDeniedDialog } = useExtensionAccessCheck({ + extensionCode: 'LINKPAY' + }); + const [activeTab, setActiveTab] = useState(LinkPaymentTabKeys.ShippingHistory) useSetHeaderTitle('링크결제') @@ -29,6 +35,10 @@ export const LinkPaymentHistoryPage = () => { navigate(PATHS.home); }); + if (!hasAccess) { + return ; + } + return ( <>
    diff --git a/src/pages/additional-service/link-payment/link-payment-wait-detail-page.tsx b/src/pages/additional-service/link-payment/link-payment-wait-detail-page.tsx index 4cc5de1..832b2c8 100644 --- a/src/pages/additional-service/link-payment/link-payment-wait-detail-page.tsx +++ b/src/pages/additional-service/link-payment/link-payment-wait-detail-page.tsx @@ -16,7 +16,8 @@ import { AdditionalServiceCategory, DetailResponse, PaymentInfo, TitleInfo } fro import { useExtensionLinkPayWaitDetailMutation, } from '@/entities/additional-service/api/link-payment/use-extension-link-pay-wait-detail-mutation'; import { PaymentInfoWrap } from '@/entities/additional-service/ui/info-wrap/payment-info-wrap'; import { useExtensionLinkPayWaitDeleteMutation } from '@/entities/additional-service/api/link-payment/use-extension-link-pay-wait-delete-mutation'; -import { ExtensionLinkPayWaitDeleteParams, ExtensionLinkPayWaitDetailParams } from '@/entities/additional-service/model/link-pay/types'; +import { ExtensionLinkPayWaitDeleteParams, ExtensionLinkPayWaitDetailParams, LinkPaymentProcessStatus } from '@/entities/additional-service/model/link-pay/types'; +import { snackBar } from '@/shared/lib'; export const LinkPaymentWaitDetailPage = () => { const { navigate } = useNavigate(); @@ -54,13 +55,13 @@ export const LinkPaymentWaitDetailPage = () => { requestId: requestId } linkPayWaitDelete(deleteParam) - .then((response) => { - console.log("Delete 성공 응답: ", response) + .then((rs) => { onClickToNavigate(PATHS.additionalService.linkPayment.pendingSend) + snackBar("삭제를 성공하였습니다.") }) .catch((error) => { console.error("Resend 실패: ", error); - + snackBar(`[실패] ${error?.response?.data?.message}`) }); } @@ -120,6 +121,7 @@ export const LinkPaymentWaitDetailPage = () => { diff --git a/src/pages/additional-service/list-page.tsx b/src/pages/additional-service/list-page.tsx index 4739273..ea46f98 100644 --- a/src/pages/additional-service/list-page.tsx +++ b/src/pages/additional-service/list-page.tsx @@ -2,16 +2,16 @@ import { ChangeEvent, useEffect, useState } from 'react'; import { PATHS } from '@/shared/constants/paths'; import { useNavigate } from '@/shared/lib/hooks/use-navigate'; import { HeaderType } from '@/entities/common/model/types'; -import { IMAGE_ROOT } from '@/shared/constants/common'; -import { - useSetHeaderTitle, - useSetHeaderType, - useSetFooterMode, +import { + useSetHeaderTitle, + useSetHeaderType, + useSetFooterMode, useSetOnBack } from '@/widgets/sub-layout/use-sub-layout'; import { useExtensionListMutation } from '@/entities/additional-service/api/use-extension-list-mutation'; -import { ExtensionListParams, ExtensionListResponse } from '@/entities/additional-service/model/types'; +import { ExtensionListParams, ExtensionListResponse, SERVICE_MAP } from '@/entities/additional-service/model/types'; import { useStore } from '@/shared/model/store'; +import { Dialog } from '@/shared/ui/dialogs/dialog'; export const ListPage = () => { const { navigate } = useNavigate(); @@ -19,6 +19,9 @@ export const ListPage = () => { const userMid = useStore.getState().UserStore.mid; const [mid, setMid] = useState(userMid); + const [activeServices, setActiveServices] = useState([]); + const [availableServices, setAvailableServices] = useState([]); + const [dialogOpen, setDialogOpen] = useState(false); const { mutateAsync: extensionList } = useExtensionListMutation(); @@ -34,112 +37,63 @@ export const ListPage = () => { mid: mid } extensionList(params).then((rs: ExtensionListResponse) => { - console.log(rs) + setActiveServices(rs.activeExtensionList || []); + setAvailableServices(rs.availableExtensionList || []); }); }; - const activeExtensionList = [ - { - className: 'list-wrap01', serviceName: 'SMS 결제 통보', serviceDesc: '입금 요청부터 완료까지 SMS 자동 전송', - icon: IMAGE_ROOT + '/icon_ing03.svg', path: PATHS.additionalService.smsPaymentNotification - }, - { - className: 'list-wrap01', serviceName: '신용카드 ARS 결제', serviceDesc: '전화 한 통으로 결제 성공 편리하고 안전한 서비스', - icon: IMAGE_ROOT + '/icon_ing01.svg', path: PATHS.additionalService.ars.list - }, - { - className: 'list-wrap01', serviceName: 'KEY-IN 결제', serviceDesc: '상담 중 카드정보 입력으로 간편한 결제 지원', - icon: IMAGE_ROOT + '/icon_ing02.svg', path: PATHS.additionalService.keyInPayment.list - }, - { - className: 'list-wrap01', serviceName: '계좌성명조회', serviceDesc: '예금주 정보 입력으로 즉시 예금주 확인', - icon: IMAGE_ROOT + '/icon_ing04.svg', path: PATHS.additionalService.accountHolderSearch.list - }, - ]; - const availableExtensionList = [ - { - className: 'list-wrap02', serviceName: '지급대행', serviceDesc: '하위 가맹점에 빠른 정산금 지급 지급대행 서비스', - icon: IMAGE_ROOT + '/icon_ing05.svg', path: PATHS.additionalService.payout.list - }, - { - className: 'list-wrap02', serviceName: '정산대행', serviceDesc: '하위 가맹점 정산금 계산부터 지급까지 자동 해결 서비스', - icon: IMAGE_ROOT + '/icon_ing06.svg', path: PATHS.additionalService.settlementAgency.manage - }, - { - className: 'list-wrap02', serviceName: '링크 결제', serviceDesc: '결제 링크 전송만으로 어디서든 결제 가능 서비스', - icon: IMAGE_ROOT + '/icon_ing07.svg', path: PATHS.additionalService.linkPayment.shippingHistory - }, - { - className: 'list-wrap02', serviceName: '자금이체', serviceDesc: '예치금으로 즉시 송금, 파일 등록만으로 다중 송금 가능', - icon: IMAGE_ROOT + '/icon_ing08.svg', path: PATHS.additionalService.fundAccount.transferList - }, - { - className: 'list-wrap02', serviceName: '계좌점유인증', serviceDesc: '1원 송금으로 실제 계좌 점유 확인 여부', - icon: IMAGE_ROOT + '/icon_ing09.svg', path: PATHS.additionalService.accountHolderAuth.list - }, - { - className: 'list-wrap02', serviceName: '알림톡 결제통보', serviceDesc: '결제 상태를 알림톡으로 쉽고 빠른 안내', - icon: IMAGE_ROOT + '/icon_ing10.svg', path: PATHS.additionalService.alimtalk.list - }, - ]; - - const onClickToNavigate = (path?: string) => { - if(!!path){ - navigate(path); - } - }; - const getActiveExtensionList = () => { - let rs = []; - for(let i=0;i onClickToNavigate(activeExtensionList[i]?.path) } - > -
    -
    { activeExtensionList[i]?.serviceName }
    -

    { activeExtensionList[i]?.serviceDesc }

    -
    - { + const filteredServices = SERVICE_MAP.filter(service => + activeServices.includes(service.code) + ); + + return filteredServices.map((service) => ( +
    service.path && navigate(service.path)} + > +
    +
    {service.serviceName}
    +

    {service.serviceDesc}

    - ); - } - return rs; + {service.serviceName} +
    + )); }; + const getAvailableExtensionList = () => { - let rs = []; - for(let i=0;i onClickToNavigate(availableExtensionList[i]?.path) } - > -
    -
    { availableExtensionList[i]?.serviceName }
    -

    { availableExtensionList[i]?.serviceDesc }

    -
    - { + const filteredServices = SERVICE_MAP.filter(service => + availableServices.includes(service.code) + ); + + return filteredServices.map((service) => ( +
    setDialogOpen(true)} + > +
    +
    {service.serviceName}
    +

    {service.serviceDesc}

    - ); - } - return rs; + {service.serviceName} +
    + )); }; useEffect(() => { - if(!!mid){ + if (!!mid) { callExtensionList(); } }, [mid]); - + return ( <>
    @@ -147,28 +101,41 @@ export const ListPage = () => {
    - +

    사용중인 서비스

    - { getActiveExtensionList() } + {getActiveExtensionList()}

    신청 가능한 서비스

    - { getAvailableExtensionList() } + {getAvailableExtensionList()}
    + setDialogOpen(false)} + message={ + <> + 이용 중이지 않은 서비스입니다.
    + 가입 문의는 영업 담당자 또는 고객센터로 문의해 주세요. + + } + buttonLabel={['확인']} + onConfirmClick={() => setDialogOpen(false)} + afterLeave={() => { }} + /> ) }; \ No newline at end of file diff --git a/src/pages/additional-service/payout/detail-page.tsx b/src/pages/additional-service/payout/detail-page.tsx index 89f6594..c6927ac 100644 --- a/src/pages/additional-service/payout/detail-page.tsx +++ b/src/pages/additional-service/payout/detail-page.tsx @@ -13,6 +13,9 @@ import { ExtensionPayoutDetailDownloadCertificateParams, ExtensionPayoutDetailDo import { useEffect, useState } from 'react'; import { NumericFormat } from 'react-number-format'; import { useExtensionPayoutDetailDownloadCertificateMutation } from '@/entities/additional-service/api/payout/use-extension-payout-detail-download-cetificate-mutation'; +import moment from 'moment'; +import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet'; +import { DownloadTypeBottomSheet } from '@/entities/common/ui/download-type-bottom-sheet'; export const PayoutDetailPage = () => { const { navigate } = useNavigate(); @@ -21,9 +24,9 @@ export const PayoutDetailPage = () => { const tid = location.state.tid; const mid = location.state.mid; - const [requestType, setRequestType] = useState(''); - const [email, setEmail] = useState(''); const [detail, setDetail] = useState(); + const [downloadTypeBottomSheetOn, setDownloadTypeBottomSheetOn] = useState(false); + const [emailBottomSheetOn, setEmailBottomSheetOn] = useState(false); const { mutateAsync: extensionPayoutDetail } = useExtensionPayoutDetailMutation(); const { mutateAsync: extensionPayoutDetailDownloadCertification } = useExtensionPayoutDetailDownloadCertificateMutation(); @@ -47,15 +50,48 @@ export const PayoutDetailPage = () => { }); const onClickToDownload = () => { - let params: ExtensionPayoutDetailDownloadCertificateParams = { - tid: tid, - mid: mid, - requestType: requestType, - email: email - }; - extensionPayoutDetailDownloadCertification(params).then((rs: ExtensionPayoutDetailDownloadCertificateResponse) => { - console.log(rs); - }); + setDownloadTypeBottomSheetOn(true); + }; + + const onSelectDownloadType = (type: 'IMAGE' | 'EMAIL') => { + if (type === 'IMAGE') { + // 이미지 저장은 바로 실행 + const params: ExtensionPayoutDetailDownloadCertificateParams = { + mid: mid, + tid: tid, + requestType: 'IMAGE', + email: '' + }; + extensionPayoutDetailDownloadCertification(params) + .then((rs: ExtensionPayoutDetailDownloadCertificateResponse) => { + console.log('Certificate Download Status:', rs); + }) + .catch((error) => { + console.error('Certificate Download Failed:', error); + }); + } else { + // 이메일은 EmailBottomSheet 열기 + setEmailBottomSheetOn(true); + } + }; + + const onSendRequest = (selectedEmail?: string) => { + if (selectedEmail) { + const params: ExtensionPayoutDetailDownloadCertificateParams = { + mid: mid, + tid: tid, + requestType: 'EMAIL', + email: selectedEmail + }; + extensionPayoutDetailDownloadCertification(params) + .then((rs: ExtensionPayoutDetailDownloadCertificateResponse) => { + console.log('Certificate Download Status:', rs); + }) + .catch((error) => { + console.error('Certificate Download Failed:', error); + }); + } + setEmailBottomSheetOn(false); }; useEffect(() => { @@ -105,11 +141,11 @@ export const PayoutDetailPage = () => {
  • 요청일 - { detail?.requestDate } + { moment(detail?.requestDate).format('YYYY.MM.DD') }
  • 지급일시 - { detail?.settlementDateTime } + {moment(detail?.settlementDateTime,'YYYYMMDDHHmmss').format('YYYY.MM.DD HH:mm:ss')}
  • 사업자번호 @@ -140,6 +176,18 @@ export const PayoutDetailPage = () => { + + ); }; \ No newline at end of file diff --git a/src/pages/additional-service/payout/list-page.tsx b/src/pages/additional-service/payout/list-page.tsx index 11f1343..7a0e8d9 100644 --- a/src/pages/additional-service/payout/list-page.tsx +++ b/src/pages/additional-service/payout/list-page.tsx @@ -15,9 +15,9 @@ import { import { JSX, useEffect, useState } from 'react'; import { DEFAULT_PAGE_PARAM } from '@/entities/common/model/constant'; import { - useSetHeaderTitle, - useSetHeaderType, - useSetFooterMode, + useSetHeaderTitle, + useSetHeaderType, + useSetFooterMode, useSetOnBack } from '@/widgets/sub-layout/use-sub-layout'; import moment from 'moment'; @@ -29,8 +29,13 @@ import { ListDateGroup } from '@/entities/additional-service/ui/list-date-group' import { AdditionalServiceCategory } from '@/entities/additional-service/model/types'; import { useStore } from '@/shared/model/store'; import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet'; +import { useExtensionAccessCheck } from '@/shared/lib/hooks/use-extension-access-check'; export const PayoutListPage = () => { + // 권한 체크 + const { hasAccess, AccessDeniedDialog } = useExtensionAccessCheck({ + extensionCode: 'PAYOUT' + }); const { navigate } = useNavigate(); const userMid = useStore.getState().UserStore.mid; @@ -44,12 +49,12 @@ export const PayoutListPage = () => { const [toDate, setToDate] = useState(moment().format('YYYYMMDD')); const [status, setStatus] = useState(PayoutDisbursementStatus.ALL); const [minAmount, setMinAmount] = useState(0); - const [maxAmount, setMaxAmount] = useState(50000000); + const [maxAmount, setMaxAmount] = useState(50000000); const [emailBottomSheetOn, setEmailBottomSheetOn] = useState(false); const { mutateAsync: extensionPayoutList } = useExtensionPayoutListMutation(); const { mutateAsync: extensionPayoutExcel } = useExtensionPayoutExcelMutation(); - + useSetHeaderTitle('지급대행'); useSetHeaderType(HeaderType.LeftArrow); useSetFooterMode(false); @@ -65,26 +70,19 @@ export const PayoutListPage = () => { sortType?: SortTypeKeys, status?: PayoutDisbursementStatus }) => { - let newMinAmount = minAmount; - if(!!minAmount && typeof(minAmount) === 'string'){ - newMinAmount = parseInt(minAmount); - } - let newMaxAmount = maxAmount; - if(!!maxAmount && typeof(maxAmount) === 'string'){ - newMaxAmount = parseInt(maxAmount); - } + let params: ExtensionPayoutListParams = { mid: mid, searchDateType: searchDateType, fromDate: fromDate, toDate: toDate, status: option?.status ?? status, - minAmount: newMinAmount, - maxAmount: newMaxAmount, + minAmount: minAmount, + maxAmount: maxAmount, page: pageParam }; - if(params.page){ + if (params.page) { params.page.sortType = option?.sortType || sortType; setPageParam(params.page); } @@ -102,13 +100,9 @@ export const PayoutListPage = () => { if (selectedEmail) { const params: ExtensionPayoutExcelParams = { mid: mid, - searchDateType: searchDateType, + email: selectedEmail, fromDate: fromDate, toDate: toDate, - status: status, - minAmount: minAmount, - maxAmount: maxAmount, - //email: selectedEmail }; extensionPayoutExcel(params).then((rs: ExtensionPayoutExcelResponse) => { console.log('Excel Download Status:', rs); @@ -127,9 +121,6 @@ export const PayoutListPage = () => { }; const onClickToDisbursementStatus = (val: PayoutDisbursementStatus) => { setStatus(val); - callExtensionPayoutList({ - status: val - }); }; useEffect(() => { @@ -145,9 +136,9 @@ export const PayoutListPage = () => { ]); const getListDateGroup = () => { - let rs= []; + let rs = []; let date = ''; - let list= []; + let list = []; for (let i = 0; i < listItems.length; i++) { let itemDateStr = ''; if (searchDateType === PayoutSearchDateType.REQUEST_DATE) { @@ -190,6 +181,10 @@ export const PayoutListPage = () => { return rs; }; + if (!hasAccess) { + return ; + } + return ( <>
    @@ -198,19 +193,19 @@ export const PayoutListPage = () => {
    - - @@ -218,10 +213,10 @@ export const PayoutListPage = () => { @@ -240,52 +235,52 @@ export const PayoutListPage = () => {
    - { - PayoutDisbursementStatusBtnGroup.map((value, index) => ( - onClickToDisbursementStatus(value.value) } - >{ value.name } - )) - } + { + PayoutDisbursementStatusBtnGroup.map((value, index) => ( + onClickToDisbursementStatus(value.value)} + >{value.name} + )) + }
    - { getListDateGroup() } + {getListDateGroup()}
    { const { navigate } = useNavigate(); @@ -41,9 +43,14 @@ export const PayoutRequestPage = () => { disbursementAmount: disbursementAmount, settlementDate: settlementDate, }; - extensionPayoutRequest(params).then((rs: ExtensionPayoutRequestResponse) => { - navigate(PATHS.additionalService.payout.list); - }); + extensionPayoutRequest(params) + .then((rs) => { + snackBar("신청을 성공하였습니다.") + }) + .catch((error) => { + snackBar(`[실패] ${error?.response?.data?.message} `|| '[실패] 신청을 실패하였습니다.') + }) + ; }; const isFormValid = () => { @@ -58,9 +65,8 @@ export const PayoutRequestPage = () => { setSettlementDate(moment(date).format('YYYYMMDD')); setCalendarOpen(false); }; - const onClickToOpenCalendar = () => { - setCalendarOpen(true); - }; + + return ( <>
    @@ -69,44 +75,44 @@ export const PayoutRequestPage = () => {
    -
    서브ID*
    +
    서브ID
    setSubmallId(e.target.value)} + onChange={(e: ChangeEvent) => setSubmallId(e.target.value)} />
    -
    지급액*
    +
    지급액
    - setDisbursementAmount(parseInt(e.target.value))} - /> + allowNegative={false} + displayType="input" + onChange={(e: ChangeEvent) => setDisbursementAmount(parseInt(e.target.value))} + >
    -
    지급일*
    +
    지급일
    -
    +
    @@ -129,6 +135,7 @@ export const PayoutRequestPage = () => { setCalendarOpen={setCalendarOpen} calendarType={CalendarType.Single} setNewDate={setNewDate} + minDate={new Date()} > ); diff --git a/src/pages/additional-service/sms-payment/sms-payment-page.tsx b/src/pages/additional-service/sms-payment/sms-payment-page.tsx index 3fd83a8..844748d 100644 --- a/src/pages/additional-service/sms-payment/sms-payment-page.tsx +++ b/src/pages/additional-service/sms-payment/sms-payment-page.tsx @@ -21,12 +21,17 @@ import { useStore } from '@/shared/model/store'; import { AdditionalServiceCategory } from '@/entities/additional-service/model/types'; import { PATHS } from '@/shared/constants/paths'; import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet'; - +import { useExtensionAccessCheck } from '@/shared/lib/hooks/use-extension-access-check'; export const SmsPaymentPage = () => { const { navigate } = useNavigate(); const userMid = useStore.getState().UserStore.mid; + // 권한 체크 + const { hasAccess, AccessDeniedDialog } = useExtensionAccessCheck({ + extensionCode: 'SMS' + }); + const [bottomSmsPaymentDetailResendOn, setBottomSmsPaymentDetailResendOn] = useState(false) const [sortType, setSortType] = useState(SortTypeKeys.LATEST); @@ -131,6 +136,10 @@ export const SmsPaymentPage = () => { smsCl ]); + // if (!hasAccess) { + // return ; + // } + return ( <>
    diff --git a/src/shared/api/api-url-additional-service.ts b/src/shared/api/api-url-additional-service.ts index 78f6a28..b73da17 100644 --- a/src/shared/api/api-url-additional-service.ts +++ b/src/shared/api/api-url-additional-service.ts @@ -11,7 +11,7 @@ export const API_URL_ADDITIONAL_SERVICE = { }, extensionAccountHolderAuthDownlaodExcel: () => { // POST: 계좌점유인증 엑셀 다운 - return `${API_BASE_URL}/api/v1/${API_URL_KEY}/extension/account-auth/excel`; + return `${API_BASE_URL}/api/v1/${API_URL_KEY}/extension/account-auth/download/excel`; }, extensionAccountHolderAuthDetail: () => { // POST: 계좌점유인증 상세 조회 @@ -97,6 +97,10 @@ export const API_URL_ADDITIONAL_SERVICE = { // POST: 부가서비스 조회 return `${API_BASE_URL}/api/v1/${API_URL_KEY}/extension/list`; }, + extensionCheck: () => { + // POST: 부가서비스 사용여부 체크 + return `${API_BASE_URL}/api/v1/${API_URL_KEY}/extension/check`; + }, extensionKeyinList: () => { // POST: KEY-IN 결제 목록 조회 return `${API_BASE_URL}/api/v1/${API_URL_KEY}/extension/keyin/list`; diff --git a/src/shared/lib/hooks/use-extension-access-check.tsx b/src/shared/lib/hooks/use-extension-access-check.tsx new file mode 100644 index 0000000..42519a1 --- /dev/null +++ b/src/shared/lib/hooks/use-extension-access-check.tsx @@ -0,0 +1,97 @@ +import { useEffect, useState } from 'react'; +import { useNavigate } from '@/shared/lib/hooks/use-navigate'; +import { useExtensionCheckMutation } from '@/entities/additional-service/api/use-extension-check-mutation'; +import { Dialog } from '@/shared/ui/dialogs/dialog'; +import { PATHS } from '@/shared/constants/paths'; + +interface UseExtensionAccessCheckProps { + extensionCode: string; + enabled?: boolean; +} + +interface UseExtensionAccessCheckReturn { + hasAccess: boolean | null; + AccessDeniedDialog: () => React.ReactElement | null; +} + +/** + * 부가서비스 접근 권한을 체크하는 훅 + * 페이지 마운트 시 extensionCheck API를 호출하여 권한을 확인하고, + * 권한이 없으면 다이얼로그를 표시한 후 이전 페이지로 이동합니다. + */ +export const useExtensionAccessCheck = ({ + extensionCode, + enabled = true +}: UseExtensionAccessCheckProps): UseExtensionAccessCheckReturn => { + const { navigate } = useNavigate(); + const { mutateAsync: extensionCheck } = useExtensionCheckMutation(); + + const [hasAccess, setHasAccess] = useState(null); + const [isChecking, setIsChecking] = useState(true); + const [dialogOpen, setDialogOpen] = useState(false); + + useEffect(() => { + if (!enabled) { + setIsChecking(false); + setHasAccess(true); + return; + } + + const checkAccess = async () => { + try { + setIsChecking(true); + const result = await extensionCheck({ extensionCode }); + + if (result.checkResult === true) { + // 권한 체크 통과 + setHasAccess(true); + } else { + // 권한 체크 실패 - 다이얼로그 표시 + setHasAccess(false); + setDialogOpen(true); + } + } catch (error) { + console.error('Extension access check error:', error); + // 에러 발생 시에도 다이얼로그 표시 + setHasAccess(false); + setDialogOpen(true); + } finally { + setIsChecking(false); + } + }; + + checkAccess(); + }, [extensionCode, enabled]); + + const handleConfirm = () => { + + setDialogOpen(false); + + setTimeout(() => { + navigate(PATHS.additionalService.list); + }, 0); + }; + + const AccessDeniedDialog = () => { + return ( + {}} + message={ + <> + 이용 중이지 않은 서비스입니다.
    + 가입 문의는 영업 담당자 또는 고객센터로 문의해 주세요. + + } + buttonLabel={['확인']} + onConfirmClick={handleConfirm} + afterLeave={() => {}} + /> + ); + }; + + return { + hasAccess, + AccessDeniedDialog, + }; +}; diff --git a/src/shared/ui/dialogs/dialog.tsx b/src/shared/ui/dialogs/dialog.tsx index ba6aed8..ca2c66f 100644 --- a/src/shared/ui/dialogs/dialog.tsx +++ b/src/shared/ui/dialogs/dialog.tsx @@ -36,7 +36,7 @@ export const Dialog = ({ const { nativeDialog, resetNativeDialog } = useBridge(bridge.store, (state) => state); const whenToBlock = useCallback(() => open, [open]); - // 다이얼로그가 열려있을때 뒤로가기 방지 + const blocker = useBlocker(whenToBlock); const nativeMessage = nativeDialog?.message; const displayMessage = nativeMessage || message; @@ -68,7 +68,6 @@ export const Dialog = ({ leaveTo="opacity-0" > <_Dialog onClose={shouldCloseOnBackdropClick ? onClose : () => null} static={!shouldCloseOnBackdropClick}> - {/* The backdrop, rendered as a fixed sibling to the panel container */}