This commit is contained in:
focp212@naver.com
2025-10-23 11:08:11 +09:00
48 changed files with 1070 additions and 1310 deletions

View File

@@ -111,7 +111,7 @@ export const UserAccountAuthWrap = ({
] ]
return ( return (
<> <>
<div className="ing-list pdtop"> <div className="ing-list pdtop pb-86">
<div className="perm-form"> <div className="perm-form">
<div className="perm-field"> <div className="perm-field">
<div className="perm-label"> </div> <div className="perm-label"> </div>
@@ -144,7 +144,7 @@ export const UserAccountAuthWrap = ({
menuGrants={ permissions } menuGrants={ permissions }
></UserAccountAuthPermList> ></UserAccountAuthPermList>
<div className="apply-row bottom-padding"> <div className="apply-row">
<button <button
className="btn-50 btn-blue flex-1" className="btn-50 btn-blue flex-1"
type="button" type="button"

View File

@@ -5,6 +5,7 @@ import { useEffect, useState } from 'react';
import { useUserModifyAuthMethodMutation } from '@/entities/user/api/use-user-modify-authmethod-mutation'; import { useUserModifyAuthMethodMutation } from '@/entities/user/api/use-user-modify-authmethod-mutation';
import { PATHS } from '@/shared/constants/paths'; import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate'; import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { snackBar } from '@/shared/lib/toast';
export const UserLoginAuthInfoWrap = ({ export const UserLoginAuthInfoWrap = ({
mid, mid,
@@ -25,7 +26,7 @@ export const UserLoginAuthInfoWrap = ({
const { mutateAsync: userFindAuthMethod } = useUserFindAuthMethodMutation(); const { mutateAsync: userFindAuthMethod } = useUserFindAuthMethodMutation();
const { mutateAsync: userModifyAuthMethod } = useUserModifyAuthMethodMutation({ const { mutateAsync: userModifyAuthMethod } = useUserModifyAuthMethodMutation({
onSuccess: () => { onSuccess: () => {
// snackBar('사용자 정보가 성공적으로 저장되었습니다.'); snackBar('사용자 정보가 성공적으로 저장되었습니다.');
navigate(PATHS.account.user.manage, { navigate(PATHS.account.user.manage, {
state: { state: {
mid: mid, mid: mid,
@@ -33,7 +34,7 @@ export const UserLoginAuthInfoWrap = ({
}); });
}, },
onError: (error) => { onError: (error) => {
// snackBar(error?.response?.data?.message || '사용자 정보 저장에 실패했습니다.'); snackBar(error?.response?.data?.message || '사용자 정보 저장에 실패했습니다.');
} }
}); });
@@ -391,7 +392,7 @@ export const UserLoginAuthInfoWrap = ({
return ( return (
<> <>
<div className="ing-list pdtop"> <div className="ing-list pdtop">
<div className="settings-login-auth"> <div className="settings-login-auth pb-86">
<div className="group"> <div className="group">
<div className="group-header"> <div className="group-header">
<div className="title"> </div> <div className="title"> </div>
@@ -489,7 +490,7 @@ export const UserLoginAuthInfoWrap = ({
<div className="notice-bar"> .</div> <div className="notice-bar"> .</div>
</div> </div>
</div> </div>
<div className="apply-row bottom-padding"> <div className="apply-row">
<button <button
className="btn-50 btn-blue flex-1" className="btn-50 btn-blue flex-1"
disabled={!isSaveButtonEnabled()} disabled={!isSaveButtonEnabled()}

View File

@@ -41,7 +41,8 @@ export const UserManageWrap = () => {
return ( return (
<> <>
<div className="ing-list" style={{ display: 'flex', flexDirection: 'column', height: 'calc(100vh - 200px)' }}> {/* <div className="ing-list" style={{ display: 'flex', flexDirection: 'column', height: 'calc(100vh - 86px)' }}> */}
<div className="ing-list pb-86">
<div style={{ flexShrink: 0 }}> <div style={{ flexShrink: 0 }}>
<div className="input-wrapper top-select mt-16"> <div className="input-wrapper top-select mt-16">
<select <select

View File

@@ -0,0 +1,29 @@
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 {
ExtensionFundAccountDownloadReceiptParams as ExtensionFundAccountDownloadReceiptParams,
ExtensionFundAccountDownloadReceiptResponse as ExtensionFundAccountDownloadReceiptResponse
} from '../../model/fund-account/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const extensionFundAccountDownloadReceipt = (params: ExtensionFundAccountDownloadReceiptParams) => {
return resultify(
axios.post<ExtensionFundAccountDownloadReceiptResponse>(API_URL_ADDITIONAL_SERVICE.extensionFundAccountDownloadReceipt(), params),
);
};
export const useExtensionFundAccountDownloadReceiptMutation = (options?: UseMutationOptions<ExtensionFundAccountDownloadReceiptResponse, CBDCAxiosError, ExtensionFundAccountDownloadReceiptParams>) => {
const mutation = useMutation<ExtensionFundAccountDownloadReceiptResponse, CBDCAxiosError, ExtensionFundAccountDownloadReceiptParams>({
...options,
mutationFn: (params: ExtensionFundAccountDownloadReceiptParams) => extensionFundAccountDownloadReceipt(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,29 @@
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 {
ExtensionFundAccountTransferRegistParams,
ExtensionFundAccountTransferRegistResponse
} from '../../model/fund-account/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const extensionFundAccountTransferRegist = (params: ExtensionFundAccountTransferRegistParams) => {
return resultify(
axios.post<ExtensionFundAccountTransferRegistResponse>(API_URL_ADDITIONAL_SERVICE.extensionFundAccountTransferRegist(), params),
);
};
export const useExtensionFundAccountTransferRegistMutation = (options?: UseMutationOptions<ExtensionFundAccountTransferRegistResponse, CBDCAxiosError, ExtensionFundAccountTransferRegistParams>) => {
const mutation = useMutation<ExtensionFundAccountTransferRegistResponse, CBDCAxiosError, ExtensionFundAccountTransferRegistParams>({
...options,
mutationFn: (params: ExtensionFundAccountTransferRegistParams) => extensionFundAccountTransferRegist(params),
});
return {
...mutation,
};
};

View File

@@ -1,29 +0,0 @@
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 {
ExtensionFundAccountTransferRequestParams,
ExtensionFundAccountTransferRequestResponse
} from '../../model/fund-account/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const extensionFundAccountTransferRequest = (params: ExtensionFundAccountTransferRequestParams) => {
return resultify(
axios.post<ExtensionFundAccountTransferRequestResponse>(API_URL_ADDITIONAL_SERVICE.extensionFundAccountTransferRequest(), params),
);
};
export const useExtensionFundAccountTransferRequestMutation = (options?: UseMutationOptions<ExtensionFundAccountTransferRequestResponse, CBDCAxiosError, ExtensionFundAccountTransferRequestParams>) => {
const mutation = useMutation<ExtensionFundAccountTransferRequestResponse, CBDCAxiosError, ExtensionFundAccountTransferRequestParams>({
...options,
mutationFn: (params: ExtensionFundAccountTransferRequestParams) => extensionFundAccountTransferRequest(params),
});
return {
...mutation,
};
};

View File

@@ -1,5 +1,5 @@
import { DefaulResponsePagination, DefaultRequestPagination } from "@/entities/common/model/types"; import { DefaulResponsePagination, DefaultRequestPagination } from "@/entities/common/model/types";
import { ExtensionRequestParams, FilterProps, ListItemProps } from "../types"; import { AdditionalServiceCategory, ExtensionRequestParams, FilterProps, ListItemProps } from "../types";
// 계좌 점유 조회 관련 타입들 // 계좌 점유 조회 관련 타입들
export enum AuthAndTransferStatus { export enum AuthAndTransferStatus {
@@ -18,7 +18,8 @@ export interface AccountHolderAuthListItem {
transferStatus?: AuthAndTransferStatus; transferStatus?: AuthAndTransferStatus;
} }
export interface AccountHolderAuthListProps { export interface AccountHolderAuthListProps {
listItems: Record<string, Array<ListItemProps>>; additionalServiceCategory: AdditionalServiceCategory;
listItems: Array<ExtensionAccountHolderAuthContentItem>;
mid: string; mid: string;
} }
export interface AccountHolderAuthFilterProps extends FilterProps { export interface AccountHolderAuthFilterProps extends FilterProps {
@@ -34,7 +35,8 @@ export interface AccountHolderAuthFilterProps extends FilterProps {
// 계좌 점유 인증 확장 서비스 // 계좌 점유 인증 확장 서비스
// ======================================== // ========================================
export interface ExtensionAccountHolderAuthListParams extends ExtensionRequestParams { export interface ExtensionAccountHolderAuthListParams {
mid: string;
fromDate: string; fromDate: string;
toDate: string; toDate: string;
authStatus: string; authStatus: string;
@@ -42,7 +44,16 @@ export interface ExtensionAccountHolderAuthListParams extends ExtensionRequestPa
} }
export interface ExtensionAccountHolderAuthListResponse extends DefaulResponsePagination { export interface ExtensionAccountHolderAuthListResponse extends DefaulResponsePagination {
content: Array<ListItemProps> content: Array<ExtensionAccountHolderAuthContentItem>
}
export interface ExtensionAccountHolderAuthContentItem {
tid?: string;
accountName?: string;
accountNo?: string;
requestDate?: string;
bankName?: string;
authStatus?: AuthAndTransferStatus;
} }
export interface ExtensionAccountHolderAuthDownloadExcelParams extends ExtensionRequestParams { export interface ExtensionAccountHolderAuthDownloadExcelParams extends ExtensionRequestParams {

View File

@@ -24,7 +24,6 @@ export interface AccountHolderSearchListItem {
export interface AccountHolderSearchListProps { export interface AccountHolderSearchListProps {
listItems: Array<AccountHolderSearchListItem>; listItems: Array<AccountHolderSearchListItem>;
mid: string; mid: string;
setTarget: (element: HTMLElement | null) => void;
} }
export interface AccountHolderSearchFilterProps extends FilterProps { export interface AccountHolderSearchFilterProps extends FilterProps {

View File

@@ -0,0 +1,42 @@
import { AlimtalkAlimCl, AlimtalkSearchCl, AlimTalkSendCl, AlimtalkSendType, ServiceCode } from "./types";
export const AlimtalkSearchClOptionGroup = [
{name: '주문자', value: AlimtalkSearchCl.BUYER_NAME },
{name: 'TID', value: AlimtalkSearchCl.TID },
];
export const AlimtalkServiceCodeOptionGroup = [
{name: '전체', value: ''},
{name: '카드', value: ServiceCode.CARD },
{name: '계좌이체', value: ServiceCode.BANK },
{name: '가상계좌', value: ServiceCode.VBANK },
{name: '휴대폰', value: ServiceCode.PHONE }
]
// 알림구분 - 카드/계좌이체/휴대폰용
export const AlimtalkAlimClBtnGroupForGeneral = [
{name: '전체', value: '' },
{name: '승인', value: AlimtalkAlimCl.APPROVAL },
{name: '취소', value: AlimtalkAlimCl.CANCEL }
]
// 알림구분 - 가상계좌용
export const AlimtalkAlimClBtnGroupForVBank = [
{name: '전체', value: '' },
{name: '입금요청', value: AlimtalkAlimCl.DEPOSIT_REQUEST },
{name: '입금완료', value: AlimtalkAlimCl.DEPOSIT_COMPLETE },
{name: '환불', value: AlimtalkAlimCl.REFUND }
]
export const AlimtalkSendTypeBtnGroup = [
{name: '전체', value: AlimtalkSendType.ALL },
{name: '카카오톡', value: AlimtalkSendType.KAKAOTALK },
{name: 'FB SMS', value: AlimtalkSendType.FB_SMS }
]
export const AlimtalkSendClBtnGroup = [
{name: '전체', value: AlimTalkSendCl.ALL },
{name: '요청', value: AlimTalkSendCl.REQUEST },
{name: '성공', value: AlimTalkSendCl.SUCCESS },
{name: '실패', value: AlimTalkSendCl.FAIL }
]

View File

@@ -31,6 +31,14 @@ export enum AlimTalkSendCl {
SUCCESS = 'SUCCESS', SUCCESS = 'SUCCESS',
FAIL = 'FAIL' FAIL = 'FAIL'
}; };
export enum ServiceCode {
CARD = 'CARD',
BANK = 'BANK',
VBANK = 'VBANK',
PHONE = 'PHONE'
}
export interface ExtensionAlimtalkSettingSaveParams { export interface ExtensionAlimtalkSettingSaveParams {
mid: string; mid: string;
sendMerchantInfo?: SendMerchantInfo; sendMerchantInfo?: SendMerchantInfo;
@@ -97,7 +105,7 @@ export interface ExtensionAlimtalkDownloadExcelParams {
mid?: string; mid?: string;
searchCl?: AlimtalkSearchCl; searchCl?: AlimtalkSearchCl;
searchValue?: string; searchValue?: string;
paymentMethod?: string; serviceCode?: string;
alimCl?: AlimtalkAlimCl; alimCl?: AlimtalkAlimCl;
fromDate?: string; fromDate?: string;
toDate?: string; toDate?: string;
@@ -105,7 +113,9 @@ export interface ExtensionAlimtalkDownloadExcelParams {
sendCl?: AlimTalkSendCl; sendCl?: AlimTalkSendCl;
}; };
export interface ExtensionAlimtalkDownloadExcelResponse {}; export interface ExtensionAlimtalkDownloadExcelResponse {
status : boolean
};
export interface ExtensionAlimtalkDetailParams { export interface ExtensionAlimtalkDetailParams {
mid: string; mid: string;

View File

@@ -20,8 +20,7 @@ export enum FundAccountReceiveAccountNameNo {
ReceiveAccountName = 'ReceiveAccountName' ReceiveAccountName = 'ReceiveAccountName'
}; };
export interface ExtensionFundAccountTransferRegistParams {
export interface ExtensionFundAccountTransferRequestParams {
mid?: string; mid?: string;
bankCode: string; bankCode: string;
accountNo: string; accountNo: string;
@@ -30,10 +29,19 @@ export interface ExtensionFundAccountTransferRequestParams {
moid: string; moid: string;
depositParameter?: string; depositParameter?: string;
}; };
export interface ExtensionFundAccountTransferRequestResponse {
export interface ExtensionFundAccountTransferRegistResponse {
status: boolean; status: boolean;
}; };
export interface ExtensionFundAccountTransferRequestParams {
}
export interface ExtensionFundAccountTransferRequestResponse {
}
export enum FundAccountSearchCl { export enum FundAccountSearchCl {
ACCOUNT_NAME = 'ACCOUNT_NAME', ACCOUNT_NAME = 'ACCOUNT_NAME',
ACCOUNT_NO = 'ACCOUNT_NO' ACCOUNT_NO = 'ACCOUNT_NO'
@@ -94,8 +102,7 @@ export interface ExtensionFundAccountTransferExcelResponse {
status: boolean; status: boolean;
}; };
export interface ExtensionFundAccountTransferDetailParams { export interface ExtensionFundAccountTransferDetailParams {
mid: string; seq: string;
tid: string;
}; };
export interface ExtensionFundAccountTransferDetailResponse { export interface ExtensionFundAccountTransferDetailResponse {
tid: string; tid: string;
@@ -177,7 +184,7 @@ export interface ExtensionFundAccountResultDetailResponse {
requsetDate: string; requsetDate: string;
resultMessage: string; resultMessage: string;
failReason: string; failReason: string;
bankCode: string; bankName: string;
}; };
export interface ExtensionFundAccountBalanceParams { export interface ExtensionFundAccountBalanceParams {
mid: string; mid: string;
@@ -187,11 +194,11 @@ export interface ExtensionFundAccountBalanceResponse {
}; };
// 입금확인증 다운로드 // 입금확인증 다운로드
export interface ExtensionFundAccountDownloadCertificateParams { export interface ExtensionFundAccountDownloadReceiptParams {
mid: string; mid: string;
tid: string; tid: string;
email: string; email: string;
}; };
export interface ExtensionFundAccountDownloadCertificateResponse { export interface ExtensionFundAccountDownloadReceiptResponse {
status: boolean; status: boolean;
}; };

View File

@@ -22,7 +22,6 @@ export interface KeyInPaymentListProps {
additionalServiceCategory: AdditionalServiceCategory; additionalServiceCategory: AdditionalServiceCategory;
listItems: Array<KeyInPaymentListItem>; listItems: Array<KeyInPaymentListItem>;
mid?: string; mid?: string;
setTarget: (element: HTMLElement | null) => void;
} }
export interface KeyInPaymentFilterProps extends FilterProps { export interface KeyInPaymentFilterProps extends FilterProps {

View File

@@ -103,14 +103,12 @@ export interface LinkPaymentWaitListItem {
export interface LinkPaymentHistoryListProps { export interface LinkPaymentHistoryListProps {
additionalServiceCategory: AdditionalServiceCategory; additionalServiceCategory: AdditionalServiceCategory;
listItems: Array<LinkPaymentHistoryListItem>; listItems: Array<LinkPaymentHistoryListItem>;
setTarget: (element: HTMLElement | null) => void;
mid: string; mid: string;
} }
export interface LinkPaymentWaitListProps { export interface LinkPaymentWaitListProps {
additionalServiceCategory: AdditionalServiceCategory; additionalServiceCategory: AdditionalServiceCategory;
listItems: Array<LinkPaymentWaitListItem>; listItems: Array<LinkPaymentWaitListItem>;
setTarget: (element: HTMLElement | null) => void;
mid: string; mid: string;
} }

View File

@@ -25,7 +25,6 @@ export interface SmsPaymentListProps {
additionalServiceCategory: AdditionalServiceCategory; additionalServiceCategory: AdditionalServiceCategory;
mid: string; mid: string;
onResendClick?: (mid: string, tid: string) => void; onResendClick?: (mid: string, tid: string) => void;
setTarget: (element: HTMLElement | null) => void;
} }
export interface SmsPaymentFilterProps extends FilterProps { export interface SmsPaymentFilterProps extends FilterProps {

View File

@@ -167,6 +167,7 @@ export interface ListItemProps extends
ArsListContent, AlimtalkListContent, FaceAuthListItem { ArsListContent, AlimtalkListContent, FaceAuthListItem {
additionalServiceCategory?: AdditionalServiceCategory; additionalServiceCategory?: AdditionalServiceCategory;
mid?: string; mid?: string;
seq?: string;
onResendClick?: (mid: string, tid: string) => void; onResendClick?: (mid: string, tid: string) => void;
} }

View File

@@ -1,24 +1,53 @@
import { ListDateGroup } from '../list-date-group'; import { ListDateGroup } from '../list-date-group';
import { AdditionalServiceCategory } from '../../model/types'; import { AdditionalServiceCategory } from '../../model/types';
import { AccountHolderAuthListProps } from '../../model/account-holder-auth/types'; import { AccountHolderAuthListProps, ExtensionAccountHolderAuthContentItem } from '../../model/account-holder-auth/types';
import { JSX } from 'react';
export const AccountHolderAuthList = ({ export const AccountHolderAuthList = ({
additionalServiceCategory,
listItems, listItems,
mid mid
}: AccountHolderAuthListProps) => { }: AccountHolderAuthListProps) => {
const getListDateGroup = () => { const getListDateGroup = () => {
let rs = []; let rs: JSX.Element[] = [];
for (const [key, value] of Object.entries(listItems)) { let date = '';
let list: ExtensionAccountHolderAuthContentItem[] = [];
for (let i = 0; i < listItems.length; i++) {
// sendDate(발송일자) 기준
let requestDate = listItems[i]?.requestDate || '';
let itemDate = requestDate.substring(0, 8);
if (i === 0) {
date = itemDate;
}
if (date !== itemDate) {
if (list.length > 0) {
rs.push( rs.push(
<ListDateGroup <ListDateGroup
additionalServiceCategory={AdditionalServiceCategory.AccountHolderAuth} additionalServiceCategory={additionalServiceCategory}
key={key} key={date + '-' + i}
date={key} date={date}
items={value} items={list as any}
mid={mid} mid={mid}
></ListDateGroup> ></ListDateGroup>
) );
}
date = itemDate;
list = [];
}
list.push(listItems[i] as any);
}
if (list.length > 0) {
rs.push(
<ListDateGroup
additionalServiceCategory={additionalServiceCategory}
key={date + '-last'}
date={date}
items={list as any}
mid={mid}
></ListDateGroup>
);
} }
return rs; return rs;
}; };

View File

@@ -7,8 +7,7 @@ import { JSX } from 'react';
export const AccountHolderSearchList = ({ export const AccountHolderSearchList = ({
listItems, listItems,
mid, mid
setTarget
}: AccountHolderSearchListProps) => { }: AccountHolderSearchListProps) => {
const { navigate } = useNavigate(); const { navigate } = useNavigate();
@@ -63,7 +62,6 @@ export const AccountHolderSearchList = ({
<> <>
<section className="transaction-list"> <section className="transaction-list">
{getListDateGroup()} {getListDateGroup()}
<div ref={setTarget}></div>
</section> </section>
<div className="apply-row"> <div className="apply-row">
<button <button

View File

@@ -1,4 +1,4 @@
import { useEffect, useState } from 'react'; import { useEffect, useState, useMemo } from 'react';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { IMAGE_ROOT } from '@/shared/constants/common'; import { IMAGE_ROOT } from '@/shared/constants/common';
import { FilterSelect } from '@/shared/ui/filter/select'; import { FilterSelect } from '@/shared/ui/filter/select';
@@ -11,93 +11,112 @@ import {
FilterMotionVariants FilterMotionVariants
} from '@/entities/common/model/constant'; } from '@/entities/common/model/constant';
import moment from 'moment'; import moment from 'moment';
import { FilterInput } from '@/shared/ui/filter/input';
import { OrderStatus, PaymentStatus } from '../../model/ars/types';
import { ArsOrderStatusBtnGroup, ArsPaymentStatusBtnGroup } from '../../model/ars/constant';
import { useStore } from '@/shared/model/store'; import { useStore } from '@/shared/model/store';
import { AlimtalkAlimCl, AlimtalkSearchCl, AlimTalkSendCl, AlimtalkSendType, ServiceCode } from '../../model/alimtalk/types';
import { FilterSelectInput } from '@/shared/ui/filter/select-input';
import { AlimtalkAlimClBtnGroupForGeneral, AlimtalkAlimClBtnGroupForVBank, AlimtalkSearchClOptionGroup, AlimtalkSendClBtnGroup, AlimtalkSendTypeBtnGroup, AlimtalkServiceCodeOptionGroup } from '../../model/alimtalk/constant';
export interface AlimtalkFilterProps { export interface AlimtalkFilterProps {
filterOn: boolean; filterOn: boolean;
setFilterOn: (filterOn: boolean) => void; setFilterOn: (filterOn: boolean) => void;
mid: string; mid: string;
moid: string; searchCl: AlimtalkSearchCl;
searchValue: string;
fromDate: string; fromDate: string;
toDate: string; toDate: string;
paymentStatus: PaymentStatus; serviceCode: ServiceCode;
orderStatus: OrderStatus; alimCl: AlimtalkAlimCl;
minAmount?: number; sendType: AlimtalkSendType;
maxAmount?: number; sendCl: AlimTalkSendCl;
setMid: (mid: string) => void; setMid: (mid: string) => void;
setMoid: (moid: string) => void; setSearchCl: (searchCl: AlimtalkSearchCl) => void;
setSearchValue: (searchValue: string) => void;
setFromDate: (fromDate: string) => void; setFromDate: (fromDate: string) => void;
setToDate: (toDate: string) => void; setToDate: (toDate: string) => void;
setPaymentStatus: (paymentStatus: PaymentStatus) => void; setServiceCode: (serviceCode: ServiceCode) => void;
setOrderStatus: (orderStatus: OrderStatus) => void; setAlimCl: (alimCl: AlimtalkAlimCl) => void;
setMinAmount: (minAmount?: number) => void; setSendType: (sendType: AlimtalkSendType) => void;
setMaxAmount: (maxAmount?: number) => void; setSendCl: (sendCl: AlimTalkSendCl) => void;
}; };
export const AlimtalkFilter = ({ export const AlimtalkFilter = ({
filterOn, filterOn,
setFilterOn, setFilterOn,
mid, mid,
moid, searchCl,
searchValue,
fromDate, fromDate,
toDate, toDate,
paymentStatus, serviceCode,
orderStatus, alimCl,
minAmount, sendType,
maxAmount, sendCl,
setMid, setMid,
setMoid, setSearchCl,
setSearchValue,
setFromDate, setFromDate,
setToDate, setToDate,
setPaymentStatus, setServiceCode,
setOrderStatus, setAlimCl,
setMinAmount, setSendType,
setMaxAmount setSendCl
}: AlimtalkFilterProps) => { }: AlimtalkFilterProps) => {
const [filterMid, setFilterMid] = useState<string>(mid); const [filterMid, setFilterMid] = useState<string>(mid);
const [filterMoid, setFilterMoid] = useState<string>(moid); const [filterSearchCl, setFilterSearchCl] = useState<AlimtalkSearchCl>(searchCl);
const [filterFromDate, setFilterFromDate] = useState<string>(moment(fromDate).format('YYYY.MM.DD')); const [filterSearchValue, setFilterSearchValue] = useState<string>(searchValue);
const [filterToDate, setFilterToDate] = useState<string>(moment(toDate).format('YYYY.MM.DD')); const [filterFromDate, setFilterFromDate] = useState<string>(moment(fromDate).format('YYYYMMDD'));
const [filterPaymentStatus, setFilterPaymentStatus] = useState<PaymentStatus>(paymentStatus); const [filterToDate, setFilterToDate] = useState<string>(moment(toDate).format('YYYYMMDD'));
const [filterOrderStatus, setFilterOrderStatus] = useState<OrderStatus>(orderStatus); const [filterServiceCode, setFilterServiceCode] = useState<ServiceCode>(serviceCode);
const [filterMinAmount, setFilterMinAmount] = useState<number | undefined>(minAmount); const [filterAlimCl, setFilterAlimCl] = useState<AlimtalkAlimCl>(alimCl);
const [filterMaxAmount, setFilterMaxAmount] = useState<number | undefined>(maxAmount); const [filterSendType, setFilterSendType] = useState<AlimtalkSendType>(sendType);
const [filterSendCl, setFilterSendCl] = useState<AlimTalkSendCl>(sendCl);
const midOptions = useStore.getState().UserStore.selectOptionsMids; const midOptions = useStore.getState().UserStore.selectOptionsMids;
// 결제수단에 따라 알림구분 버튼 그룹 선택
const alimClBtnGroup = useMemo(() => {
if (filterServiceCode === ServiceCode.VBANK) {
return AlimtalkAlimClBtnGroupForVBank;
}
return AlimtalkAlimClBtnGroupForGeneral;
}, [filterServiceCode]);
const onClickToClose = () => { const onClickToClose = () => {
setFilterOn(false); setFilterOn(false);
}; };
const onClickToSetFilter = () => { const onClickToSetFilter = () => {
setMid(filterMid); setMid(filterMid);
setFilterMoid(filterMoid); setSearchCl(filterSearchCl);
setSearchValue(filterSearchValue);
setFromDate(filterFromDate); setFromDate(filterFromDate);
setToDate(filterToDate); setToDate(filterToDate);
setPaymentStatus(filterPaymentStatus); setServiceCode(filterServiceCode);
setOrderStatus(filterOrderStatus); setAlimCl(filterAlimCl);
setMinAmount(filterMinAmount); setSendType(filterSendType);
setMaxAmount(filterMaxAmount); setSendCl(filterSendCl);
onClickToClose(); onClickToClose();
}; };
useEffect(() => { useEffect(() => {
setFilterPaymentStatus(paymentStatus); setFilterSendCl(sendCl);
}, [paymentStatus]); }, [searchCl]);
// 결제수단이 변경되면 알림구분을 초기화
useEffect(() => {
setFilterAlimCl('' as AlimtalkAlimCl);
}, [filterServiceCode]);
return ( return (
<> <>
<motion.div <motion.div
className="full-menu-modal" className="full-menu-modal"
initial="hidden" initial="hidden"
animate={ (filterOn)? 'visible': 'hidden' } animate={(filterOn) ? 'visible' : 'hidden'}
variants={ FilterMotionVariants } variants={FilterMotionVariants}
transition={ FilterMotionDuration } transition={FilterMotionDuration}
style={ FilterMotionStyle } style={FilterMotionStyle}
> >
<div className="full-menu-container"> <div className="full-menu-container">
<div className="full-menu-header"> <div className="full-menu-header">
@@ -108,9 +127,9 @@ export const AlimtalkFilter = ({
className="full-menu-close" className="full-menu-close"
> >
<img <img
src={ IMAGE_ROOT + '/ico_close.svg' } src={IMAGE_ROOT + '/ico_close.svg'}
alt="닫기" alt="닫기"
onClick={ () => onClickToClose() } onClick={() => onClickToClose()}
/> />
</button> </button>
</div> </div>
@@ -118,46 +137,54 @@ export const AlimtalkFilter = ({
<div className="option-list pt-16"> <div className="option-list pt-16">
<FilterSelect <FilterSelect
title='가맹점' title='가맹점'
selectValue={ filterMid } selectValue={filterMid}
selectSetter={ setFilterMid } selectSetter={setFilterMid}
selectOptions={ midOptions } selectOptions={midOptions}
></FilterSelect> ></FilterSelect>
<FilterInput <FilterSelectInput
title='주문번호' title='주문자,TID'
inputValue={ filterMoid } selectValue={filterSearchCl}
inputSetter={ setFilterMoid } selectSetter={setFilterSearchCl}
></FilterInput> selectOptions={AlimtalkSearchClOptionGroup}
inputValue={filterSearchValue}
inputSetter={setFilterSearchValue}
></FilterSelectInput>
<FilterSelect
title='결제수단'
selectValue={filterServiceCode}
selectSetter={setFilterServiceCode}
selectOptions={AlimtalkServiceCodeOptionGroup}
></FilterSelect>
<FilterButtonGroups
title='알림구분'
activeValue={filterAlimCl}
btnGroups={alimClBtnGroup}
setter={setFilterAlimCl}
></FilterButtonGroups>
<FilterCalendar <FilterCalendar
title='조회기간' title='조회기간'
startDate={ filterFromDate } startDate={filterFromDate}
endDate={ filterToDate } endDate={filterToDate}
setStartDate={ setFilterFromDate } setStartDate={setFilterFromDate}
setEndDate={ setFilterToDate } setEndDate={setFilterToDate}
></FilterCalendar> ></FilterCalendar>
<FilterButtonGroups <FilterButtonGroups
title='결제상태' title='발송 종류'
activeValue={ filterPaymentStatus } activeValue={filterSendType}
btnGroups={ ArsPaymentStatusBtnGroup } btnGroups={AlimtalkSendTypeBtnGroup}
setter={ setFilterPaymentStatus } setter={setFilterSendType}
></FilterButtonGroups> ></FilterButtonGroups>
<FilterButtonGroups <FilterButtonGroups
title='주문상태' title='발송 구분'
activeValue={ filterOrderStatus } activeValue={filterSendCl}
btnGroups={ ArsOrderStatusBtnGroup } btnGroups={AlimtalkSendClBtnGroup}
setter={ setFilterOrderStatus } setter={setFilterSendCl}
></FilterButtonGroups> ></FilterButtonGroups>
<FilterRangeAmount
title='거래금액'
minAmount={ filterMinAmount }
maxAmount={ filterMaxAmount }
setMinAmount={ setFilterMinAmount }
setMaxAmount={ setFilterMaxAmount }
></FilterRangeAmount>
</div> </div>
<div className="apply-row"> <div className="apply-row">
<button <button
className="btn-50 btn-blue flex-1" className="btn-50 btn-blue flex-1"
onClick={ () => onClickToSetFilter() } onClick={() => onClickToSetFilter()}
></button> ></button>
</div> </div>
</div> </div>

View File

@@ -51,8 +51,8 @@ export const FundAccountTransactionFilter = ({
const [filterMid, setFilterMid] = useState<string>(mid); const [filterMid, setFilterMid] = useState<string>(mid);
const [filterSearchCl,setFilterSearchCl] = useState<FundAccountSearchCl>(searchCl); const [filterSearchCl,setFilterSearchCl] = useState<FundAccountSearchCl>(searchCl);
const [filterSearchValue, setFilterSearchValue] = useState<string>(searchValue); const [filterSearchValue, setFilterSearchValue] = useState<string>(searchValue);
const [filterFromDate, setFilterFromDate] = useState<string>(moment(fromDate).format('YYYY.MM.DD')); const [filterFromDate, setFilterFromDate] = useState<string>(moment(fromDate).format('YYYYMMDD'));
const [filterToDate, setFilterToDate] = useState<string>(moment(toDate).format('YYYY.MM.DD')); const [filterToDate, setFilterToDate] = useState<string>(moment(toDate).format('YYYYMMDD'));
const [filterBankCode, setFilterBankCode] = useState<string>(bankCode); const [filterBankCode, setFilterBankCode] = useState<string>(bankCode);
const [filterStatus, setFilterStatus] = useState<FundAccountStatus>(status); const [filterStatus, setFilterStatus] = useState<FundAccountStatus>(status);
const midOptions = useStore.getState().UserStore.selectOptionsMids; const midOptions = useStore.getState().UserStore.selectOptionsMids;

View File

@@ -1,5 +1,5 @@
import moment from 'moment'; import moment from 'moment';
import { SortTypeKeys } from '@/entities/common/model/types'; import { DefaultRequestPagination, SortTypeKeys } from '@/entities/common/model/types';
import { IMAGE_ROOT } from '@/shared/constants/common'; import { IMAGE_ROOT } from '@/shared/constants/common';
import { useNavigate } from '@/shared/lib/hooks/use-navigate'; import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { JSX, useEffect, useState } from 'react'; import { JSX, useEffect, useState } from 'react';
@@ -16,38 +16,17 @@ import { SortTypeBox } from '@/entities/common/ui/sort-type-box';
import { FundAccountResultStatusBtnGroup, FundAccountStatusBtnGroup } from '../../model/fund-account/constant'; import { FundAccountResultStatusBtnGroup, FundAccountStatusBtnGroup } from '../../model/fund-account/constant';
import { FundAccountResultFilter } from '../filter/fund-account-result-filter'; import { FundAccountResultFilter } from '../filter/fund-account-result-filter';
import { useStore } from '@/shared/model/store'; import { useStore } from '@/shared/model/store';
import useIntersectionObserver from '@/widgets/intersection-observer'; import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet';
export const FundAccountResultListWrap = () => { export const FundAccountResultListWrap = () => {
const { navigate } = useNavigate(); const { navigate } = useNavigate();
const [onActionIntersect, setOnActionIntersect] = useState<boolean>(false);
const onIntersect: IntersectionObserverCallback = (entries: Array<IntersectionObserverEntry>) => {
entries.forEach((entry: IntersectionObserverEntry) => {
if (entry.isIntersecting) {
console.log('Element is now intersecting with the root. [' + onActionIntersect + ']');
if (onActionIntersect) {
callList();
}
}
else {
console.log('Element is no longer intersecting with the root.');
}
});
};
const { setTarget } = useIntersectionObserver({
threshold: 1,
onIntersect
});
const userMid = useStore.getState().UserStore.mid; const userMid = useStore.getState().UserStore.mid;
const [sortType, setSortType] = useState<SortTypeKeys>(SortTypeKeys.LATEST); const [sortType, setSortType] = useState<SortTypeKeys>(SortTypeKeys.LATEST);
const [listItems, setListItems] = useState<Array<FundAccountResultContentItem>>([]); const [listItems, setListItems] = useState<Array<FundAccountResultContentItem>>([]);
const [filterOn, setFilterOn] = useState<boolean>(false); const [filterOn, setFilterOn] = useState<boolean>(false);
const [nextCursor, setNextCursor] = useState<string | null>(null); const [pageParam, setPageParam] = useState<DefaultRequestPagination>(DEFAULT_PAGE_PARAM);
const [pageParam, setPageParam] = useState(DEFAULT_PAGE_PARAM);
const [mid, setMid] = useState<string>(userMid); const [mid, setMid] = useState<string>(userMid);
const [searchCl, setSearchCl] = useState<FundAccountSearchCl>(FundAccountSearchCl.ACCOUNT_NAME); const [searchCl, setSearchCl] = useState<FundAccountSearchCl>(FundAccountSearchCl.ACCOUNT_NAME);
@@ -74,49 +53,28 @@ export const FundAccountResultListWrap = () => {
const callList = (option?: { const callList = (option?: {
sortType?: SortTypeKeys, sortType?: SortTypeKeys,
resultStatus?: FundAccountResultStatus, resultStatus?: FundAccountResultStatus
resetPage?: boolean
}) => { }) => {
setOnActionIntersect(false);
const currentPageParam = option?.resetPage
? { ...DEFAULT_PAGE_PARAM, sortType: option?.sortType ?? sortType }
: { ...pageParam, sortType: option?.sortType ?? sortType };
setPageParam(currentPageParam);
let listSummaryParams: ExtensionFundAccountResultListParams = { let listSummaryParams: ExtensionFundAccountResultListParams = {
mid: mid, mid: mid,
searchCl: searchCl, searchCl: searchCl,
searchValue: searchValue, searchValue: searchValue,
searchDateType: searchDateType, searchDateType: searchDateType,
fromDate: '20240901', fromDate: fromDate,
toDate: '20250930', toDate: toDate,
bankCode: bankCode, bankCode: bankCode,
resultStatus: option?.resultStatus ?? resultStatus, resultStatus: option?.resultStatus ?? resultStatus,
... { page: pageParam
page: currentPageParam
}
}; };
if (listSummaryParams.page) {
listSummaryParams.page.sortType = option?.sortType || sortType;
setPageParam(listSummaryParams.page);
}
extensionFundAccountResultList(listSummaryParams).then((rs: any) => { extensionFundAccountResultList(listSummaryParams).then((rs: any) => {
console.log(rs); console.log(rs);
// resetPage면 기존 리스트 무시, 아니면 추가 setListItems(rs.content);
setListItems(option?.resetPage ? rs.content : [
...listItems,
...rs.content
]);
if (rs.hasNext) {
setNextCursor(rs.nextCursor);
setPageParam({
...currentPageParam, // pageParam이 아니라 currentPageParam 사용
cursor: rs.nextCursor
});
setOnActionIntersect(true)
}
else {
setNextCursor(null);
}
}); });
}; };
@@ -159,46 +117,46 @@ export const FundAccountResultListWrap = () => {
const onClickToSort = (sort: SortTypeKeys) => { const onClickToSort = (sort: SortTypeKeys) => {
setSortType(sort); setSortType(sort);
callList({ callList({
sortType: sort, sortType: sort
resetPage: true
}); });
}; };
const onClickToStatus = (val: FundAccountResultStatus) => { const onClickToStatus = (val: FundAccountResultStatus) => {
setResultStatus(val); setResultStatus(val);
callList({ callList({
resultStatus: val, resultStatus: val
resetPage: true
}); });
}; };
const getListDateGroup = () => { const getListDateGroup = () => {
let rs: JSX.Element[] = []; let rs = [];
let date = ''; let date = '';
let list: FundAccountResultContentItem[] = []; let list = [];
for (let i = 0; i < listItems.length; i++) { for (let i = 0; i < listItems.length; i++) {
// requestDate format: "20211018140420" (YYYYMMDDHHmmss) let items = listItems[i];
let requestDate = listItems[i]?.requestDate || ''; if (!!items) {
let itemDate = requestDate.substring(0, 8); let requestDate = items?.requestDate;
requestDate = requestDate?.substring(0, 8);
if (!!requestDate) {
if (i === 0) { if (i === 0) {
date = itemDate; date = requestDate;
} }
if (date !== itemDate) { if (date !== requestDate) {
// 날짜가 바뀌면 이전 리스트를 푸시 (날짜 업데이트 전에!) date = requestDate;
if (list.length > 0) { if (list.length > 0) {
rs.push( rs.push(
<ListDateGroup <ListDateGroup
additionalServiceCategory={AdditionalServiceCategory.FundAccountResult} additionalServiceCategory={AdditionalServiceCategory.FundAccountResult}
mid={mid}
key={date + '-' + i} key={date + '-' + i}
date={date} // 이전 날짜 사용 date={date}
items={list as any} items={list}
></ListDateGroup> ></ListDateGroup>
); );
} }
date = itemDate; // 그 다음에 날짜 업데이트
list = []; list = [];
} }
list.push(listItems[i] as any); list.push(items);
}
}
} }
if (list.length > 0) { if (list.length > 0) {
rs.push( rs.push(
@@ -207,7 +165,7 @@ export const FundAccountResultListWrap = () => {
mid={mid} mid={mid}
key={date + '-last'} key={date + '-last'}
date={date} date={date}
items={list as any} items={list}
></ListDateGroup> ></ListDateGroup>
); );
} }
@@ -219,8 +177,7 @@ export const FundAccountResultListWrap = () => {
}, []); }, []);
useEffect(() => { useEffect(() => {
// 필터 조건이 변경되면 첫 페이지부터 다시 시작 callList();
callList({ resetPage: true });
}, [ }, [
mid, mid,
searchCl, searchCl,
@@ -361,7 +318,6 @@ export const FundAccountResultListWrap = () => {
<section className="transaction-list"> <section className="transaction-list">
{getListDateGroup()} {getListDateGroup()}
<div ref={setTarget}></div>
</section> </section>
<div className="apply-row"> <div className="apply-row">
<button <button

View File

@@ -25,37 +25,16 @@ import { NumericFormat } from 'react-number-format';
import { FundAccountTransactionFilter } from '../filter/fund-account-trnasaction-filter'; import { FundAccountTransactionFilter } from '../filter/fund-account-trnasaction-filter';
import { PATHS } from '@/shared/constants/paths'; import { PATHS } from '@/shared/constants/paths';
import { useStore } from '@/shared/model/store'; import { useStore } from '@/shared/model/store';
import useIntersectionObserver from '@/widgets/intersection-observer'; import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet';
export const FundAccountTransferListWrap = () => { export const FundAccountTransferListWrap = () => {
const { navigate } = useNavigate(); const { navigate } = useNavigate();
const [onActionIntersect, setOnActionIntersect] = useState<boolean>(false);
const onIntersect: IntersectionObserverCallback = (entries: Array<IntersectionObserverEntry>) => {
entries.forEach((entry: IntersectionObserverEntry) => {
if (entry.isIntersecting) {
console.log('Element is now intersecting with the root. [' + onActionIntersect + ']');
if (onActionIntersect) {
callList();
}
}
else {
console.log('Element is no longer intersecting with the root.');
}
});
};
const { setTarget } = useIntersectionObserver({
threshold: 1,
onIntersect
});
const userMid = useStore.getState().UserStore.mid; const userMid = useStore.getState().UserStore.mid;
const [sortType, setSortType] = useState<SortTypeKeys>(SortTypeKeys.LATEST); const [sortType, setSortType] = useState<SortTypeKeys>(SortTypeKeys.LATEST);
const [listItems, setListItems] = useState<Array<FundAccountTransferContentItem>>([]); const [listItems, setListItems] = useState<Array<FundAccountTransferContentItem>>([]);
const [filterOn, setFilterOn] = useState<boolean>(false); const [filterOn, setFilterOn] = useState<boolean>(false);
const [nextCursor, setNextCursor] = useState<string | null>(null);
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 [searchCl, setSearchCl] = useState<FundAccountSearchCl>(FundAccountSearchCl.ACCOUNT_NAME); const [searchCl, setSearchCl] = useState<FundAccountSearchCl>(FundAccountSearchCl.ACCOUNT_NAME);
@@ -65,7 +44,7 @@ export const FundAccountTransferListWrap = () => {
const [status, setStatus] = useState<FundAccountStatus>(FundAccountStatus.ALL); const [status, setStatus] = useState<FundAccountStatus>(FundAccountStatus.ALL);
const [bankCode, setBankCode] = useState<string>(''); const [bankCode, setBankCode] = useState<string>('');
const [email, setEmail] = useState<string>(''); const [emailBottomSheetOn, setEmailBottomSheetOn] = useState<boolean>(false);
const [balance, setBalance] = useState<number>(0); const [balance, setBalance] = useState<number>(0);
const { mutateAsync: extensionFundAccountTransferList } = useExtensionFundAccountTransferListMutation(); const { mutateAsync: extensionFundAccountTransferList } = useExtensionFundAccountTransferListMutation();
@@ -74,17 +53,8 @@ export const FundAccountTransferListWrap = () => {
const callList = (option?: { const callList = (option?: {
sortType?: SortTypeKeys, sortType?: SortTypeKeys,
status?: FundAccountStatus, status?: FundAccountStatus
resetPage?: boolean
}) => { }) => {
setOnActionIntersect(false);
const currentPageParam = option?.resetPage
? { ...DEFAULT_PAGE_PARAM, sortType: option?.sortType ?? sortType }
: { ...pageParam, sortType: option?.sortType ?? sortType };
setPageParam(currentPageParam);
let listSummaryParams: ExtensionFundAccountTransferListParams = { let listSummaryParams: ExtensionFundAccountTransferListParams = {
mid: mid, mid: mid,
searchCl: searchCl, searchCl: searchCl,
@@ -93,41 +63,37 @@ export const FundAccountTransferListWrap = () => {
fromDate: fromDate, fromDate: fromDate,
toDate: toDate, toDate: toDate,
resultStatus: option?.status ?? status, resultStatus: option?.status ?? status,
... { page: pageParam
page: currentPageParam
}
}; };
if (listSummaryParams.page) {
listSummaryParams.page.sortType = option?.sortType || sortType;
setPageParam(listSummaryParams.page);
}
extensionFundAccountTransferList(listSummaryParams).then((rs: any) => { extensionFundAccountTransferList(listSummaryParams).then((rs: any) => {
setListItems(option?.resetPage ? rs.content : [ setListItems(rs.content);
...listItems,
...rs.content
]);
if (rs.hasNext) {
setNextCursor(rs.nextCursor);
setPageParam({
...currentPageParam, // pageParam이 아니라 currentPageParam 사용
cursor: rs.nextCursor
});
setOnActionIntersect(true)
}
else {
setNextCursor(null);
}
}); });
callBalance(); callBalance();
}; };
const callDownloadExcel = () => { const onClickToOpenEmailBottomSheet = () => {
let params: ExtensionFundAccountTransferExcelParams = { setEmailBottomSheetOn(true);
};
const onSendRequest = (selectedEmail?: string) => {
if (selectedEmail) {
const params: ExtensionFundAccountTransferExcelParams = {
mid: mid, mid: mid,
email: email, email: selectedEmail,
fromDate: fromDate, fromDate: fromDate,
toDate: toDate, toDate: toDate,
}; };
extensionFundAccountTransferExcel(params).then((rs: ExtensionFundAccountTransferExcelResponse) => { extensionFundAccountTransferExcel(params).then((rs: ExtensionFundAccountTransferExcelResponse) => {
console.log('Excel Download Status:', rs.status);
}); });
}
setEmailBottomSheetOn(false);
}; };
const callBalance = () => { const callBalance = () => {
@@ -139,11 +105,6 @@ export const FundAccountTransferListWrap = () => {
}); });
}; };
const onClickToDownloadExcel = () => {
callDownloadExcel();
};
const onClickToOpenFilter = () => { const onClickToOpenFilter = () => {
setFilterOn(!filterOn); setFilterOn(!filterOn);
}; };
@@ -151,47 +112,47 @@ export const FundAccountTransferListWrap = () => {
const onClickToSort = (sort: SortTypeKeys) => { const onClickToSort = (sort: SortTypeKeys) => {
setSortType(sort); setSortType(sort);
callList({ callList({
sortType: sort, sortType: sort
resetPage: true
}); });
}; };
const onClickToStatus = (val: FundAccountStatus) => { const onClickToStatus = (val: FundAccountStatus) => {
setStatus(val); setStatus(val);
callList({ callList({
status: val, status: val
resetPage: true
}); });
}; };
const getListDateGroup = () => { const getListDateGroup = () => {
let rs: JSX.Element[] = []; let rs = [];
let date = ''; let date = '';
let list: FundAccountTransferContentItem[] = []; let list = [];
for (let i = 0; i < listItems.length; i++) { for (let i = 0; i < listItems.length; i++) {
// registDate format: "20211018140420" (YYYYMMDDHHmmss) let items = listItems[i];
let registDate = listItems[i]?.registDate || ''; if (!!items) {
let itemDate = registDate.substring(0, 8); let registDate = items?.registDate;
registDate = registDate?.substring(0, 8);
if (!!registDate) {
if (i === 0) { if (i === 0) {
date = itemDate; date = registDate;
} }
if (date !== itemDate) { if (date !== registDate) {
// 날짜가 바뀌면 이전 리스트를 푸시 (날짜 업데이트 전에!) date = registDate;
if (list.length > 0) { if (list.length > 0) {
rs.push( rs.push(
<ListDateGroup <ListDateGroup
additionalServiceCategory={AdditionalServiceCategory.FundAccountTransfer} additionalServiceCategory={AdditionalServiceCategory.FundAccountTransfer}
mid={mid}
key={date + '-' + i} key={date + '-' + i}
date={date} // 이전 날짜 사용 date={date}
items={list as any} items={list}
></ListDateGroup> ></ListDateGroup>
); );
} }
date = itemDate; // 그 다음에 날짜 업데이트
list = []; list = [];
} }
list.push(listItems[i] as any); list.push(items);
}
}
} }
if (list.length > 0) { if (list.length > 0) {
rs.push( rs.push(
@@ -200,7 +161,7 @@ export const FundAccountTransferListWrap = () => {
mid={mid} mid={mid}
key={date + '-last'} key={date + '-last'}
date={date} date={date}
items={list as any} items={list}
></ListDateGroup> ></ListDateGroup>
); );
} }
@@ -208,8 +169,7 @@ export const FundAccountTransferListWrap = () => {
}; };
useEffect(() => { useEffect(() => {
// 필터 조건이 변경되면 첫 페이지부터 다시 시작 callList();
callList({ resetPage: true });
}, [ }, [
mid, mid,
searchCl, searchCl,
@@ -249,7 +209,7 @@ export const FundAccountTransferListWrap = () => {
<button <button
className="download-btn" className="download-btn"
aria-label="다운로드" aria-label="다운로드"
onClick={() => onClickToDownloadExcel()} onClick={onClickToOpenEmailBottomSheet}
> >
<img <img
src={IMAGE_ROOT + '/ico_download.svg'} src={IMAGE_ROOT + '/ico_download.svg'}
@@ -298,7 +258,6 @@ export const FundAccountTransferListWrap = () => {
<section className="transaction-list pb-86"> <section className="transaction-list pb-86">
{getListDateGroup()} {getListDateGroup()}
<div ref={setTarget}></div>
</section> </section>
<div className="apply-row"> <div className="apply-row">
<button <button
@@ -324,6 +283,14 @@ export const FundAccountTransferListWrap = () => {
setBankCode={setBankCode} setBankCode={setBankCode}
setStatus={setStatus} setStatus={setStatus}
></FundAccountTransactionFilter> ></FundAccountTransactionFilter>
<EmailBottomSheet
bottomSheetOn={emailBottomSheetOn}
setBottomSheetOn={setEmailBottomSheetOn}
imageSave={false}
sendEmail={true}
sendRequest={onSendRequest}
/>
</> </>
); );
}; };

View File

@@ -7,38 +7,40 @@ import { JSX } from 'react';
export const KeyInPaymentList = ({ export const KeyInPaymentList = ({
additionalServiceCategory, additionalServiceCategory,
listItems, listItems,
mid, mid
setTarget
}: KeyInPaymentListProps) => { }: KeyInPaymentListProps) => {
const { navigate } = useNavigate(); const { navigate } = useNavigate();
const getListDateGroup = () => { const getListDateGroup = () => {
let rs: JSX.Element[] = []; let rs = [];
let date = ''; let date = '';
let list: KeyInPaymentListItem[] = []; let list = [];
for (let i = 0; i < listItems.length; i++) { for (let i = 0; i < listItems.length; i++) {
// paymentDate format: "20211018140420" (YYYYMMDDHHmmss) let items = listItems[i];
let paymentDate = listItems[i]?.paymentDate || ''; if (!!items) {
let itemDate = paymentDate.substring(0, 8); let paymentDate = items?.paymentDate;
paymentDate = paymentDate?.substring(0, 8)
if (!!paymentDate) {
if (i === 0) { if (i === 0) {
date = itemDate; date = paymentDate;
} }
if (date !== itemDate) { if (date !== paymentDate) {
date = itemDate; date = paymentDate;
if (list.length > 0) { if (list.length > 0) {
rs.push( rs.push(
<ListDateGroup <ListDateGroup
additionalServiceCategory={additionalServiceCategory} additionalServiceCategory={additionalServiceCategory}
mid={mid}
key={date + '-' + i} key={date + '-' + i}
date={date} date={date}
items={list as any} items={list}
></ListDateGroup> ></ListDateGroup>
); );
} }
list = []; list = [];
} }
list.push(listItems[i] as any); list.push(items);
}
}
} }
if (list.length > 0) { if (list.length > 0) {
rs.push( rs.push(
@@ -47,7 +49,7 @@ export const KeyInPaymentList = ({
mid={mid} mid={mid}
key={date + '-last'} key={date + '-last'}
date={date} date={date}
items={list as any} items={list}
></ListDateGroup> ></ListDateGroup>
); );
} }
@@ -62,7 +64,6 @@ export const KeyInPaymentList = ({
<> <>
<section className="transaction-list"> <section className="transaction-list">
{getListDateGroup()} {getListDateGroup()}
<div ref={setTarget}></div>
</section> </section>
<div className="apply-row"> <div className="apply-row">
<button <button

View File

@@ -5,47 +5,48 @@ import { ListDateGroup } from '../list-date-group';
export const LinkPaymentHistoryList = ({ export const LinkPaymentHistoryList = ({
additionalServiceCategory, additionalServiceCategory,
listItems, listItems,
setTarget,
mid mid
}: LinkPaymentHistoryListProps) => { }: LinkPaymentHistoryListProps) => {
const getListDateGroup = () => { const getListDateGroup = () => {
let rs: JSX.Element[] = []; let rs = [];
let date = ''; let date = '';
let list: LinkPaymentHistoryListItem[] = []; let list = [];
for (let i = 0; i < listItems.length; i++) { for (let i = 0; i < listItems.length; i++) {
let items = listItems[i];
// sendDate(발송일자) 기준 if (!!items) {
let sendDate = listItems[i]?.sendDate || ''; let sendDate = items?.sendDate;
let itemDate = sendDate.substring(0, 8); sendDate = sendDate?.substring(0, 8);
if (!!sendDate) {
if (i === 0) { if (i === 0) {
date = itemDate; date = sendDate;
} }
if (date !== itemDate) { if (date !== sendDate) {
date = sendDate;
if (list.length > 0) { if (list.length > 0) {
rs.push( rs.push(
<ListDateGroup <ListDateGroup
additionalServiceCategory={additionalServiceCategory} additionalServiceCategory={additionalServiceCategory}
key={date + '-' + i} key={date + '-' + i}
date={date} date={date}
items={list as any} items={list}
mid={mid}
></ListDateGroup> ></ListDateGroup>
); );
} }
date = itemDate;
list = []; list = [];
} }
list.push(listItems[i] as any); list.push(items);
}
}
} }
if (list.length > 0) { if (list.length > 0) {
rs.push( rs.push(
<ListDateGroup <ListDateGroup
additionalServiceCategory={additionalServiceCategory} additionalServiceCategory={additionalServiceCategory}
mid={mid}
key={date + '-last'} key={date + '-last'}
date={date} date={date}
items={list as any} items={list}
mid={mid}
></ListDateGroup> ></ListDateGroup>
); );
} }
@@ -56,7 +57,6 @@ export const LinkPaymentHistoryList = ({
<> <>
<div className="transaction-list"> <div className="transaction-list">
{getListDateGroup()} {getListDateGroup()}
<div ref={setTarget}></div>
</div> </div>
</> </>
) )

View File

@@ -13,7 +13,6 @@ import { DEFAULT_PAGE_PARAM } from '@/entities/common/model/constant';
import { useExtensionLinkPayHistoryDownloadExcelMutation } from '../../api/link-payment/use-extension-link-pay-history-download-excel-mutation'; import { useExtensionLinkPayHistoryDownloadExcelMutation } from '../../api/link-payment/use-extension-link-pay-history-download-excel-mutation';
import { useStore } from '@/shared/model/store'; import { useStore } from '@/shared/model/store';
import { ExtensionLinkPayHistoryListParams, LinkPaymentHistoryListItem, LinkPaymentPaymentMethod, LinkPaymentPaymentStatus, LinkPaymentSearchCl, LinkPaymentSendMethod, LinkPaymentSendStatus } from '../../model/link-pay/types'; import { ExtensionLinkPayHistoryListParams, LinkPaymentHistoryListItem, LinkPaymentPaymentMethod, LinkPaymentPaymentStatus, LinkPaymentSearchCl, LinkPaymentSendMethod, LinkPaymentSendStatus } from '../../model/link-pay/types';
import useIntersectionObserver from '@/widgets/intersection-observer';
const paymentResultBtnGroup = [ const paymentResultBtnGroup = [
{ name: '전체', value: LinkPaymentPaymentStatus.ALL }, { name: '전체', value: LinkPaymentPaymentStatus.ALL },
@@ -27,30 +26,10 @@ const paymentResultBtnGroup = [
export const LinkPaymentHistoryWrap = () => { export const LinkPaymentHistoryWrap = () => {
const { navigate } = useNavigate(); const { navigate } = useNavigate();
const userMid = useStore.getState().UserStore.mid; const userMid = useStore.getState().UserStore.mid;
const [onActionIntersect, setOnActionIntersect] = useState<boolean>(false);
const onIntersect: IntersectionObserverCallback = (entries: Array<IntersectionObserverEntry>) => {
entries.forEach((entry: IntersectionObserverEntry) => {
if (entry.isIntersecting) {
console.log('Element is now intersecting with the root. [' + onActionIntersect + ']');
if (onActionIntersect) {
callList();
}
}
else {
console.log('Element is no longer intersecting with the root.');
}
});
};
const { setTarget } = useIntersectionObserver({
threshold: 1,
onIntersect
});
const [filterOn, setFilterOn] = useState<boolean>(false); const [filterOn, setFilterOn] = useState<boolean>(false);
const [sortType, setSortType] = useState<SortTypeKeys>(SortTypeKeys.LATEST); const [sortType, setSortType] = useState<SortTypeKeys>(SortTypeKeys.LATEST);
const [listItems, setListItems] = useState<Array<LinkPaymentHistoryListItem>>([]); const [listItems, setListItems] = useState<Array<LinkPaymentHistoryListItem>>([]);
const [nextCursor, setNextCursor] = useState<string | null>(null);
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);
@@ -74,17 +53,8 @@ export const LinkPaymentHistoryWrap = () => {
const callList = (option?: { const callList = (option?: {
sortType?: SortTypeKeys, sortType?: SortTypeKeys,
status?: LinkPaymentPaymentStatus, status?: LinkPaymentPaymentStatus
resetPage?: boolean
}) => { }) => {
setOnActionIntersect(false);
const currentPageParam = option?.resetPage
? { ...DEFAULT_PAGE_PARAM, sortType: option?.sortType ?? sortType }
: { ...pageParam, sortType: option?.sortType ?? sortType };
setPageParam(currentPageParam); // currentPageParam으로 수정!
let listParams: ExtensionLinkPayHistoryListParams = { let listParams: ExtensionLinkPayHistoryListParams = {
mid: mid, mid: mid,
searchCl: searchCl, searchCl: searchCl,
@@ -94,27 +64,16 @@ export const LinkPaymentHistoryWrap = () => {
paymentStatus: option?.status ?? paymentStatus, paymentStatus: option?.status ?? paymentStatus,
sendStatus: sendStatus, sendStatus: sendStatus,
sendMethod: sendMethod, sendMethod: sendMethod,
... { page: pageParam
page: currentPageParam
}
}; };
if (listParams.page) {
listParams.page.sortType = option?.sortType || sortType;
setPageParam(listParams.page);
}
linkPayHistoryList(listParams).then((rs) => { linkPayHistoryList(listParams).then((rs) => {
setListItems(option?.resetPage ? rs.content : [ setListItems(rs.content);
...listItems,
...rs.content
]);
if (rs.hasNext) {
setNextCursor(rs.nextCursor);
setPageParam({
...currentPageParam, // pageParam이 아니라 currentPageParam 사용
cursor: rs.nextCursor
});
setOnActionIntersect(true)
}
else {
setNextCursor(null);
}
}); });
}; };
@@ -138,16 +97,14 @@ export const LinkPaymentHistoryWrap = () => {
const onClickPaymentStatus = (val: LinkPaymentPaymentStatus) => { const onClickPaymentStatus = (val: LinkPaymentPaymentStatus) => {
setPaymentStatus(val); setPaymentStatus(val);
callList({ callList({
status: val, status: val
resetPage: true
}) })
} }
const onClickToSort = (sort: SortTypeKeys) => { const onClickToSort = (sort: SortTypeKeys) => {
setSortType(sort); setSortType(sort);
callList({ callList({
sortType: sort, sortType: sort
resetPage: true
}); });
}; };
@@ -156,8 +113,7 @@ export const LinkPaymentHistoryWrap = () => {
}; };
useEffect(() => { useEffect(() => {
// 필터 조건이 변경되면 첫 페이지부터 다시 시작 callList();
callList({ resetPage: true });
}, [ }, [
mid, mid,
searchCl, searchCl,
@@ -227,7 +183,6 @@ export const LinkPaymentHistoryWrap = () => {
<LinkPaymentHistoryList <LinkPaymentHistoryList
listItems={listItems} listItems={listItems}
additionalServiceCategory={AdditionalServiceCategory.LinkPaymentHistory} additionalServiceCategory={AdditionalServiceCategory.LinkPaymentHistory}
setTarget={setTarget}
mid={mid} mid={mid}
></LinkPaymentHistoryList> ></LinkPaymentHistoryList>
<div className="apply-row"> <div className="apply-row">

View File

@@ -5,46 +5,48 @@ import { ListDateGroup } from '../list-date-group';
export const LinkPaymentWaitList = ({ export const LinkPaymentWaitList = ({
additionalServiceCategory, additionalServiceCategory,
listItems, listItems,
setTarget,
mid mid
}: LinkPaymentWaitListProps) => { }: LinkPaymentWaitListProps) => {
const getListDateGroup = () => { const getListDateGroup = () => {
let rs: JSX.Element[] = []; let rs = [];
let date = ''; let date = '';
let list: LinkPaymentWaitListItem[] = []; let list = [];
for (let i = 0; i < listItems.length; i++) { for (let i = 0; i < listItems.length; i++) {
// paymentDate format: "20211018140420" (YYYYMMDDHHmmss) let items = listItems[i];
let scheduledSendDate = listItems[i]?.scheduledSendDate || ''; if(!!items) {
let itemDate = scheduledSendDate.substring(0, 8); let scheduledSendDate = items?.scheduledSendDate;
if (i === 0) { scheduledSendDate = scheduledSendDate?.substring(0, 8);
date = itemDate; if(!!scheduledSendDate) {
if(i === 0) {
date = scheduledSendDate;
} }
if (date !== itemDate) { if(date !== scheduledSendDate) {
if (list.length > 0) { date = scheduledSendDate;
if(list.length > 0) {
rs.push( rs.push(
<ListDateGroup <ListDateGroup
additionalServiceCategory={additionalServiceCategory} additionalServiceCategory={additionalServiceCategory}
key={date + '-' + i} key={ date + '-' + i}
date={date} date={ date }
items={list as any} items={ list }
mid={mid}
></ListDateGroup> ></ListDateGroup>
); );
} }
date = itemDate;
list = []; list = [];
} }
list.push(listItems[i] as any); list.push(items);
}
}
} }
if (list.length > 0) { if (list.length > 0) {
rs.push( rs.push(
<ListDateGroup <ListDateGroup
additionalServiceCategory={additionalServiceCategory} additionalServiceCategory={additionalServiceCategory}
mid={mid}
key={date + '-last'} key={date + '-last'}
date={date} date={date}
items={list as any} items={list}
mid={mid}
></ListDateGroup> ></ListDateGroup>
); );
} }
@@ -55,7 +57,6 @@ export const LinkPaymentWaitList = ({
<> <>
<div className="transaction-list"> <div className="transaction-list">
{getListDateGroup()} {getListDateGroup()}
<div ref={setTarget}></div>
</div> </div>
</> </>
) )

View File

@@ -13,9 +13,9 @@ import { DEFAULT_PAGE_PARAM } from '@/entities/common/model/constant';
import { useExtensionLinkPayWaitDownloadExcelMutation } from '../../api/link-payment/use-extension-link-pay-wait-download-excel-mutation'; import { useExtensionLinkPayWaitDownloadExcelMutation } from '../../api/link-payment/use-extension-link-pay-wait-download-excel-mutation';
import { useStore } from '@/shared/model/store'; import { useStore } from '@/shared/model/store';
import { LinkPaymentProcessStatus, LinkPaymentSearchCl, LinkPaymentSendMethod, LinkPaymentSendStatus, LinkPaymentWaitListItem } from '../../model/link-pay/types'; import { LinkPaymentProcessStatus, LinkPaymentSearchCl, LinkPaymentSendMethod, LinkPaymentSendStatus, LinkPaymentWaitListItem } from '../../model/link-pay/types';
import useIntersectionObserver from '@/widgets/intersection-observer';
import { ProcessStatusBtnGrouup } from '../../model/link-pay/constant'; import { ProcessStatusBtnGrouup } from '../../model/link-pay/constant';
import { useExtensionLinkPayWaitDeleteMutation } from '../../api/link-payment/use-extension-link-pay-wait-delete-mutation'; import { useExtensionLinkPayWaitDeleteMutation } from '../../api/link-payment/use-extension-link-pay-wait-delete-mutation';
import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet';
@@ -23,26 +23,6 @@ export const LinkPaymentWaitSendWrap = () => {
const { navigate } = useNavigate(); const { navigate } = useNavigate();
const userMid = useStore.getState().UserStore.mid; const userMid = useStore.getState().UserStore.mid;
const [onActionIntersect, setOnActionIntersect] = useState<boolean>(false);
const onIntersect: IntersectionObserverCallback = (entries: Array<IntersectionObserverEntry>) => {
entries.forEach((entry: IntersectionObserverEntry) => {
if (entry.isIntersecting) {
console.log('Element is now intersecting with the root. [' + onActionIntersect + ']');
if (onActionIntersect) {
callList();
}
}
else {
console.log('Element is no longer intersecting with the root.');
}
});
};
const { setTarget } = useIntersectionObserver({
threshold: 1,
onIntersect
});
const [sortType, setSortType] = useState<SortTypeKeys>(SortTypeKeys.LATEST); const [sortType, setSortType] = useState<SortTypeKeys>(SortTypeKeys.LATEST);
const [filterOn, setFilterOn] = useState<boolean>(false); const [filterOn, setFilterOn] = useState<boolean>(false);
const [mid, setMid] = useState<string>(userMid); const [mid, setMid] = useState<string>(userMid);
@@ -53,7 +33,6 @@ export const LinkPaymentWaitSendWrap = () => {
const [sendMethod, setSendMethod] = useState<LinkPaymentSendMethod>(LinkPaymentSendMethod.ALL); const [sendMethod, setSendMethod] = useState<LinkPaymentSendMethod>(LinkPaymentSendMethod.ALL);
const [processStatus, setProcessStatus] = useState<LinkPaymentProcessStatus>(LinkPaymentProcessStatus.ALL); const [processStatus, setProcessStatus] = useState<LinkPaymentProcessStatus>(LinkPaymentProcessStatus.ALL);
const [listItems, setListItems] = useState<Array<LinkPaymentWaitListItem>>([]); const [listItems, setListItems] = useState<Array<LinkPaymentWaitListItem>>([]);
const [nextCursor, setNextCursor] = useState<string | null>(null);
const [pageParam, setPageParam] = useState<DefaultRequestPagination>(DEFAULT_PAGE_PARAM); const [pageParam, setPageParam] = useState<DefaultRequestPagination>(DEFAULT_PAGE_PARAM);
const [email, setEmail] = useState<string>(''); const [email, setEmail] = useState<string>('');
@@ -69,17 +48,8 @@ export const LinkPaymentWaitSendWrap = () => {
const callList = (option?: { const callList = (option?: {
sortType?: SortTypeKeys, sortType?: SortTypeKeys,
status?: LinkPaymentProcessStatus, status?: LinkPaymentProcessStatus
resetPage?: boolean
}) => { }) => {
setOnActionIntersect(false);
const currentPageParam = option?.resetPage
? { ...DEFAULT_PAGE_PARAM, sortType: option?.sortType ?? sortType }
: { ...pageParam, sortType: option?.sortType ?? sortType };
setPageParam(currentPageParam);
let listParams = { let listParams = {
mid: mid, mid: mid,
searchCl: searchType, searchCl: searchType,
@@ -88,27 +58,16 @@ export const LinkPaymentWaitSendWrap = () => {
toDate: endDate, toDate: endDate,
sendMethod: sendMethod, sendMethod: sendMethod,
processStatus: option?.status ?? processStatus, processStatus: option?.status ?? processStatus,
... { page: pageParam
page: currentPageParam
} }
if (listParams.page) {
listParams.page.sortType = option?.sortType || sortType;
setPageParam(listParams.page);
} }
pendingSendList(listParams).then((rs) => { pendingSendList(listParams).then((rs) => {
setListItems(option?.resetPage ? rs.content : [ setListItems(rs.content);
...listItems,
...rs.content
]);
if (rs.hasNext) {
setNextCursor(rs.nextCursor);
setPageParam({
...currentPageParam,
cursor: rs.nextCursor
});
setOnActionIntersect(true);
}
else {
setNextCursor(null);
}
}); });
}; };
@@ -130,22 +89,19 @@ export const LinkPaymentWaitSendWrap = () => {
const onClickToSort = (sort: SortTypeKeys) => { const onClickToSort = (sort: SortTypeKeys) => {
setSortType(sort); setSortType(sort);
callList({ callList({
sortType: sort, sortType: sort
resetPage: true
}); });
}; };
const onClickSendingStatus = (val: LinkPaymentProcessStatus) => { const onClickSendingStatus = (val: LinkPaymentProcessStatus) => {
setProcessStatus(val); setProcessStatus(val);
callList({ callList({
status: val, status: val
resetPage: true
}); });
}; };
useEffect(() => { useEffect(() => {
// 필터 조건이 변경되면 첫 페이지부터 다시 시작 callList();
callList({ resetPage: true });
}, [ }, [
mid, mid,
searchType, searchType,
@@ -212,7 +168,6 @@ export const LinkPaymentWaitSendWrap = () => {
<LinkPaymentWaitList <LinkPaymentWaitList
listItems={listItems} listItems={listItems}
additionalServiceCategory={AdditionalServiceCategory.LinkPaymentWait} additionalServiceCategory={AdditionalServiceCategory.LinkPaymentWait}
setTarget={setTarget}
mid={mid} mid={mid}
></LinkPaymentWaitList> ></LinkPaymentWaitList>
<div className="apply-row"> <div className="apply-row">

View File

@@ -71,6 +71,8 @@ export const ListDateGroup = ({
smsCl= { items[i]?.smsCl } smsCl= { items[i]?.smsCl }
onResendClick={ onResendClick } onResendClick={ onResendClick }
seq= { items[i]?.seq}
></ListItem> ></ListItem>
) )
} }

View File

@@ -28,6 +28,7 @@ export const ListItem = ({
paymentMethod, receiverName, paymentMethod, receiverName,
requestId,subReqId, requestId,subReqId,
buyerName,receiverInfo, buyerName,receiverInfo,
seq,
smsCl, smsCl,
name, name,
@@ -190,8 +191,7 @@ export const ListItem = ({
navigate(PATHS.additionalService.fundAccount.transferDetail, { navigate(PATHS.additionalService.fundAccount.transferDetail, {
state: { state: {
additionalServiceCategory: additionalServiceCategory, additionalServiceCategory: additionalServiceCategory,
mid: mid, seq: seq
tid: tid
} }
}); });
} }

View File

@@ -6,37 +6,39 @@ export const SmsPaymentList = ({
listItems, listItems,
additionalServiceCategory, additionalServiceCategory,
mid, mid,
onResendClick, onResendClick
setTarget
}: SmsPaymentListProps) => { }: SmsPaymentListProps) => {
const getListDateGroup = () => { const getListDateGroup = () => {
let rs = []; let rs = [];
let date = ''; let date = '';
let list: SmsPaymentListItem[] = []; let list = [];
for (let i = 0; i < listItems.length; i++) { for (let i = 0; i < listItems.length; i++) {
let paymentDate = listItems[i]?.paymentDate || ''; let items = listItems[i];
let itemDate = paymentDate.substring(0, 8); if(!!items) {
if (i === 0) { let paymentDate = items?.paymentDate;
date = itemDate; paymentDate = paymentDate?.substring(0, 8);
if(!!paymentDate) {
if(i === 0) {
date = paymentDate;
} }
if (date !== itemDate) { if(date !== paymentDate) {
date = itemDate; date = paymentDate;
if (list.length > 0) { if(list.length > 0) {
rs.push( rs.push(
<ListDateGroup <ListDateGroup
additionalServiceCategory={additionalServiceCategory} additionalServiceCategory={additionalServiceCategory}
onResendClick={onResendClick} key={ date + '-' + i}
mid={mid} date={ date }
key={date + '-' + i} items={ list }
date={date}
items={list as any}
></ListDateGroup> ></ListDateGroup>
); );
} }
list = []; list = [];
} }
list.push(listItems[i] as any); list.push(items);
}
}
} }
if (list.length > 0) { if (list.length > 0) {
rs.push( rs.push(
@@ -46,7 +48,7 @@ export const SmsPaymentList = ({
mid={mid} mid={mid}
key={date + '-last'} key={date + '-last'}
date={date} date={date}
items={list as any} items={list}
></ListDateGroup> ></ListDateGroup>
); );
} }
@@ -57,7 +59,6 @@ export const SmsPaymentList = ({
<> <>
<section className="transaction-list"> <section className="transaction-list">
{getListDateGroup()} {getListDateGroup()}
<div ref={setTarget}></div>
</section> </section>
</> </>
) )

View File

@@ -18,12 +18,12 @@ export const EmailBottomSheet = ({
sendEmail, sendEmail,
sendRequest sendRequest
}: EmailBottomSheetProps) => { }: EmailBottomSheetProps) => {
const [userEmail, setUserEmail] = useState<string>('');
const emailList = [ const emailList = [
{name: 'test1@nicepay.co.kr', value: 'test1@nicepay.co.kr'}, {name: 'test1@nicepay.co.kr', value: 'test1@nicepay.co.kr'},
{name: 'test2@nicepay.co.kr', value: 'test2@nicepay.co.kr'}, {name: 'test2@nicepay.co.kr', value: 'test2@nicepay.co.kr'},
{name: 'test3@nicepay.co.kr', value: 'test3@nicepay.co.kr'}, {name: 'test3@nicepay.co.kr', value: 'test3@nicepay.co.kr'},
]; ];
const [userEmail, setUserEmail] = useState<string>(emailList[0]?.value || '');
const onClickToClose = () => { const onClickToClose = () => {
setBottomSheetOn(false); setBottomSheetOn(false);
}; };

View File

@@ -1,4 +1,4 @@
import { useState, useRef, useEffect, ChangeEvent } from 'react'; import { useState } from 'react';
import { PATHS } from '@/shared/constants/paths'; import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate'; import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { HeaderType } from '@/entities/common/model/types'; import { HeaderType } from '@/entities/common/model/types';
@@ -10,7 +10,7 @@ import {
} from '@/widgets/sub-layout/use-sub-layout'; } from '@/widgets/sub-layout/use-sub-layout';
import { useUserChangeCancelPasswordMutation } from '@/entities/user/api/use-user-change-cancel-password-mutation'; import { useUserChangeCancelPasswordMutation } from '@/entities/user/api/use-user-change-cancel-password-mutation';
import { useStore } from '@/shared/model/store'; import { useStore } from '@/shared/model/store';
import { XKeypad, XKeypadManager, createPasswordKeypad } from '@/utils/xkeypad'; import { snackBar } from '@/shared/lib/toast';
export const PasswordModifyCancelPasswordPage = () => { export const PasswordModifyCancelPasswordPage = () => {
const { navigate } = useNavigate(); const { navigate } = useNavigate();
@@ -20,69 +20,20 @@ export const PasswordModifyCancelPasswordPage = () => {
const [mid, setMid] = useState<string>(userMid); const [mid, setMid] = useState<string>(userMid);
const [password, setPassword] = useState<string>(''); const [password, setPassword] = useState<string>('');
const [confirmPassword, setConfirmPassword] = useState<string>(''); const [confirmPassword, setConfirmPassword] = useState<string>('');
const [isKeypadLoaded, setIsKeypadLoaded] = useState(false);
// Input refs for xkeypad
const passwordInputRef = useRef<HTMLInputElement>(null);
const confirmPasswordInputRef = useRef<HTMLInputElement>(null);
// XKeypad instances
const passwordKeypadRef = useRef<XKeypad | null>(null);
const confirmPasswordKeypadRef = useRef<XKeypad | null>(null);
// RSA Keys (실제 프로덕션에서는 서버에서 받아와야 함)
const RSA_MODULUS = "C4F7B39E2E93DB19C016C7A0C1C05B028A1D57CB9B91E13F5B7353F8FB5AC6CE6BE31ABEB8E8F7AD18B90C08F4EBC011A6A8FCE614EA879ED5B96296B969CE92923BC9BAD6FD87F00E08F529F93010EA77E40937BDAC1C866E79ACE2F2822A3ECD982F90532D5301CF90D9BF89E953A0593AB6C5F31E99B690DD582FB85F85A9";
const RSA_EXPONENT = "10001";
const changeCancelPasswordMutation = useUserChangeCancelPasswordMutation({ const changeCancelPasswordMutation = useUserChangeCancelPasswordMutation({
onSuccess: () => { onSuccess: () => {
// snackBar('비밀번호가 성공적으로 변경되었습니다.'); snackBar('비밀번호가 성공적으로 변경되었습니다.');
// Clear form and keypads // Clear form
setPassword(''); setPassword('');
setConfirmPassword(''); setConfirmPassword('');
if (passwordKeypadRef.current) passwordKeypadRef.current.clear();
if (confirmPasswordKeypadRef.current) confirmPasswordKeypadRef.current.clear();
if (passwordInputRef.current) passwordInputRef.current.value = '';
if (confirmPasswordInputRef.current) confirmPasswordInputRef.current.value = '';
// Navigate back // Navigate back
navigate(PATHS.account.password.manage); navigate(PATHS.account.password.manage);
}, },
onError: (error) => { onError: (error) => {
// snackBar(error?.response?.data?.message || '비밀번호 변경에 실패했습니다.'); snackBar(error?.response?.data?.message || '비밀번호 변경에 실패했습니다.');
} }
}); });
// Initialize XKeypad
useEffect(() => {
const initializeKeypad = async () => {
try {
const manager = XKeypadManager.getInstance({
modulus: RSA_MODULUS,
exponent: RSA_EXPONENT
});
await manager.loadScripts();
// RSA 키 설정을 명시적으로 다시 한번 수행
manager.setRSAPublicKey(RSA_MODULUS, RSA_EXPONENT);
setIsKeypadLoaded(true);
} catch (error) {
console.error('Failed to load XKeypad:', error);
}
};
initializeKeypad();
return () => {
// Cleanup keypads on unmount
if (passwordKeypadRef.current) {
passwordKeypadRef.current.destroy();
}
if (confirmPasswordKeypadRef.current) {
confirmPasswordKeypadRef.current.destroy();
}
};
}, []);
useSetHeaderTitle('거래취소 비밀번호 변경'); useSetHeaderTitle('거래취소 비밀번호 변경');
useSetHeaderType(HeaderType.LeftArrow); useSetHeaderType(HeaderType.LeftArrow);
@@ -100,97 +51,10 @@ export const PasswordModifyCancelPasswordPage = () => {
); );
}; };
// Handle password keypad
const handlePasswordKeypad = async () => {
if (!passwordInputRef.current || !isKeypadLoaded) return;
// Close other keypad if open
if (confirmPasswordKeypadRef.current) {
confirmPasswordKeypadRef.current.close();
}
// Create or initialize password keypad
if (!passwordKeypadRef.current) {
passwordKeypadRef.current = createPasswordKeypad(passwordInputRef.current, {
keyType: 'qwertysmart',
viewType: 'half',
maxInputSize: 16,
useOverlay: true,
useModal: false,
hasPressEffect: true,
isE2E: false, // E2E 모드 비활성화
onInputChange: (length: number) => {
// Update password state as typing
if (passwordKeypadRef.current) {
const plainText = passwordKeypadRef.current.getPlainText();
console.log('passwordKeypadRef:', plainText, passwordInputRef.current?.value);
setPassword(plainText);
}
},
onKeypadClose: () => {
// Final update when keypad closes
if (passwordKeypadRef.current) {
const plainText = passwordKeypadRef.current.getPlainText();
setPassword(plainText);
}
}
});
}
const result = await passwordKeypadRef.current.initialize(passwordInputRef.current);
if (result !== 0) {
console.error('Failed to initialize password keypad');
}
};
// Handle confirm password keypad
const handleConfirmPasswordKeypad = async () => {
if (!confirmPasswordInputRef.current || !isKeypadLoaded) return;
// Close other keypad if open
if (passwordKeypadRef.current) {
passwordKeypadRef.current.close();
}
// Create or initialize confirm password keypad
if (!confirmPasswordKeypadRef.current) {
confirmPasswordKeypadRef.current = createPasswordKeypad(confirmPasswordInputRef.current, {
keyType: 'qwertysmart',
viewType: 'half',
maxInputSize: 16,
useOverlay: true,
useModal: false,
hasPressEffect: true,
isE2E: false, // E2E 모드 비활성화
onInputChange: (length: number) => {
// Update confirm password state as typing
if (confirmPasswordKeypadRef.current) {
const plainText = confirmPasswordKeypadRef.current.getPlainText();
console.log('confirmPasswordKeypadRef:', plainText, confirmPasswordInputRef.current?.value);
setConfirmPassword(plainText);
}
},
onKeypadClose: () => {
// Final update when keypad closes
if (confirmPasswordKeypadRef.current) {
const plainText = confirmPasswordKeypadRef.current.getPlainText();
setConfirmPassword(plainText);
}
}
});
}
const result = await confirmPasswordKeypadRef.current.initialize(confirmPasswordInputRef.current);
if (result !== 0) {
console.error('Failed to initialize confirm password keypad');
}
};
// 저장 버튼 클릭 핸들러 // 저장 버튼 클릭 핸들러
const handleSave = () => { const handleSave = () => {
if (!isFormValid()) return; if (!isFormValid()) return;
// 평문 비밀번호 사용 (E2E 모드가 꺼져있으므로)
changeCancelPasswordMutation.mutate({ changeCancelPasswordMutation.mutate({
mid, mid,
password: password password: password
@@ -208,15 +72,15 @@ export const PasswordModifyCancelPasswordPage = () => {
<div className="ua-label"> <span className="red">*</span></div> <div className="ua-label"> <span className="red">*</span></div>
<select <select
className="wid-100" className="wid-100"
value={ mid } value={mid}
onChange={ (e: ChangeEvent<HTMLSelectElement>) => setMid(e.target.value) } onChange={(e) => setMid(e.target.value)}
> >
{ {
midOptions.map((value, index) => ( midOptions.map((value) => (
<option <option
key={ value.value } key={value.value}
value={ value.value } value={value.value}
>{ value.name }</option> >{value.name}</option>
)) ))
} }
</select> </select>
@@ -224,27 +88,21 @@ export const PasswordModifyCancelPasswordPage = () => {
<div className="ua-row"> <div className="ua-row">
<div className="ua-label"> <span className="red">*</span></div> <div className="ua-label"> <span className="red">*</span></div>
<input <input
ref={passwordInputRef}
className={`wid-100 ${confirmPassword && password !== confirmPassword ? 'error' : ''}`} className={`wid-100 ${confirmPassword && password !== confirmPassword ? 'error' : ''}`}
type="password" type="password"
placeholder="클릭하여 비밀번호 입력" placeholder="비밀번호 입력하세요"
value={password} value={password}
onClick={handlePasswordKeypad} onChange={(e) => setPassword(e.target.value)}
readOnly
style={{ cursor: 'pointer' }}
/> />
</div> </div>
<div className="ua-row"> <div className="ua-row">
<div className="ua-label"> <span className="red">*</span></div> <div className="ua-label"> <span className="red">*</span></div>
<input <input
ref={confirmPasswordInputRef}
className={`wid-100 ${confirmPassword && password !== confirmPassword ? 'error' : ''}`} className={`wid-100 ${confirmPassword && password !== confirmPassword ? 'error' : ''}`}
type="password" type="password"
placeholder="클릭하여 비밀번호 재입력" placeholder="비밀번호를 다시 입력하세요"
value={confirmPassword} value={confirmPassword}
onClick={handleConfirmPasswordKeypad} onChange={(e) => setConfirmPassword(e.target.value)}
readOnly
style={{ cursor: 'pointer' }}
/> />
</div> </div>
{confirmPassword && password !== confirmPassword && ( {confirmPassword && password !== confirmPassword && (

View File

@@ -9,6 +9,7 @@ import {
useSetOnBack useSetOnBack
} from '@/widgets/sub-layout/use-sub-layout'; } from '@/widgets/sub-layout/use-sub-layout';
import { useUserChangePasswordMutation } from '@/entities/user/api/use-user-change-password-mutation'; import { useUserChangePasswordMutation } from '@/entities/user/api/use-user-change-password-mutation';
import { snackBar } from '@/shared/lib/toast';
export const PasswordModifyLoginPasswordPage = () => { export const PasswordModifyLoginPasswordPage = () => {
const { navigate } = useNavigate(); const { navigate } = useNavigate();
@@ -19,7 +20,7 @@ export const PasswordModifyLoginPasswordPage = () => {
const changePasswordMutation = useUserChangePasswordMutation({ const changePasswordMutation = useUserChangePasswordMutation({
onSuccess: () => { onSuccess: () => {
// snackBar('비밀번호가 성공적으로 변경되었습니다.'); snackBar('비밀번호가 성공적으로 변경되었습니다.');
// Clear form // Clear form
setCurrentPassword(''); setCurrentPassword('');
setNewPassword(''); setNewPassword('');
@@ -28,7 +29,7 @@ export const PasswordModifyLoginPasswordPage = () => {
navigate(PATHS.account.password.manage); navigate(PATHS.account.password.manage);
}, },
onError: (error) => { onError: (error) => {
// snackBar(error?.response?.data?.message || '비밀번호 변경에 실패했습니다.'); snackBar(error?.response?.data?.message || '비밀번호 변경에 실패했습니다.');
} }
}); });

View File

@@ -12,6 +12,7 @@ import { VerificationItem } from '@/entities/account/model/types';
import { useUserCreateMutation } from '@/entities/user/api/use-user-create-mutation'; import { useUserCreateMutation } from '@/entities/user/api/use-user-create-mutation';
import { useUserExistsUseridQuery } from '@/entities/user/api/use-user-exists-userid-query'; import { useUserExistsUseridQuery } from '@/entities/user/api/use-user-exists-userid-query';
import { useLocation } from 'react-router'; import { useLocation } from 'react-router';
import { snackBar } from '@/shared/lib/toast';
export const UserAddAccountPage = () => { export const UserAddAccountPage = () => {
const { navigate } = useNavigate(); const { navigate } = useNavigate();
@@ -20,10 +21,10 @@ export const UserAddAccountPage = () => {
const { mutateAsync: userCreate, isPending } = useUserCreateMutation({ const { mutateAsync: userCreate, isPending } = useUserCreateMutation({
onSuccess: () => { onSuccess: () => {
// snackBar('사용자가 성공적으로 추가되었습니다.'); snackBar('사용자가 성공적으로 추가되었습니다.');
}, },
onError: (error) => { onError: (error) => {
// snackBar(error?.response?.data?.message || '사용자 추가에 실패했습니다.'); snackBar(error?.response?.data?.message || '사용자 추가에 실패했습니다.');
} }
}); });
@@ -381,7 +382,7 @@ export const UserAddAccountPage = () => {
if (response.status) { if (response.status) {
// 성공 시 사용자 관리 페이지로 이동 // 성공 시 사용자 관리 페이지로 이동
// snackBar('사용자가 성공적으로 추가되었습니다.'); snackBar('사용자가 성공적으로 추가되었습니다.');
navigate(PATHS.account.user.manage); navigate(PATHS.account.user.manage);
} else if (response.error) { } else if (response.error) {
// 에러 처리 // 에러 처리
@@ -409,7 +410,7 @@ export const UserAddAccountPage = () => {
<main> <main>
<div className="tab-content"> <div className="tab-content">
<div className="tab-pane sub active"> <div className="tab-pane sub active">
<div className="ing-list add"> <div className="ing-list pb-86">
<div className="user-add"> <div className="user-add">
<div className="ua-row"> <div className="ua-row">
<div className="ua-label">ID <span className="red">*</span></div> <div className="ua-label">ID <span className="red">*</span></div>
@@ -537,7 +538,7 @@ export const UserAddAccountPage = () => {
</div> </div>
</div> </div>
<div className="apply-row bottom-padding"> <div className="apply-row">
<button <button
className="btn-50 btn-blue flex-1" className="btn-50 btn-blue flex-1"
type="button" type="button"

View File

@@ -12,7 +12,7 @@ import { useLocation } from 'react-router';
import { useUserMenuPermissionsSaveMutation } from '@/entities/user/api/use-user-menu-permission-save-mutation'; import { useUserMenuPermissionsSaveMutation } from '@/entities/user/api/use-user-menu-permission-save-mutation';
// import { useUserMenuPermissionsMutation } from '@/entities/user/api/use-user-menu-permission-mutation'; // import { useUserMenuPermissionsMutation } from '@/entities/user/api/use-user-menu-permission-mutation';
import { UserMenuPermissionData } from '@/entities/user/model/types'; import { UserMenuPermissionData } from '@/entities/user/model/types';
//import { snackBar } from '@/shared/lib/toast'; import { snackBar } from '@/shared/lib/toast';
// 권한 비트 플래그 (실제 API 데이터 기준) // 권한 비트 플래그 (실제 API 데이터 기준)
const PERMISSION = { const PERMISSION = {
@@ -35,7 +35,7 @@ export const UserMenuAuthPage = () => {
const [isInitialLoad, setIsInitialLoad] = useState(true); const [isInitialLoad, setIsInitialLoad] = useState(true);
const savePermissionsMutation = useUserMenuPermissionsSaveMutation({ const savePermissionsMutation = useUserMenuPermissionsSaveMutation({
onSuccess: () => { onSuccess: () => {
//snackBar('권한이 성공적으로 저장되었습니다.'); snackBar('권한이 성공적으로 저장되었습니다.');
navigate(PATHS.account.user.accountAuth, { navigate(PATHS.account.user.accountAuth, {
state: { state: {
mid, mid,
@@ -46,7 +46,7 @@ export const UserMenuAuthPage = () => {
}); });
}, },
onError: (error) => { onError: (error) => {
// snackBar(error?.response?.data?.message || '권한 저장에 실패했습니다.'); snackBar(error?.response?.data?.message || '권한 저장에 실패했습니다.');
} }
}); });
@@ -181,7 +181,7 @@ export const UserMenuAuthPage = () => {
{ mid, namsUserMenuAccess }, { mid, namsUserMenuAccess },
{ {
onSuccess: () => { onSuccess: () => {
alert('권한이 저장되었습니다.'); snackBar('권한이 저장되었습니다.');
// 저장 성공 후 초기값 업데이트 // 저장 성공 후 초기값 업데이트
setInitialPermissions({...permissions}); setInitialPermissions({...permissions});
setHasChanges(false); setHasChanges(false);
@@ -199,7 +199,7 @@ export const UserMenuAuthPage = () => {
<main> <main>
<div className="tab-content"> <div className="tab-content">
<div className="tab-pane pt-46 active"> <div className="tab-pane pt-46 active">
<div className="ing-list sev"> <div className="ing-list pb-86">
<div className="desc service-tip"> .</div> <div className="desc service-tip"> .</div>
<div className="desc service-tip"> .</div> <div className="desc service-tip"> .</div>
@@ -281,6 +281,7 @@ export const UserMenuAuthPage = () => {
</div> </div>
); );
})} })}
</div>
<div className="apply-row"> <div className="apply-row">
<button <button
@@ -294,7 +295,6 @@ export const UserMenuAuthPage = () => {
</div> </div>
</div> </div>
</div> </div>
</div>
</main> </main>
</> </>
); );

View File

@@ -1,7 +1,7 @@
import moment from 'moment'; import moment from 'moment';
import { PATHS } from '@/shared/constants/paths'; import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate'; import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { HeaderType } from '@/entities/common/model/types'; import { DefaultRequestPagination, HeaderType } from '@/entities/common/model/types';
import { IMAGE_ROOT } from '@/shared/constants/common'; import { IMAGE_ROOT } from '@/shared/constants/common';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { DEFAULT_PAGE_PARAM } from '@/entities/common/model/constant'; import { DEFAULT_PAGE_PARAM } from '@/entities/common/model/constant';
@@ -19,21 +19,24 @@ import { AccountHolderAuthList } from '@/entities/additional-service/ui/account-
import { useExtensionAccountHolderAuthDownloadExcelMutation } from '@/entities/additional-service/api/account-holder-auth/use-extension-account-holder-auth-download-excel-mutation'; import { useExtensionAccountHolderAuthDownloadExcelMutation } from '@/entities/additional-service/api/account-holder-auth/use-extension-account-holder-auth-download-excel-mutation';
import { AccountHolderAuthFilter } from '@/entities/additional-service/ui/account-holder-auth/filter/account-holder-auth-filter'; import { AccountHolderAuthFilter } from '@/entities/additional-service/ui/account-holder-auth/filter/account-holder-auth-filter';
import { useStore } from '@/shared/model/store'; import { useStore } from '@/shared/model/store';
import { AccountHolderAuthListItem, AuthAndTransferStatus } from '@/entities/additional-service/model/account-holder-auth/types'; import { AccountHolderAuthListItem, AuthAndTransferStatus, 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';
export const AccountHolderAuthPage = () => { export const AccountHolderAuthPage = () => {
const { navigate } = useNavigate(); const { navigate } = useNavigate();
const userMid = useStore.getState().UserStore.mid; const userMid = useStore.getState().UserStore.mid;
const [sortType, setSortType] = useState<SortTypeKeys>(SortTypeKeys.LATEST); const [sortType, setSortType] = useState<SortTypeKeys>(SortTypeKeys.LATEST);
const [listItems, setListItems] = useState({}); const [listItems, setListItems] = useState<Array<ExtensionAccountHolderAuthContentItem>>([]);
const [filterOn, setFilterOn] = useState<boolean>(false); const [filterOn, setFilterOn] = useState<boolean>(false);
const [pageParam, setPageParam] = useState(DEFAULT_PAGE_PARAM); const [pageParam, setPageParam] = useState<DefaultRequestPagination>(DEFAULT_PAGE_PARAM);
const [mid, setMid] = useState<string>(userMid); const [mid, setMid] = useState<string>(userMid);
const [fromDate, setFromDate] = useState(moment().format('YYYY-MM-DD')); const [fromDate, setFromDate] = useState(moment().format('YYYYMMDD'));
const [toDate, setToDate] = useState(moment().format('YYYY-MM-DD')); const [toDate, setToDate] = useState(moment().format('YYYYMMDD'));
const [authStatus, setAuthStatus] = useState<AuthAndTransferStatus>(AuthAndTransferStatus.ALL) const [authStatus, setAuthStatus] = useState<AuthAndTransferStatus>(AuthAndTransferStatus.ALL)
const [emailBottomSheetOn, setEmailBottomSheetOn] = useState<boolean>(false);
useSetHeaderTitle('계좌점유인증'); useSetHeaderTitle('계좌점유인증');
useSetHeaderType(HeaderType.LeftArrow); useSetHeaderType(HeaderType.LeftArrow);
useSetFooterMode(false); useSetFooterMode(false);
@@ -43,12 +46,11 @@ export const AccountHolderAuthPage = () => {
const { mutateAsync: accountHolderAuthList } = useExtensionAccountHolderAuthListMutation(); const { mutateAsync: accountHolderAuthList } = useExtensionAccountHolderAuthListMutation();
const { mutateAsync: downloadExcel } = useExtensionAccountHolderAuthDownloadExcelMutation(); const { mutateAsync: downloadExcel } = useExtensionAccountHolderAuthDownloadExcelMutation();
const callList = (option?: { const callList = (option?: {
sortType?: SortTypeKeys, sortType?: SortTypeKeys,
val?: string status?: AuthAndTransferStatus
}) => { }) => {
pageParam.sortType = (option?.sortType)? option.sortType: sortType;
setPageParam(pageParam);
let listParams = { let listParams = {
mid: mid, mid: mid,
fromDate: fromDate, fromDate: fromDate,
@@ -57,28 +59,14 @@ export const AccountHolderAuthPage = () => {
page: pageParam page: pageParam
}; };
accountHolderAuthList(listParams).then((rs) => { if (listParams.page) {
setListItems(assembleData(rs.content)); listParams.page.sortType = option?.sortType || sortType;
}); setPageParam(listParams.page);
} }
const assembleData = (content: Array<AccountHolderAuthListItem>) => { accountHolderAuthList(listParams).then((rs) => {
console.log('rs.content:', content) setListItems(rs.content);
let data: any = {}; });
if (content && content.length > 0) {
for (let i = 0; i < content?.length; i++) {
let requestDate = content[i]?.requestDate?.substring(0, 8);
let groupDate = moment(requestDate).format('YYYYMMDD');
if(!!groupDate && !data.hasOwnProperty(groupDate)){
data[groupDate] = [];
}
if(!!groupDate && data.hasOwnProperty(groupDate)){
data[groupDate].push(content[i]);
}
}
}
console.log('Data : ', data);
return data;
}; };
const onClickToDownloadExcel = () => { const onClickToDownloadExcel = () => {
@@ -100,18 +88,45 @@ export const AccountHolderAuthPage = () => {
setSortType(sort); setSortType(sort);
callList({ callList({
sortType: sort sortType: sort
}) });
}; };
const onClickToAuthStatus = (val: AuthAndTransferStatus) => { const onClickToAuthStatus = (val: AuthAndTransferStatus) => {
setAuthStatus(val); setAuthStatus(val);
callList({ val: val }); callList({
status: val
});
};
const onClickToOpenEmailBottomSheet = () => {
setEmailBottomSheetOn(true);
};
const onSendRequest = (selectedEmail?: string) => {
if (selectedEmail) {
const params: ExtensionAccountHolderAuthDownloadExcelParams = { // 추후 수정필요
mid: mid,
//email: selectedEmail,
fromDate: fromDate,
toDate: toDate,
authStatus: authStatus
};
downloadExcel(params).then((rs: ExtensionAccountHolderAuthDownloadExcelResponse) => {
console.log('Excel Download Status:', rs.status);
});
}
setEmailBottomSheetOn(false);
}; };
useEffect(() => { useEffect(() => {
callList(); callList();
}, []); }, [
mid,
fromDate,
toDate,
authStatus
]);
return ( return (
<> <>
@@ -152,8 +167,8 @@ export const AccountHolderAuthPage = () => {
<div className="filter-section"> <div className="filter-section">
<SortTypeBox <SortTypeBox
sortType={ sortType } sortType={sortType}
onClickToSort={ onClickToSort } onClickToSort={onClickToSort}
></SortTypeBox> ></SortTypeBox>
<div className="excrow"> <div className="excrow">
<div className="full-menu-keywords no-padding"> <div className="full-menu-keywords no-padding">
@@ -170,6 +185,7 @@ export const AccountHolderAuthPage = () => {
</div> </div>
</div> </div>
<AccountHolderAuthList <AccountHolderAuthList
additionalServiceCategory={AdditionalServiceCategory.AccountHolderAuth}
listItems={listItems} listItems={listItems}
mid={mid} mid={mid}
></AccountHolderAuthList> ></AccountHolderAuthList>
@@ -189,6 +205,14 @@ export const AccountHolderAuthPage = () => {
setAuthStatus={setAuthStatus} setAuthStatus={setAuthStatus}
> >
</AccountHolderAuthFilter> </AccountHolderAuthFilter>
<EmailBottomSheet
bottomSheetOn={emailBottomSheetOn}
setBottomSheetOn={setEmailBottomSheetOn}
imageSave={false}
sendEmail={true}
sendRequest={onSendRequest}
/>
</> </>
); );
}; };

View File

@@ -21,37 +21,16 @@ import { AccountHolderSearchList } from '@/entities/additional-service/ui/accoun
import { useStore } from '@/shared/model/store'; import { useStore } from '@/shared/model/store';
import { AccountHolderSearchListItem, AccountHolderSearchType } from '@/entities/additional-service/model/account-holder-search/types'; import { AccountHolderSearchListItem, AccountHolderSearchType } from '@/entities/additional-service/model/account-holder-search/types';
import { resultStatusBtnGroup } from '@/entities/additional-service/model/account-holder-search/constant'; import { resultStatusBtnGroup } from '@/entities/additional-service/model/account-holder-search/constant';
import useIntersectionObserver from '@/widgets/intersection-observer'; import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet';
export const AccountHolderSearchPage = () => { export const AccountHolderSearchPage = () => {
const { navigate } = useNavigate(); const { navigate } = useNavigate();
const [onActionIntersect, setOnActionIntersect] = useState<boolean>(false);
const onIntersect: IntersectionObserverCallback = (entries: Array<IntersectionObserverEntry>) => {
entries.forEach((entry: IntersectionObserverEntry) => {
if (entry.isIntersecting) {
console.log('Element is now intersecting with the root. [' + onActionIntersect + ']');
if (onActionIntersect) {
callList();
}
}
else {
console.log('Element is no longer intersecting with the root.');
}
});
};
const { setTarget } = useIntersectionObserver({
threshold: 1,
onIntersect
});
const userMid = useStore.getState().UserStore.mid; const userMid = useStore.getState().UserStore.mid;
const [sortType, setSortType] = useState<SortTypeKeys>(SortTypeKeys.LATEST); const [sortType, setSortType] = useState<SortTypeKeys>(SortTypeKeys.LATEST);
const [listItems, setListItems] = useState<Array<AccountHolderSearchListItem>>([]); const [listItems, setListItems] = useState<Array<AccountHolderSearchListItem>>([]);
const [pageParam, setPageParam] = useState<DefaultRequestPagination>(DEFAULT_PAGE_PARAM); const [pageParam, setPageParam] = useState<DefaultRequestPagination>(DEFAULT_PAGE_PARAM);
const [nextCursor, setNextCursor] = useState<string | null>(null);
const [filterOn, setFilterOn] = useState<boolean>(false); const [filterOn, setFilterOn] = useState<boolean>(false);
const [mid, setMid] = useState<string>(userMid); const [mid, setMid] = useState<string>(userMid);
const [searchType, setSearchType] = useState<AccountHolderSearchType>(AccountHolderSearchType.ACCOUNT_NAME) const [searchType, setSearchType] = useState<AccountHolderSearchType>(AccountHolderSearchType.ACCOUNT_NAME)
@@ -60,6 +39,8 @@ export const AccountHolderSearchPage = () => {
const [endDate, setEndDate] = useState(moment().format('YYYYMMDD')); const [endDate, setEndDate] = useState(moment().format('YYYYMMDD'));
const [bank, setBank] = useState<string>(''); const [bank, setBank] = useState<string>('');
const [processResult, setProcessResult] = useState<ProcessResult>(ProcessResult.ALL); const [processResult, setProcessResult] = useState<ProcessResult>(ProcessResult.ALL);
const [emailBottomSheetOn, setEmailBottomSheetOn] = useState<boolean>(false);
const [email, setEmail] = useState<string>('');
useSetHeaderTitle('계좌성명조회'); useSetHeaderTitle('계좌성명조회');
useSetHeaderType(HeaderType.LeftArrow); useSetHeaderType(HeaderType.LeftArrow);
@@ -73,17 +54,8 @@ export const AccountHolderSearchPage = () => {
const callList = (option?: { const callList = (option?: {
sortType?: SortTypeKeys, sortType?: SortTypeKeys,
processResult?: ProcessResult, processResult?: ProcessResult
resetPage?: boolean
}) => { }) => {
setOnActionIntersect(false);
const currentPageParam = option?.resetPage
? { ...DEFAULT_PAGE_PARAM, sortType: option?.sortType ?? sortType }
: { ...pageParam, sortType: option?.sortType ?? sortType };
setPageParam(currentPageParam);
let listParams = { let listParams = {
mid: mid, mid: mid,
searchCl: searchType, searchCl: searchType,
@@ -92,27 +64,16 @@ export const AccountHolderSearchPage = () => {
toDate: endDate, toDate: endDate,
bankCode: bank, bankCode: bank,
resultStatus: option?.processResult ?? processResult, resultStatus: option?.processResult ?? processResult,
... { page: pageParam
page: currentPageParam
} }
if (listParams.page) {
listParams.page.sortType = option?.sortType || sortType;
setPageParam(listParams.page);
} }
accountHolderSearchList(listParams).then((rs) => { accountHolderSearchList(listParams).then((rs) => {
setListItems(option?.resetPage ? rs.content : [ setListItems(rs.content);
...listItems,
...rs.content
]);
if (rs.hasNext) {
setNextCursor(rs.nextCursor);
setPageParam({
...currentPageParam,
cursor: rs.nextCursor
});
setOnActionIntersect(true)
}
else {
setNextCursor(null);
}
}); });
} }
@@ -120,6 +81,30 @@ export const AccountHolderSearchPage = () => {
setFilterOn(!filterOn); setFilterOn(!filterOn);
}; };
const onClickToOpenEmailBottomSheet = () => {
setEmailBottomSheetOn(true);
};
const onSendRequest = (selectedEmail?: string) => {
if (selectedEmail) {
// 이메일을 설정한 후 다운로드 실행
downloadExcel({
mid: mid,
//email: selectedEmail,
searchCl: searchType,
searchValue: searchKeyword,
fromDate: startDate,
toDate: endDate,
bankCode: bank,
resultStatus: processResult
}).then((rs) => {
console.log('Excel Download Status: ' + rs.status);
});
}
setEmailBottomSheetOn(false);
};
const onClickToDownloadExcel = () => { const onClickToDownloadExcel = () => {
downloadExcel({ downloadExcel({
mid: mid, mid: mid,
@@ -137,22 +122,19 @@ export const AccountHolderSearchPage = () => {
const onClickToSort = (sort: SortTypeKeys) => { const onClickToSort = (sort: SortTypeKeys) => {
setSortType(sort); setSortType(sort);
callList({ callList({
sortType: sort, sortType: sort
resetPage: true
}); });
}; };
const onClickToTransactionStatus = (val: ProcessResult) => { const onClickToTransactionStatus = (val: ProcessResult) => {
setProcessResult(val); setProcessResult(val);
callList({ callList({
processResult: val, processResult: val
resetPage: true
}); });
}; };
useEffect(() => { useEffect(() => {
// 필터 조건이 변경되면 첫 페이지부터 다시 시작 callList();
callList({ resetPage: true });
}, [ }, [
mid, mid,
searchType, searchType,
@@ -190,11 +172,11 @@ export const AccountHolderSearchPage = () => {
</div> </div>
<button <button
className="download-btn" className="download-btn"
onClick={onClickToOpenEmailBottomSheet}
> >
<img <img
src={IMAGE_ROOT + '/ico_download.svg'} src={IMAGE_ROOT + '/ico_download.svg'}
alt="다운로드" alt="다운로드"
onClick={() => onClickToDownloadExcel()}
/> />
</button> </button>
</div> </div>
@@ -222,7 +204,6 @@ export const AccountHolderSearchPage = () => {
<AccountHolderSearchList <AccountHolderSearchList
listItems={listItems} listItems={listItems}
mid={mid} mid={mid}
setTarget={setTarget}
></AccountHolderSearchList> ></AccountHolderSearchList>
</div> </div>
</div> </div>
@@ -245,6 +226,14 @@ export const AccountHolderSearchPage = () => {
setBank={setBank} setBank={setBank}
setProcessResult={setProcessResult} setProcessResult={setProcessResult}
></AccountHolderSearchFilter> ></AccountHolderSearchFilter>
<EmailBottomSheet
bottomSheetOn={emailBottomSheetOn}
setBottomSheetOn={setEmailBottomSheetOn}
imageSave={false}
sendEmail={true}
sendRequest={onSendRequest}
/>
</> </>
); );
}; };

View File

@@ -19,7 +19,8 @@ import {
ExtensionAlimtalkDownloadExcelParams, ExtensionAlimtalkDownloadExcelParams,
ExtensionAlimtalkDownloadExcelResponse, ExtensionAlimtalkDownloadExcelResponse,
ExtensionAlimtalkListParams, ExtensionAlimtalkListParams,
ExtensionAlimtalkListResponse ExtensionAlimtalkListResponse,
ServiceCode
} from '@/entities/additional-service/model/alimtalk/types'; } from '@/entities/additional-service/model/alimtalk/types';
import moment from 'moment'; import moment from 'moment';
import { useExtensionAlimtalkListMutation } from '@/entities/additional-service/api/alimtalk/use-extansion-alimtalk-list-mutation'; import { useExtensionAlimtalkListMutation } from '@/entities/additional-service/api/alimtalk/use-extansion-alimtalk-list-mutation';
@@ -27,47 +28,29 @@ import { useExtensionAlimtalkDownloadExcelMutation } from '@/entities/additional
import { ListDateGroup } from '@/entities/additional-service/ui/list-date-group'; import { ListDateGroup } from '@/entities/additional-service/ui/list-date-group';
import { AdditionalServiceCategory } from '@/entities/additional-service/model/types'; import { AdditionalServiceCategory } from '@/entities/additional-service/model/types';
import { useStore } from '@/shared/model/store'; import { useStore } from '@/shared/model/store';
import useIntersectionObserver from '@/widgets/intersection-observer'; import { snackBar } from '@/shared/lib';
import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet';
import { AlimtalkFilter } from '@/entities/additional-service/ui/filter/alimtalk-filter';
export const AlimtalkListPage = () => { export const AlimtalkListPage = () => {
const { navigate } = useNavigate(); const { navigate } = useNavigate();
const userMid = useStore.getState().UserStore.mid; const userMid = useStore.getState().UserStore.mid;
const [onActionIntersect, setOnActionIntersect] = useState<boolean>(false);
const onIntersect: IntersectionObserverCallback = (entries: Array<IntersectionObserverEntry>) => {
entries.forEach((entry: IntersectionObserverEntry) => {
if (entry.isIntersecting) {
console.log('Element is now intersecting with the root. [' + onActionIntersect + ']');
if (onActionIntersect) {
callList();
}
}
else {
console.log('Element is no longer intersecting with the root.');
}
});
};
const { setTarget } = useIntersectionObserver({
threshold: 1,
onIntersect
});
const [sortType, setSortType] = useState<SortTypeKeys>(SortTypeKeys.LATEST); const [sortType, setSortType] = useState<SortTypeKeys>(SortTypeKeys.LATEST);
const [listItems, setListItems] = useState<Array<AlimtalkListContent>>([]); const [listItems, setListItems] = useState<Array<AlimtalkListContent>>([]);
const [filterOn, setFilterOn] = useState<boolean>(false); const [filterOn, setFilterOn] = useState<boolean>(false);
const [nextCursor, setNextCursor] = useState<string | null>(null);
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 [searchCl, setSearchCl] = useState<AlimtalkSearchCl>(AlimtalkSearchCl.BUYER_NAME); const [searchCl, setSearchCl] = useState<AlimtalkSearchCl>(AlimtalkSearchCl.BUYER_NAME);
const [searchValue, setSearchValue] = useState<string>(); const [searchValue, setSearchValue] = useState<string>('');
const [paymentMethod, setPaymentMethod] = useState<string>(); const [serviceCode, setServiceCode] = useState<ServiceCode>(ServiceCode.CARD);
const [alimCl, setAlimCl] = useState<AlimtalkAlimCl>(AlimtalkAlimCl.DEPOSIT_REQUEST); const [alimCl, setAlimCl] = useState<AlimtalkAlimCl>(AlimtalkAlimCl.DEPOSIT_REQUEST);
const [fromDate, setFromDate] = useState<string>(moment().format('YYYYMMDD')); const [fromDate, setFromDate] = useState<string>(moment().format('YYYYMMDD'));
const [toDate, setToDate] = useState<string>(moment().format('YYYYMMDD')); const [toDate, setToDate] = useState<string>(moment().format('YYYYMMDD'));
const [sendType, setSendType] = useState<AlimtalkSendType>(AlimtalkSendType.ALL); const [sendType, setSendType] = useState<AlimtalkSendType>(AlimtalkSendType.ALL);
const [sendCl, setSendCl] = useState<AlimTalkSendCl>(AlimTalkSendCl.ALL); const [sendCl, setSendCl] = useState<AlimTalkSendCl>(AlimTalkSendCl.ALL);
const [emailBottomSheetOn, setEmailBottomSheetOn] = useState<boolean>(false);
const { mutateAsync: extensionAlimtalkList } = useExtensionAlimtalkListMutation(); const { mutateAsync: extensionAlimtalkList } = useExtensionAlimtalkListMutation();
const { mutateAsync: extensionAlimtalkDownloadExcel } = useExtensionAlimtalkDownloadExcelMutation(); const { mutateAsync: extensionAlimtalkDownloadExcel } = useExtensionAlimtalkDownloadExcelMutation();
@@ -79,86 +62,81 @@ export const AlimtalkListPage = () => {
}); });
const callList = (option?: { const callList = (option?: {
sortType?: SortTypeKeys, sortType?: SortTypeKeys
resetPage?: boolean
}) => { }) => {
setOnActionIntersect(false);
const currentPageParam = option?.resetPage
? { ...DEFAULT_PAGE_PARAM, sortType: option?.sortType ?? sortType }
: { ...pageParam, sortType: option?.sortType ?? sortType };
setPageParam(currentPageParam);
let params: ExtensionAlimtalkListParams = { let params: ExtensionAlimtalkListParams = {
mid: mid, mid: mid,
searchCl: searchCl, searchCl: searchCl,
searchValue: searchValue, searchValue: searchValue,
serviceCode: paymentMethod, serviceCode: serviceCode,
fromDate: fromDate,
toDate: toDate,
sendType: sendType,
sendCl: sendCl,
page: currentPageParam
};
extensionAlimtalkList(params).then((rs: ExtensionAlimtalkListResponse) => {
setListItems(option?.resetPage ? rs.content : [
...listItems,
...rs.content
]);
if (rs.hasNext) {
setNextCursor(rs.nextCursor);
setPageParam({
...currentPageParam,
cursor: rs.nextCursor
});
setOnActionIntersect(true);
}
else {
setNextCursor(null);
}
});
};
const callDownloadExcel = () => {
let params: ExtensionAlimtalkDownloadExcelParams = {
mid: mid,
searchCl: searchCl,
searchValue: searchValue,
paymentMethod: paymentMethod,
alimCl: alimCl, alimCl: alimCl,
fromDate: fromDate, fromDate: fromDate,
toDate: toDate, toDate: toDate,
sendType: sendType, sendType: sendType,
sendCl: sendCl sendCl: sendCl,
page: pageParam
};
if (params.page) {
params.page.sortType = option?.sortType || sortType;
setPageParam(params.page);
}
extensionAlimtalkList(params).then((rs: ExtensionAlimtalkListResponse) => {
setListItems(rs.content);
});
};
const onClickToOpenEmailBottomSheet = () => {
setEmailBottomSheetOn(true);
}
const onSendRequest = (selectedEmail?: string) => {
if (selectedEmail) {
const params: ExtensionAlimtalkDownloadExcelParams = {
mid: mid,
searchCl: searchCl,
searchValue: searchValue,
serviceCode: serviceCode,
alimCl: alimCl,
fromDate: fromDate,
toDate: toDate,
sendType: sendType,
sendCl: sendCl,
//email: selectedEmail
}; };
extensionAlimtalkDownloadExcel(params).then((rs: ExtensionAlimtalkDownloadExcelResponse) => { extensionAlimtalkDownloadExcel(params).then((rs: ExtensionAlimtalkDownloadExcelResponse) => {
console.log('Excel Download Status:', rs.status);
}); });
}; };
setEmailBottomSheetOn(false);
};
const onClickToNavigate = () => { const onClickToNavigate = () => {
navigate(PATHS.additionalService.alimtalk.setting); navigate(PATHS.additionalService.alimtalk.setting);
}; };
const onClickToDownloadExcel = () => {
callDownloadExcel();
};
const onClickToOpenFilter = () => { const onClickToOpenFilter = () => {
setFilterOn(!filterOn); setFilterOn(!filterOn);
}; };
const getAlimtalkList = () => { const getAlimtalkList = () => {
let rs: JSX.Element[] = []; let rs = [];
let date = ''; let date = '';
let list: AlimtalkListContent[] = []; let list = [];
for (let i = 0; i < listItems.length; i++) { for (let i = 0; i < listItems.length; i++) {
let item = listItems[i];
if (!!item) {
// sendDate format: "20211018140420" (YYYYMMDDHHmmss) // sendDate format: "20211018140420" (YYYYMMDDHHmmss)
let sendDate = listItems[i]?.sendDate || ''; let sendDate = item?.sendDate || '';
let itemDate = sendDate.substring(0, 8); let itemDate = sendDate.substring(0, 8);
if (!!itemDate) {
if (i === 0) { if (i === 0) {
date = itemDate; date = itemDate;
} }
if (date !== itemDate) { if (date !== itemDate) {
// 날짜가 바뀌면 이전 리스트를 푸시 date = itemDate;
if (list.length > 0) { if (list.length > 0) {
rs.push( rs.push(
<ListDateGroup <ListDateGroup
@@ -170,10 +148,11 @@ export const AlimtalkListPage = () => {
></ListDateGroup> ></ListDateGroup>
); );
} }
date = itemDate;
list = []; list = [];
} }
list.push(listItems[i] as any); list.push(item);
}
}
} }
if (list.length > 0) { if (list.length > 0) {
rs.push( rs.push(
@@ -190,13 +169,13 @@ export const AlimtalkListPage = () => {
} }
useEffect(() => { useEffect(() => {
// 필터 조건이 변경되면 첫 페이지부터 다시 시작 callList();
callList({ resetPage: true });
}, [ }, [
mid, mid,
searchCl, searchCl,
searchValue, searchValue,
paymentMethod, serviceCode,
alimCl,
fromDate, fromDate,
toDate, toDate,
sendType, sendType,
@@ -214,16 +193,16 @@ export const AlimtalkListPage = () => {
<input <input
className="credit-period" className="credit-period"
type="text" type="text"
value={ moment(fromDate).format('YYYY.MM.DD') + '-' + moment(toDate).format('YYYY.MM.DD') } value={moment(fromDate).format('YYYY.MM.DD') + '-' + moment(toDate).format('YYYY.MM.DD')}
readOnly={ true } readOnly={true}
/> />
<button <button
className="filter-btn" className="filter-btn"
aria-label="필터" aria-label="필터"
onClick={ () => onClickToOpenFilter() } onClick={() => onClickToOpenFilter()}
> >
<img <img
src={ IMAGE_ROOT + '/ico_setting.svg' } src={IMAGE_ROOT + '/ico_setting.svg'}
alt="검색옵션" alt="검색옵션"
/> />
</button> </button>
@@ -231,10 +210,10 @@ export const AlimtalkListPage = () => {
<button <button
className="download-btn" className="download-btn"
aria-label="다운로드" aria-label="다운로드"
onClick={ () => onClickToDownloadExcel() } onClick={() => onClickToOpenEmailBottomSheet()}
> >
<img <img
src={ IMAGE_ROOT + '/ico_download.svg' } src={IMAGE_ROOT + '/ico_download.svg'}
alt="다운로드" alt="다운로드"
/> />
</button> </button>
@@ -242,8 +221,7 @@ export const AlimtalkListPage = () => {
</section> </section>
<section className="transaction-list"> <section className="transaction-list">
{ getAlimtalkList() } {getAlimtalkList()}
<div ref={setTarget}></div>
</section> </section>
</div> </div>
</div> </div>
@@ -251,9 +229,39 @@ export const AlimtalkListPage = () => {
<div className="apply-row"> <div className="apply-row">
<button <button
className="btn-50 btn-blue flex-1" className="btn-50 btn-blue flex-1"
onClick={ () => onClickToNavigate() } onClick={() => onClickToNavigate()}
> </button> > </button>
</div> </div>
<AlimtalkFilter
filterOn={filterOn}
setFilterOn={setFilterOn}
mid={mid}
searchCl={searchCl}
searchValue={searchValue}
fromDate={fromDate}
toDate={toDate}
serviceCode={serviceCode}
alimCl={alimCl}
sendType={sendType}
sendCl={sendCl}
setMid={setMid}
setSearchCl={setSearchCl}
setSearchValue={setSearchValue}
setFromDate={setFromDate}
setToDate={setToDate}
setServiceCode={setServiceCode}
setAlimCl={setAlimCl}
setSendType={setSendType}
setSendCl={setSendCl}
></AlimtalkFilter>
<EmailBottomSheet
bottomSheetOn={emailBottomSheetOn}
setBottomSheetOn={setEmailBottomSheetOn}
imageSave={false}
sendEmail={true}
sendRequest={onSendRequest}
>
</EmailBottomSheet>
</> </>
); );
}; };

View File

@@ -20,37 +20,15 @@ import { SortTypeBox } from '@/entities/common/ui/sort-type-box';
import { ArsPaymentStatusBtnGroup } from '@/entities/additional-service/model/ars/constant'; import { ArsPaymentStatusBtnGroup } from '@/entities/additional-service/model/ars/constant';
import { ArsFilter } from '@/entities/additional-service/ui/filter/ars-filter'; import { ArsFilter } from '@/entities/additional-service/ui/filter/ars-filter';
import { useStore } from '@/shared/model/store'; import { useStore } from '@/shared/model/store';
import useIntersectionObserver from '@/widgets/intersection-observer';
export const ArsListPage = () => { export const ArsListPage = () => {
const { navigate } = useNavigate(); const { navigate } = useNavigate();
const [onActionIntersect, setOnActionIntersect] = useState<boolean>(false);
const onIntersect: IntersectionObserverCallback = (entries: Array<IntersectionObserverEntry>) => {
entries.forEach((entry: IntersectionObserverEntry) => {
if (entry.isIntersecting) {
console.log('Element is now intersecting with the root. [' + onActionIntersect + ']');
if (onActionIntersect) {
callList();
}
}
else {
console.log('Element is no longer intersecting with the root.');
}
});
};
const { setTarget } = useIntersectionObserver({
threshold: 1,
onIntersect
});
const userMid = useStore.getState().UserStore.mid; const userMid = useStore.getState().UserStore.mid;
const [sortType, setSortType] = useState<SortTypeKeys>(SortTypeKeys.LATEST); const [sortType, setSortType] = useState<SortTypeKeys>(SortTypeKeys.LATEST);
const [listItems, setListItems] = useState<Array<ArsListContent>>([]); const [listItems, setListItems] = useState<Array<ArsListContent>>([]);
const [filterOn, setFilterOn] = useState<boolean>(false); const [filterOn, setFilterOn] = useState<boolean>(false);
const [nextCursor, setNextCursor] = useState<string | null>(null);
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 [moid, setMoid] = useState<string>(''); const [moid, setMoid] = useState<string>('');
@@ -73,17 +51,8 @@ export const ArsListPage = () => {
const callList = (option?: { const callList = (option?: {
sortType?: SortTypeKeys, sortType?: SortTypeKeys,
paymentStatus?: PaymentStatus, paymentStatus?: PaymentStatus
resetPage?: boolean
}) => { }) => {
setOnActionIntersect(false);
const currentPageParam = option?.resetPage
? { ...DEFAULT_PAGE_PARAM, sortType: option?.sortType ?? sortType }
: { ...pageParam, sortType: option?.sortType ?? sortType };
setPageParam(currentPageParam);
let params: ExtensionArsListParams = { let params: ExtensionArsListParams = {
mid: mid, mid: mid,
moid: moid, moid: moid,
@@ -93,25 +62,16 @@ export const ArsListPage = () => {
orderStatus: orderStatus, orderStatus: orderStatus,
minAmount: minAmount, minAmount: minAmount,
maxAmount: maxAmount, maxAmount: maxAmount,
page: currentPageParam page: pageParam
}; };
if (params.page) {
params.page.sortType = option?.sortType || sortType;
setPageParam(params.page);
}
extensionArsList(params).then((rs: ExtensionArsListResponse) => { extensionArsList(params).then((rs: ExtensionArsListResponse) => {
// resetPage면 기존 리스트 무시, 아니면 추가 setListItems(rs.content);
setListItems(option?.resetPage ? rs.content : [
...listItems,
...rs.content
]);
if (rs.hasNext) {
setNextCursor(rs.nextCursor);
setPageParam({
...currentPageParam,
cursor: rs.nextCursor
});
setOnActionIntersect(true)
}
else {
setNextCursor(null);
}
}); });
}; };
@@ -146,21 +106,21 @@ export const ArsListPage = () => {
const onClickToSort = (sort: SortTypeKeys) => { const onClickToSort = (sort: SortTypeKeys) => {
setSortType(sort); setSortType(sort);
callList({ callList({
sortType: sort, sortType: sort
resetPage: true
}); });
}; };
const onClickToPaymentStatus = (val: PaymentStatus) => { const onClickToPaymentStatus = (val: PaymentStatus) => {
setPaymentStatus(val); setPaymentStatus(val);
callList({ callList({
paymentStatus: val, paymentStatus: val
resetPage: true
}); });
}; };
useEffect(() => { useEffect(() => {
// 필터 조건이 변경되면 첫 페이지부터 다시 시작 callList();
callList({ resetPage: true }); }, []);
useEffect(() => {
callList();
}, [ }, [
mid, mid,
moid, moid,
@@ -173,18 +133,20 @@ export const ArsListPage = () => {
]); ]);
const getListDateGroup = () => { const getListDateGroup = () => {
let rs: JSX.Element[] = []; let rs = [];
let date = ''; let date = '';
let list: ArsListContent[] = []; let list = [];
for (let i = 0; i < listItems.length; i++) { for (let i = 0; i < listItems.length; i++) {
// paymentDate format: "20211018140420" (YYYYMMDDHHmmss) let item = listItems[i];
let paymentDate = listItems[i]?.paymentDate || ''; if (!!item) {
let paymentDate = item?.paymentDate || '';
let itemDate = paymentDate.substring(0, 8); let itemDate = paymentDate.substring(0, 8);
if (!!itemDate) {
if (i === 0) { if (i === 0) {
date = itemDate; date = itemDate;
} }
if (date !== itemDate) { if (date !== itemDate) {
// 날짜가 바뀌면 이전 리스트를 푸시 (날짜 업데이트 전에!) date = itemDate;
if (list.length > 0) { if (list.length > 0) {
rs.push( rs.push(
<ListDateGroup <ListDateGroup
@@ -192,14 +154,15 @@ export const ArsListPage = () => {
mid={mid} mid={mid}
key={date + '-' + i} key={date + '-' + i}
date={date} date={date}
items={list as any} items={list}
></ListDateGroup> ></ListDateGroup>
); );
} }
date = itemDate; // 그 다음에 날짜 업데이트
list = []; list = [];
} }
list.push(listItems[i] as any); list.push(item);
}
}
} }
if (list.length > 0) { if (list.length > 0) {
rs.push( rs.push(
@@ -226,16 +189,16 @@ export const ArsListPage = () => {
<input <input
className="credit-period" className="credit-period"
type="text" type="text"
value={ moment(fromDate).format('YYYY.MM.DD') + '-' + moment(toDate).format('YYYY.MM.DD') } value={moment(fromDate).format('YYYY.MM.DD') + '-' + moment(toDate).format('YYYY.MM.DD')}
readOnly={ true } readOnly={true}
/> />
<button <button
className="filter-btn" className="filter-btn"
aria-label="필터" aria-label="필터"
onClick={ () => onClickToOpenFilter() } onClick={() => onClickToOpenFilter()}
> >
<img <img
src={ IMAGE_ROOT + '/ico_setting.svg' } src={IMAGE_ROOT + '/ico_setting.svg'}
alt="검색옵션" alt="검색옵션"
/> />
</button> </button>
@@ -243,10 +206,10 @@ export const ArsListPage = () => {
<button <button
className="download-btn" className="download-btn"
aria-label="다운로드" aria-label="다운로드"
onClick={ () => onClickToDownloadExcel() } onClick={() => onClickToDownloadExcel()}
> >
<img <img
src={ IMAGE_ROOT +'/ico_download.svg' } src={IMAGE_ROOT + '/ico_download.svg'}
alt="다운로드" alt="다운로드"
/> />
</button> </button>
@@ -255,18 +218,18 @@ export const ArsListPage = () => {
<section className="filter-section"> <section className="filter-section">
<SortTypeBox <SortTypeBox
sortType={ sortType } sortType={sortType}
onClickToSort={ onClickToSort } onClickToSort={onClickToSort}
></SortTypeBox> ></SortTypeBox>
<div className="excrow mr-0"> <div className="excrow mr-0">
<div className="full-menu-keywords no-padding"> <div className="full-menu-keywords no-padding">
{ {
ArsPaymentStatusBtnGroup.map((value, index) => ( ArsPaymentStatusBtnGroup.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 ${(paymentStatus === value.value) ? 'active' : ''}`}
onClick={ () => onClickToPaymentStatus(value.value) } onClick={() => onClickToPaymentStatus(value.value)}
>{ value.name }</span> >{value.name}</span>
)) ))
} }
</div> </div>
@@ -274,37 +237,36 @@ export const ArsListPage = () => {
</section> </section>
<section className="transaction-list"> <section className="transaction-list">
{ getListDateGroup() } {getListDateGroup()}
<div ref={setTarget}></div>
</section> </section>
<div className="apply-row"> <div className="apply-row">
<button <button
className="btn-50 btn-blue flex-1" className="btn-50 btn-blue flex-1"
onClick={ () => onClickToNavigate() } onClick={() => onClickToNavigate()}
> </button> > </button>
</div> </div>
</div> </div>
</div> </div>
</main> </main>
<ArsFilter <ArsFilter
filterOn={ filterOn } filterOn={filterOn}
setFilterOn={ setFilterOn } setFilterOn={setFilterOn}
mid={ mid } mid={mid}
moid={ moid } moid={moid}
fromDate={ fromDate } fromDate={fromDate}
toDate={ toDate } toDate={toDate}
paymentStatus={ paymentStatus } paymentStatus={paymentStatus}
orderStatus={ orderStatus } orderStatus={orderStatus}
minAmount={ minAmount } minAmount={minAmount}
maxAmount={ maxAmount } maxAmount={maxAmount}
setMid={ setMid } setMid={setMid}
setMoid={ setMoid } setMoid={setMoid}
setFromDate={ setFromDate } setFromDate={setFromDate}
setToDate={ setToDate } setToDate={setToDate}
setPaymentStatus={ setPaymentStatus } setPaymentStatus={setPaymentStatus}
setOrderStatus={ setOrderStatus } setOrderStatus={setOrderStatus}
setMinAmount={ setMinAmount } setMinAmount={setMinAmount}
setMaxAmount={ setMaxAmount } setMaxAmount={setMaxAmount}
></ArsFilter> ></ArsFilter>
</> </>
); );

View File

@@ -11,11 +11,14 @@ import { useLocation } from 'react-router';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { NumericFormat } from 'react-number-format'; import { NumericFormat } from 'react-number-format';
import { import {
ExtensionFundAccountDownloadReceiptParams,
ExtensionFundAccountDownloadReceiptResponse,
ExtensionFundAccountResultDetailParams, ExtensionFundAccountResultDetailParams,
ExtensionFundAccountResultDetailResponse, ExtensionFundAccountResultDetailResponse,
} from '@/entities/additional-service/model/fund-account/types'; } from '@/entities/additional-service/model/fund-account/types';
import moment from 'moment'; import moment from 'moment';
import { useExtensionFundAccountResultDetailMutation } from '@/entities/additional-service/api/fund-account/use-extension-fund-account-result-detail-mutation'; import { useExtensionFundAccountResultDetailMutation } from '@/entities/additional-service/api/fund-account/use-extension-fund-account-result-detail-mutation';
import { useExtensionFundAccountDownloadReceiptMutation } from '@/entities/additional-service/api/fund-account/use-extension-fund-account-download-certificate-mutation';
export const FundAccountResultDetailPage = () => { export const FundAccountResultDetailPage = () => {
const { navigate } = useNavigate(); const { navigate } = useNavigate();
@@ -25,8 +28,10 @@ export const FundAccountResultDetailPage = () => {
const mid = location.state.mid; const mid = location.state.mid;
const [detail, setDetail] = useState<ExtensionFundAccountResultDetailResponse>(); const [detail, setDetail] = useState<ExtensionFundAccountResultDetailResponse>();
const [email, setEmail] = useState<string>('');
const { mutateAsync: extensionFundAccountResultDetail } = useExtensionFundAccountResultDetailMutation(); const { mutateAsync: extensionFundAccountResultDetail } = useExtensionFundAccountResultDetailMutation();
const { mutateAsync: extensionFundAccountDownlaodReceipt } = useExtensionFundAccountDownloadReceiptMutation();
const callDetail = () => { const callDetail = () => {
let params: ExtensionFundAccountResultDetailParams = { let params: ExtensionFundAccountResultDetailParams = {
@@ -39,6 +44,17 @@ export const FundAccountResultDetailPage = () => {
}); });
}; };
const onClickToDownload = () => {
let params: ExtensionFundAccountDownloadReceiptParams = {
mid: mid,
tid: tid,
email: email
};
extensionFundAccountDownlaodReceipt(params).then((rs: ExtensionFundAccountDownloadReceiptResponse) => {
console.log(rs);
});
};
useSetHeaderTitle('자금이체 상세'); useSetHeaderTitle('자금이체 상세');
useSetHeaderType(HeaderType.LeftArrow); useSetHeaderType(HeaderType.LeftArrow);
useSetFooterMode(false); useSetFooterMode(false);
@@ -72,7 +88,11 @@ export const FundAccountResultDetailPage = () => {
{/* ✅ resultMessage가 "정상"일 때만 표시 */} {/* ✅ resultMessage가 "정상"일 때만 표시 */}
{detail?.resultMessage === '정상' && ( {detail?.resultMessage === '정상' && (
<div className="receipt-row"> <div className="receipt-row">
<button type="button" className="receipt-btn"> <button
type="button"
className="receipt-btn"
onClick={ onClickToDownload }
>
<span className="icon-24 download"></span> <span className="icon-24 download"></span>
<span></span> <span></span>
</button> </button>
@@ -104,7 +124,7 @@ export const FundAccountResultDetailPage = () => {
</li> </li>
<li className="kv-row"> <li className="kv-row">
<span className="k"></span> <span className="k"></span>
<span className="v">{detail?.bankCode}</span> <span className="v">{detail?.bankName}</span>
</li> </li>
<li className="kv-row"> <li className="kv-row">
<span className="k"></span> <span className="k"></span>

View File

@@ -11,27 +11,25 @@ import { useLocation } from 'react-router';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { NumericFormat } from 'react-number-format'; import { NumericFormat } from 'react-number-format';
import { useExtensionFundAccountTransferDetailMutation } from '@/entities/additional-service/api/fund-account/use-extension-fund-account-transfer-detail-mutation'; import { useExtensionFundAccountTransferDetailMutation } from '@/entities/additional-service/api/fund-account/use-extension-fund-account-transfer-detail-mutation';
import { ExtensionFundAccountTransferDetailParams, ExtensionFundAccountTransferDetailResponse, ExtensionFundAccountTransferRequestParams, ExtensionFundAccountTransferRequestResponse, FundAccountStatus } from '@/entities/additional-service/model/fund-account/types'; import { ExtensionFundAccountTransferDetailParams, ExtensionFundAccountTransferDetailResponse, ExtensionFundAccountTransferRegistParams, ExtensionFundAccountTransferRequestResponse, FundAccountStatus } from '@/entities/additional-service/model/fund-account/types';
import { getFundAccountStatusName } from '@/entities/additional-service/model/fund-account/constant'; import { getFundAccountStatusName } from '@/entities/additional-service/model/fund-account/constant';
import moment from 'moment'; import moment from 'moment';
import { useExtensionFundAccountTransferRequestMutation } from '@/entities/additional-service/api/fund-account/use-extension-fund-account-transfer-request-mutation'; import { useExtensionFundAccountTransferRegistMutation } from '@/entities/additional-service/api/fund-account/use-extension-fund-account-transfer-regist-mutation';
export const FundAccountTransferDetailPage = () => { export const FundAccountTransferDetailPage = () => {
const { navigate } = useNavigate(); const { navigate } = useNavigate();
const location = useLocation(); const location = useLocation();
const tid = location.state.tid; const seq = location.state.seq;
const mid = location.state.mid;
const [detail, setDetail] = useState<ExtensionFundAccountTransferDetailResponse>(); const [detail, setDetail] = useState<ExtensionFundAccountTransferDetailResponse>();
const { mutateAsync: extensionFundAccountTransferDetail } = useExtensionFundAccountTransferDetailMutation(); const { mutateAsync: extensionFundAccountTransferDetail } = useExtensionFundAccountTransferDetailMutation();
const { mutateAsync: extensionFundAccountTransferRequest } = useExtensionFundAccountTransferRequestMutation(); const { mutateAsync: extensionFundAccountTransferRequest } = useExtensionFundAccountTransferRegistMutation();
const callDetail = () => { const callDetail = () => {
let params: ExtensionFundAccountTransferDetailParams = { let params: ExtensionFundAccountTransferDetailParams = {
tid: tid, seq: seq
mid: mid,
}; };
extensionFundAccountTransferDetail(params).then((rs: ExtensionFundAccountTransferDetailResponse) => { extensionFundAccountTransferDetail(params).then((rs: ExtensionFundAccountTransferDetailResponse) => {
@@ -50,26 +48,26 @@ export const FundAccountTransferDetailPage = () => {
callDetail(); callDetail();
}, []); }, []);
const onClickToRequest = () => { // const onClickToRequest = () => {
if (!detail) { // if (!detail) {
alert('상세 정보를 불러오는 중입니다.'); // alert('상세 정보를 불러오는 중입니다.');
return; // return;
} // }
let params: ExtensionFundAccountTransferRequestParams = { // let params: ExtensionFundAccountTransferRegistParams = {
mid: mid, // mid: mid,
bankCode: detail.bankCode || '', // bankCode: detail.bankCode || '',
accountNo: detail.accountNo || '', // accountNo: detail.accountNo || '',
accountName: detail.accountName || '', // accountName: detail.accountName || '',
amount: detail.amount || 0, // amount: detail.amount || 0,
moid: detail.moid || '' // moid: detail.moid || ''
}; // };
extensionFundAccountTransferRequest(params).then((rs: ExtensionFundAccountTransferRequestResponse) => { // extensionFundAccountTransferRequest(params).then((rs: ExtensionFundAccountTransferRequestResponse) => {
console.log(rs) // console.log(rs)
alert(rs.status ? '이체 요청이 완료되었습니다.' : '이체 요청에 실패했습니다.'); // alert(rs.status ? '이체 요청이 완료되었습니다.' : '이체 요청에 실패했습니다.');
navigate(PATHS.additionalService.fundAccount.transferList); // navigate(PATHS.additionalService.fundAccount.transferList);
}); // });
}; // };
return ( return (
<> <>
@@ -138,7 +136,7 @@ export const FundAccountTransferDetailPage = () => {
<div className="apply-row"> <div className="apply-row">
<button <button
className="btn-50 btn-blue flex-1" className="btn-50 btn-blue flex-1"
onClick={() => onClickToRequest()} //onClick={() => onClickToRequest()}
disabled={detail?.resultStatus !== FundAccountStatus.REGIST_COMPLETE} disabled={detail?.resultStatus !== FundAccountStatus.REGIST_COMPLETE}
> </button> > </button>
</div> </div>

View File

@@ -7,15 +7,15 @@ import {
useSetFooterMode, useSetFooterMode,
useSetOnBack useSetOnBack
} from '@/widgets/sub-layout/use-sub-layout'; } from '@/widgets/sub-layout/use-sub-layout';
import { ChangeEvent, useEffect, useState } from 'react'; import { ChangeEvent, useState } from 'react';
import { useExtensionFundAccountTransferRequestMutation } from '@/entities/additional-service/api/fund-account/use-extension-fund-account-transfer-request-mutation'; import { ExtensionFundAccountTransferRegistParams, ExtensionFundAccountTransferRegistResponse } from '@/entities/additional-service/model/fund-account/types';
import { ExtensionFundAccountTransferRequestParams, ExtensionFundAccountTransferRequestResponse } from '@/entities/additional-service/model/fund-account/types';
import { useStore } from '@/shared/model/store'; import { useStore } from '@/shared/model/store';
import { snackBar } from '@/shared/lib';
import { useExtensionFundAccountTransferRegistMutation } from '@/entities/additional-service/api/fund-account/use-extension-fund-account-transfer-regist-mutation';
export const FundAccountTransferRequestPage = () => { export const FundAccountTransferRequestPage = () => {
const { navigate } = useNavigate(); const { navigate } = useNavigate();
const midOptions = useStore.getState().UserStore.selectOptionsMids; const midOptions = useStore.getState().UserStore.selectOptionsMids;
const userMid = useStore.getState().UserStore.mid; const userMid = useStore.getState().UserStore.mid;
@@ -27,7 +27,7 @@ export const FundAccountTransferRequestPage = () => {
const [moid, setMoid] = useState<string>(''); const [moid, setMoid] = useState<string>('');
const [depositParameter, setDepositParameter] = useState<string>(''); const [depositParameter, setDepositParameter] = useState<string>('');
const { mutateAsync: extensionFundAccountRequest } = useExtensionFundAccountTransferRequestMutation(); const { mutateAsync: extensionFundAccountRegist } = useExtensionFundAccountTransferRegistMutation();
useSetHeaderTitle('자금이체 이체등록'); useSetHeaderTitle('자금이체 이체등록');
useSetHeaderType(HeaderType.RightClose); useSetHeaderType(HeaderType.RightClose);
@@ -36,8 +36,17 @@ export const FundAccountTransferRequestPage = () => {
navigate(PATHS.additionalService.fundAccount.transferList); navigate(PATHS.additionalService.fundAccount.transferList);
}); });
const callExtensionFundAccountTransferRequest = () => { const resetForm = () => {
let params: ExtensionFundAccountTransferRequestParams = { setBankCode('');
setAccountNo('');
setAccountName('');
setAmount(0);
setMoid('');
setDepositParameter('');
};
const callExtensionFundAccountTransferRegist = () => {
let params: ExtensionFundAccountTransferRegistParams = {
mid: mid, mid: mid,
bankCode: bankCode, bankCode: bankCode,
accountNo: accountNo, accountNo: accountNo,
@@ -46,8 +55,13 @@ export const FundAccountTransferRequestPage = () => {
moid: moid, moid: moid,
depositParameter: depositParameter depositParameter: depositParameter
}; };
extensionFundAccountRequest(params).then((rs: ExtensionFundAccountTransferRequestResponse) => { extensionFundAccountRegist(params).then((rs: ExtensionFundAccountTransferRegistResponse) => {
navigate(PATHS.additionalService.payout.list); if (rs.status) {
snackBar("이체등록을 성공하였습니다.")
resetForm();
} else {
snackBar("이체등록이 실패하였습니다.")
}
}); });
}; };
@@ -72,10 +86,7 @@ export const FundAccountTransferRequestPage = () => {
<div className="billing-row"> <div className="billing-row">
<div className="billing-label"><span>*</span></div> <div className="billing-label"><span>*</span></div>
<div className="billing-field"> <div className="billing-field">
<select <select value={mid} onChange={(e) => setMid(e.target.value)}>
value={ mid }
onChange={ (e: ChangeEvent<HTMLSelectElement>) => setMid(e.target.value) }
>
{ {
midOptions.map((value, index) => ( midOptions.map((value, index) => (
<option <option
@@ -154,7 +165,7 @@ export const FundAccountTransferRequestPage = () => {
<div className="apply-row"> <div className="apply-row">
<button <button
className="btn-50 btn-blue flex-1" className="btn-50 btn-blue flex-1"
onClick={callExtensionFundAccountTransferRequest} onClick={callExtensionFundAccountTransferRegist}
disabled={!isFormValid()} disabled={!isFormValid()}
></button> ></button>
</div> </div>

View File

@@ -21,7 +21,6 @@ import { KeyInPaymentList } from '@/entities/additional-service/ui/key-in-paymen
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, KeyInPaymentPaymentStatus } 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 useIntersectionObserver from '@/widgets/intersection-observer';
export const KeyInPaymentPage = () => { export const KeyInPaymentPage = () => {
const { navigate } = useNavigate(); const { navigate } = useNavigate();
@@ -31,32 +30,12 @@ export const KeyInPaymentPage = () => {
const [listItems, setListItems] = useState<Array<KeyInPaymentListItem>>([]); const [listItems, setListItems] = useState<Array<KeyInPaymentListItem>>([]);
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 [nextCursor, setNextCursor] = useState<string | null>(null);
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('YYYY-MM-DD'));
const [endDate, setEndDate] = useState(moment().format('YYYY-MM-DD')); const [endDate, setEndDate] = useState(moment().format('YYYY-MM-DD'));
const [paymentStatus, setPaymentStatus] = useState<KeyInPaymentPaymentStatus>(KeyInPaymentPaymentStatus.ALL) const [paymentStatus, setPaymentStatus] = useState<KeyInPaymentPaymentStatus>(KeyInPaymentPaymentStatus.ALL)
const [minAmount, setMinAmount] = useState<number>(); const [minAmount, setMinAmount] = useState<number>();
const [maxAmount, setMaxAmount] = useState<number>(); const [maxAmount, setMaxAmount] = useState<number>();
const [onActionIntersect, setOnActionIntersect] = useState<boolean>(false);
const onIntersect: IntersectionObserverCallback = (entries: Array<IntersectionObserverEntry>) => {
entries.forEach((entry: IntersectionObserverEntry) => {
if (entry.isIntersecting) {
console.log('Element is now intersecting with the root. [' + onActionIntersect + ']');
if (onActionIntersect) {
callList();
}
}
else {
console.log('Element is no longer intersecting with the root.');
}
});
};
const { setTarget } = useIntersectionObserver({
threshold: 1,
onIntersect
});
useSetHeaderTitle('KEY-IN 결제'); useSetHeaderTitle('KEY-IN 결제');
useSetHeaderType(HeaderType.LeftArrow); useSetHeaderType(HeaderType.LeftArrow);
@@ -70,17 +49,8 @@ export const KeyInPaymentPage = () => {
const callList = (option?: { const callList = (option?: {
sortType?: SortTypeKeys, sortType?: SortTypeKeys,
status?: KeyInPaymentPaymentStatus, status?: KeyInPaymentPaymentStatus
resetPage?: boolean
}) => { }) => {
setOnActionIntersect(false);
const currentPageParam = option?.resetPage
? { ...DEFAULT_PAGE_PARAM, sortType: option?.sortType ?? sortType }
: { ...pageParam, sortType: option?.sortType ?? sortType };
setPageParam(currentPageParam);
let newMinAmount = minAmount; let newMinAmount = minAmount;
if (!!minAmount && typeof (minAmount) === 'string') { if (!!minAmount && typeof (minAmount) === 'string') {
newMinAmount = parseInt(minAmount); newMinAmount = parseInt(minAmount);
@@ -96,28 +66,16 @@ export const KeyInPaymentPage = () => {
paymentStatus: paymentStatus, paymentStatus: paymentStatus,
minAmount: newMinAmount, minAmount: newMinAmount,
maxAmount: newMaxAmount, maxAmount: newMaxAmount,
... { page: pageParam
page: currentPageParam
}
}; };
if (listParams.page) {
listParams.page.sortType = option?.sortType || sortType;
setPageParam(listParams.page);
}
keyinList(listParams).then((rs) => { keyinList(listParams).then((rs) => {
// resetPage면 기존 리스트 무시, 아니면 추가 setListItems(rs.content);
setListItems(option?.resetPage ? rs.content : [
...listItems,
...rs.content
]);
if (rs.hasNext) {
setNextCursor(rs.nextCursor);
setPageParam({
...currentPageParam, // pageParam이 아니라 currentPageParam 사용
cursor: rs.nextCursor
});
setOnActionIntersect(true)
}
else {
setNextCursor(null);
}
}); });
} }
@@ -149,21 +107,19 @@ export const KeyInPaymentPage = () => {
const onClickToSort = (sort: SortTypeKeys) => { const onClickToSort = (sort: SortTypeKeys) => {
setSortType(sort); setSortType(sort);
callList({ callList({
sortType: sort, sortType: sort
resetPage: true
}); });
}; };
const onClickToPaymentStatus = (val: KeyInPaymentPaymentStatus) => { const onClickToPaymentStatus = (val: KeyInPaymentPaymentStatus) => {
setPaymentStatus(val); setPaymentStatus(val);
callList({ callList({
status: val, status: val
resetPage: true
}); });
}; };
useEffect(() => { useEffect(() => {
callList({resetPage: true}); callList();
}, [ }, [
mid, mid,
startDate, startDate,
@@ -234,7 +190,6 @@ export const KeyInPaymentPage = () => {
listItems={listItems} listItems={listItems}
additionalServiceCategory={AdditionalServiceCategory.KeyInPayment} additionalServiceCategory={AdditionalServiceCategory.KeyInPayment}
mid={mid} mid={mid}
setTarget={setTarget}
></KeyInPaymentList> ></KeyInPaymentList>
</div> </div>
</div> </div>

View File

@@ -256,7 +256,12 @@ export const LinkPaymentSeparateApprovalPage = () => {
</li> </li>
<li> <li>
<span className="label"> :</span> <span className="label"> :</span>
<span className="value">{item.paymentLimitDate}</span> <span className="value">
{item.paymentLimitDate
? moment(item.paymentLimitDate, 'YYYYMMDD').format('YYYY/MM/DD')
: '-'
}
</span>
</li> </li>
<li> <li>
<span className="label"> :</span> <span className="label"> :</span>
@@ -272,13 +277,11 @@ export const LinkPaymentSeparateApprovalPage = () => {
onChange={(e) => handleExtendPeriodChange(itemId, e.target.value)} onChange={(e) => handleExtendPeriodChange(itemId, e.target.value)}
> >
<option value=""></option> <option value=""></option>
<option value="1">1</option> {[1, 2, 3, 4, 5, 6, 7].map(days => {
<option value="2">2</option> const baseDate = moment(item.paymentLimitDate, 'YYYYMMDD');
<option value="3">3</option> const targetDate = baseDate.clone().add(days, 'days').format('YYYY/MM/DD');
<option value="4">4</option> return <option key={days} value={days.toString()}>{targetDate}</option>;
<option value="5">5</option> })}
<option value="6">6</option>
<option value="7">7</option>
</select> </select>
</div> </div>
</div> </div>

View File

@@ -28,36 +28,14 @@ import { PayoutDisbursementStatusBtnGroup } from '@/entities/additional-service/
import { ListDateGroup } from '@/entities/additional-service/ui/list-date-group'; import { ListDateGroup } from '@/entities/additional-service/ui/list-date-group';
import { AdditionalServiceCategory } from '@/entities/additional-service/model/types'; import { AdditionalServiceCategory } from '@/entities/additional-service/model/types';
import { useStore } from '@/shared/model/store'; import { useStore } from '@/shared/model/store';
import useIntersectionObserver from '@/widgets/intersection-observer';
export const PayoutListPage = () => { export const PayoutListPage = () => {
const { navigate } = useNavigate(); const { navigate } = useNavigate();
const userMid = useStore.getState().UserStore.mid; const userMid = useStore.getState().UserStore.mid;
const [onActionIntersect, setOnActionIntersect] = useState<boolean>(false);
const onIntersect: IntersectionObserverCallback = (entries: Array<IntersectionObserverEntry>) => {
entries.forEach((entry: IntersectionObserverEntry) => {
if (entry.isIntersecting) {
console.log('Element is now intersecting with the root. [' + onActionIntersect + ']');
if (onActionIntersect) {
callExtensionPayoutList();
}
}
else {
console.log('Element is no longer intersecting with the root.');
}
});
};
const { setTarget } = useIntersectionObserver({
threshold: 1,
onIntersect
});
const [sortType, setSortType] = useState<SortTypeKeys>(SortTypeKeys.LATEST); const [sortType, setSortType] = useState<SortTypeKeys>(SortTypeKeys.LATEST);
const [listItems, setListItems] = useState<Array<PayoutContent>>([]); const [listItems, setListItems] = useState<Array<PayoutContent>>([]);
const [filterOn, setFilterOn] = useState<boolean>(false); const [filterOn, setFilterOn] = useState<boolean>(false);
const [nextCursor, setNextCursor] = useState<string | null>(null);
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 [searchDateType, setSearchDateType] = useState<PayoutSearchDateType>(PayoutSearchDateType.REQUEST_DATE); const [searchDateType, setSearchDateType] = useState<PayoutSearchDateType>(PayoutSearchDateType.REQUEST_DATE);
@@ -83,17 +61,8 @@ export const PayoutListPage = () => {
const callExtensionPayoutList = (option?: { const callExtensionPayoutList = (option?: {
sortType?: SortTypeKeys, sortType?: SortTypeKeys,
status?: PayoutDisbursementStatus, status?: PayoutDisbursementStatus
resetPage?: boolean
}) => { }) => {
setOnActionIntersect(false);
const currentPageParam = option?.resetPage
? { ...DEFAULT_PAGE_PARAM, sortType: option?.sortType ?? sortType }
: { ...pageParam, sortType: option?.sortType ?? sortType };
setPageParam(currentPageParam);
let newMinAmount = minAmount; let newMinAmount = minAmount;
if(!!minAmount && typeof(minAmount) === 'string'){ if(!!minAmount && typeof(minAmount) === 'string'){
newMinAmount = parseInt(minAmount); newMinAmount = parseInt(minAmount);
@@ -110,25 +79,16 @@ export const PayoutListPage = () => {
status: option?.status ?? status, status: option?.status ?? status,
minAmount: newMinAmount, minAmount: newMinAmount,
maxAmount: newMaxAmount, maxAmount: newMaxAmount,
page: currentPageParam page: pageParam
}; };
if(params.page){
params.page.sortType = option?.sortType || sortType;
setPageParam(params.page);
}
extensionPayoutList(params).then((rs: ExtensionPayoutListResponse) => { extensionPayoutList(params).then((rs: ExtensionPayoutListResponse) => {
// resetPage면 기존 리스트 무시, 아니면 추가 setListItems(rs.content);
setListItems(option?.resetPage ? rs.content : [
...listItems,
...rs.content
]);
if (rs.hasNext) {
setNextCursor(rs.nextCursor);
setPageParam({
...currentPageParam,
cursor: rs.nextCursor
});
setOnActionIntersect(true)
}
else {
setNextCursor(null);
}
}); });
}; };
@@ -156,21 +116,18 @@ export const PayoutListPage = () => {
const onClickToSort = (sort: SortTypeKeys) => { const onClickToSort = (sort: SortTypeKeys) => {
setSortType(sort); setSortType(sort);
callExtensionPayoutList({ callExtensionPayoutList({
sortType: sort, sortType: sort
resetPage: true
}); });
}; };
const onClickToDisbursementStatus = (val: PayoutDisbursementStatus) => { const onClickToDisbursementStatus = (val: PayoutDisbursementStatus) => {
setStatus(val); setStatus(val);
callExtensionPayoutList({ callExtensionPayoutList({
status: val, status: val
resetPage: true
}); });
}; };
useEffect(() => { useEffect(() => {
// 필터 조건이 변경되면 첫 페이지부터 다시 시작 callExtensionPayoutList();
callExtensionPayoutList({ resetPage: true });
}, [ }, [
mid, mid,
searchDateType, searchDateType,
@@ -298,7 +255,6 @@ export const PayoutListPage = () => {
</section> </section>
<section className="transaction-list"> <section className="transaction-list">
{ getListDateGroup() } { getListDateGroup() }
<div ref={setTarget}></div>
</section> </section>
<div className="apply-row"> <div className="apply-row">
<button <button

View File

@@ -18,7 +18,6 @@ import { SmsPaymentList } from '@/entities/additional-service/ui/sms-payment/sms
import { SmsPaymentFilter } from '@/entities/additional-service/ui/sms-payment/sms-payment-filter'; import { SmsPaymentFilter } from '@/entities/additional-service/ui/sms-payment/sms-payment-filter';
import { useExtensionSmsDetailMutation } from '@/entities/additional-service/api/sms-payment/use-extension-sms-detail-mutation'; import { useExtensionSmsDetailMutation } from '@/entities/additional-service/api/sms-payment/use-extension-sms-detail-mutation';
import { useStore } from '@/shared/model/store'; import { useStore } from '@/shared/model/store';
import useIntersectionObserver from '@/widgets/intersection-observer';
import { AdditionalServiceCategory } from '@/entities/additional-service/model/types'; import { AdditionalServiceCategory } from '@/entities/additional-service/model/types';
import { PATHS } from '@/shared/constants/paths'; import { PATHS } from '@/shared/constants/paths';
@@ -27,31 +26,10 @@ export const SmsPaymentPage = () => {
const { navigate } = useNavigate(); const { navigate } = useNavigate();
const userMid = useStore.getState().UserStore.mid; const userMid = useStore.getState().UserStore.mid;
const [onActionIntersect, setOnActionIntersect] = useState<boolean>(false);
const onIntersect: IntersectionObserverCallback = (entries: Array<IntersectionObserverEntry>) => {
entries.forEach((entry: IntersectionObserverEntry) => {
if (entry.isIntersecting) {
console.log('Element is now intersecting with the root. [' + onActionIntersect + ']');
if (onActionIntersect) {
callList();
}
}
else {
console.log('Element is no longer intersecting with the root.');
}
});
};
const { setTarget } = useIntersectionObserver({
threshold: 1,
onIntersect
});
const [bottomSmsPaymentDetailResendOn, setBottomSmsPaymentDetailResendOn] = useState<boolean>(false) const [bottomSmsPaymentDetailResendOn, setBottomSmsPaymentDetailResendOn] = useState<boolean>(false)
const [sortType, setSortType] = useState<SortTypeKeys>(SortTypeKeys.LATEST); const [sortType, setSortType] = useState<SortTypeKeys>(SortTypeKeys.LATEST);
const [listItems, setListItems] = useState<Array<SmsPaymentListItem>>([]); const [listItems, setListItems] = useState<Array<SmsPaymentListItem>>([]);
const [nextCursor, setNextCursor] = useState<string | null>(null);
const [pageParam, setPageParam] = useState<DefaultRequestPagination>(DEFAULT_PAGE_PARAM); const [pageParam, setPageParam] = useState<DefaultRequestPagination>(DEFAULT_PAGE_PARAM);
const [filterOn, setFilterOn] = useState<boolean>(false); const [filterOn, setFilterOn] = useState<boolean>(false);
const [mid, setMid] = useState<string>(userMid); const [mid, setMid] = useState<string>(userMid);
@@ -75,15 +53,8 @@ export const SmsPaymentPage = () => {
navigate(PATHS.home); navigate(PATHS.home);
}); });
const callList = (option?: { const callList = (option?: {
sortType?: SortTypeKeys, sortType?: SortTypeKeys
resetPage?: boolean
}) => { }) => {
const currentPageParam = option?.resetPage
? { ...DEFAULT_PAGE_PARAM, sortType: option?.sortType ?? sortType }
: { ...pageParam, sortType: option?.sortType ?? sortType };
setPageParam(currentPageParam);
let listParams: ExtensionSmsPaymentListParams = { let listParams: ExtensionSmsPaymentListParams = {
mid: mid, mid: mid,
searchCl: searchCl, searchCl: searchCl,
@@ -91,26 +62,16 @@ export const SmsPaymentPage = () => {
fromDate: fromDate, fromDate: fromDate,
toDate: toDate, toDate: toDate,
smsCl: smsCl, smsCl: smsCl,
... { page: pageParam
page: currentPageParam
} }
if (listParams.page) {
listParams.page.sortType = option?.sortType || sortType;
setPageParam(listParams.page);
} }
smsPaymentList(listParams).then((rs) => { smsPaymentList(listParams).then((rs) => {
setListItems(option?.resetPage ? rs.content : [ setListItems(rs.content);
...listItems,
...rs.content
]);
if (rs.hasNext) {
setNextCursor(rs.nextCursor);
setPageParam({
...currentPageParam,
cursor: rs.nextCursor
});
setOnActionIntersect(true)
} else {
setNextCursor(null);
}
}); });
} }
@@ -150,7 +111,7 @@ export const SmsPaymentPage = () => {
}; };
useEffect(() => { useEffect(() => {
callList({resetPage: true}); callList();
}, [ }, [
mid, mid,
searchCl, searchCl,
@@ -203,7 +164,6 @@ export const SmsPaymentPage = () => {
additionalServiceCategory={AdditionalServiceCategory.SMSPayment} additionalServiceCategory={AdditionalServiceCategory.SMSPayment}
mid={mid} mid={mid}
onResendClick={onClickToShowDetail} onResendClick={onClickToShowDetail}
setTarget={setTarget}
></SmsPaymentList> ></SmsPaymentList>
</div> </div>
</div> </div>

View File

@@ -173,6 +173,10 @@ export const API_URL_ADDITIONAL_SERVICE = {
}, },
// Fund Account Management 부가서비스 > 자금이체 API // Fund Account Management 부가서비스 > 자금이체 API
extensionFundAccountTransferRegist: () => {
// POST: 자금이체 > 이체등록
return `${API_BASE_URL}/api/v1/${API_URL_KEY}/extension/fund-account/transfer/regist`
},
extensionFundAccountTransferRequest: () => { extensionFundAccountTransferRequest: () => {
// POST: 자금이체 > 이체신청 // POST: 자금이체 > 이체신청
return `${API_BASE_URL}/api/v1/${API_URL_KEY}/extension/fund-account/transfer/request`; return `${API_BASE_URL}/api/v1/${API_URL_KEY}/extension/fund-account/transfer/request`;

View File

@@ -176,16 +176,22 @@ main.home-main{
} }
.approval-cards-wrapper { .approval-cards-wrapper {
display: flex;
flex-direction: column;
gap: 16px; gap: 16px;
padding: 16px;
padding-bottom: 2px; padding-bottom: 2px;
} }
.separate-approval-main .apply-row.two-button { .separate-approval-main .apply-row.two-button {
display: flex;
gap: 8px;
flex-shrink: 0; flex-shrink: 0;
position: sticky; position: sticky;
bottom: 0; bottom: 0;
background: white; background: white;
z-index: 10; z-index: 10;
padding: 16px;
} }
/* 분할승인 안내 박스 */ /* 분할승인 안내 박스 */
@@ -215,13 +221,15 @@ main.home-main{
border: 2px solid var(--color-d6d6d6); border: 2px solid var(--color-d6d6d6);
border-radius: 16px; border-radius: 16px;
padding: 16px; padding: 16px;
margin-bottom: 16px; margin-bottom: 0;
transition: all 0.4s ease; transition: all 0.3s ease;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
} }
.approval-card.selected { .approval-card.selected {
border-color: var(--color-3E6AFC); border-color: var(--color-3E6AFC);
background: var(--color-F4F8FF); background: var(--color-F4F8FF);
box-shadow: 0 4px 12px rgba(62, 106, 252, 0.2);
} }
.approval-card .card-checkbox { .approval-card .card-checkbox {
@@ -270,6 +278,8 @@ main.home-main{
/* 분할승인 카드 헤더 */ /* 분할승인 카드 헤더 */
.approval-card .card-header { .approval-card .card-header {
display: flex;
align-items: center;
gap: 8px; gap: 8px;
margin-bottom: 16px; margin-bottom: 16px;
padding-bottom: 12px; padding-bottom: 12px;
@@ -309,6 +319,8 @@ main.home-main{
} }
.approval-card .info-list { .approval-card .info-list {
display: flex;
flex-direction: column;
list-style: none; list-style: none;
padding: 0; padding: 0;
margin: 0; margin: 0;
@@ -316,6 +328,7 @@ main.home-main{
} }
.approval-card .info-list li { .approval-card .info-list li {
display: flex;
align-items: center; align-items: center;
font-size: var(--fs-14); font-size: var(--fs-14);
color: var(--color-2D3436); color: var(--color-2D3436);
@@ -351,6 +364,7 @@ main.home-main{
} }
.approval-card .period-selector select { .approval-card .period-selector select {
flex: 1;
height: 36px; height: 36px;
font-size: var(--fs-14); font-size: var(--fs-14);
padding: 6px 30px 6px 12px; padding: 6px 30px 6px 12px;
@@ -358,6 +372,7 @@ main.home-main{
border-radius: 4px; border-radius: 4px;
background-color: var(--color-white); background-color: var(--color-white);
transition: all 0.2s ease; transition: all 0.2s ease;
cursor: pointer;
} }
/* Scrollbar hide utility class */ /* Scrollbar hide utility class */

View File

@@ -166,6 +166,12 @@ export const SubLayout = () => {
id: 'nictest00', id: 'nictest00',
password: 'nictest00' password: 'nictest00'
}; };
// userParmas = {
// id: 'medi9332',
// password: 'medi9332'
// };
} }
callLogin(userParmas).then(() => { callLogin(userParmas).then(() => {
callHomeGroups(); callHomeGroups();