부가서비스 : 링크결제 발송내역,발송대기 상세페이지 추가

This commit is contained in:
HyeonJongKim
2025-09-10 17:03:19 +09:00
parent a71690bad8
commit 409a711b9a
29 changed files with 1039 additions and 320 deletions

View File

@@ -19,6 +19,14 @@ export enum SettlementAgencyTabKeys {
Deposit = 'Deposit',
Member = 'Member',
};
export enum SortByKeys {
New = 'New',
Amount = 'Amount',
};
export interface SortOptionsBoxProps {
sortBy: SortByKeys;
onClickToSort: (sortBy: SortByKeys) => void;
};
export interface SettlementAgencyTabProps {
activeTab: SettlementAgencyTabKeys;
};
@@ -306,4 +314,23 @@ export interface SettlementAgencyBottomAgreeProps {
export interface LinkPaymentFilterProps {
filterOn: boolean;
setFilterOn: (filterOn: boolean) => void;
};
export enum DetailInfoSectionKeys {
Payment = 'Payment',
Deets = 'Deets'
}
export interface DetailPaymentInfoProps {
};
export interface DetailDeetsInfoProps {
};
export interface DetailResponse {
paymentInfo?: DetailPaymentInfoProps
deetsInfo?: DetailDeetsInfoProps
}
export interface DetailInfoSectionProps extends DetailResponse {
show?: boolean;
tid?: string;
onClickToShowInfo?: (info: DetailInfoSectionKeys) => void;
}

View File

@@ -1,158 +0,0 @@
import { IMAGE_ROOT } from "@/shared/constants/common";
import { useState } from "react";
import { LinkPaymentFilter } from "./link-payment-filter";
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { PATHS } from "@/shared/constants/paths";
export const LinkPaymentDispatchListWrap = () => {
const { navigate } = useNavigate();
const [filterOn, setFilterOn] = useState<boolean>(false);
const onClickToOpenFilter = () => {
setFilterOn(!filterOn);
};
const onClickToNavigate = () => {
navigate(PATHS.additionalService.linkPayment.request)
}
return (
<>
<section className="summary-section">
<div className="credit-controls">
<div>
<input
className="credit-period"
type="text"
value="2025.06.01 ~ 2025.06.30"
readOnly={true}
/>
<button
className="filter-btn"
aria-label="필터"
>
<img
src={IMAGE_ROOT + '/ico_setting.svg'}
alt="검색옵션"
onClick={() => onClickToOpenFilter()}
/>
</button>
</div>
<button
className="download-btn"
aria-label="다운로드"
>
<img
src={IMAGE_ROOT + '/ico_download.svg'}
alt="다운로드"
/>
</button>
</div>
</section>
<section className="filter-section">
<div className="sort-options">
<button className="sort-btn active"></button>
<span className="sort-divider">|</span>
<button className="sort-btn"></button>
</div>
<div className="excrow">
<div className="full-menu-keywords no-padding">
<span className="keyword-tag active"></span>
<span className="keyword-tag"></span>
<span className="keyword-tag"></span>
</div>
</div>
</section>
<section className="transaction-list">
<div className="date-header">25.06.08()</div>
<div className="transaction-item approved">
<div className="transaction-status">
<div className="status-dot blue"></div>
</div>
<div className="transaction-content">
<div className="transaction-title">*(7000)</div>
<div className="transaction-details">
<span></span>
<span className="separator"></span>
<span>SMS</span>
<span className="separator"></span>
<span></span>
</div>
</div>
<div className="transaction-amount">5,254,000</div>
</div>
<div className="transaction-item approved">
<div className="transaction-status">
<div className="status-dot blue"></div>
</div>
<div className="transaction-content">
<div className="transaction-title">*(7000)</div>
<div className="transaction-details">
<span></span>
<span className="separator"></span>
<span></span>
<span className="separator"></span>
<span></span>
</div>
</div>
<div className="transaction-amount">5,254,000</div>
</div>
<div className="transaction-item approved">
<div className="transaction-status">
<div className="status-dot blue"></div>
</div>
<div className="transaction-content">
<div className="transaction-title">*(7000)</div>
<div className="transaction-details">
<span></span>
<span className="separator"></span>
<span></span>
<span className="separator"></span>
<span></span>
</div>
</div>
<div className="transaction-amount">5,254,000</div>
</div>
<div className="transaction-item approved">
<div className="transaction-status">
<div className="status-dot gray"></div>
</div>
<div className="transaction-content">
<div className="transaction-title">*(7000)</div>
<div className="transaction-details">
<span></span>
<span className="separator"></span>
<span>SMS</span>
</div>
</div>
<div className="transaction-amount">5,254,000</div>
</div>
<div className="transaction-item approved">
<div className="transaction-status">
<div className="status-dot gray"></div>
</div>
<div className="transaction-content">
<div className="transaction-title">*(7000)</div>
<div className="transaction-details">
<span></span>
<span className="separator"></span>
<span>SMS</span>
</div>
</div>
<div className="transaction-amount">5,254,000</div>
</div>
</section>
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={() => onClickToNavigate()}
> </button>
</div>
<LinkPaymentFilter
filterOn={filterOn}
setFilterOn={setFilterOn}
></LinkPaymentFilter>
</>
)
}

View File

@@ -1,150 +0,0 @@
import { IMAGE_ROOT } from "@/shared/constants/common";
import { useState } from "react";
import { LinkPaymentFilter } from "./link-payment-filter";
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { PATHS } from "@/shared/constants/paths";
export const LinkPaymentPendingSendWrap = () => {
const { navigate } = useNavigate();
const [filterOn, setFilterOn] = useState<boolean>(false);
const onClickToOpenFilter = () => {
setFilterOn(!filterOn);
};
const onClickToNavigate = () => {
navigate(PATHS.additionalService.linkPayment.request)
}
return (
<>
<section className="summary-section">
<div className="credit-controls">
<div>
<input
className="credit-period"
type="text"
value="2025.06.01 ~ 2025.06.30"
readOnly={true}
/>
<button
className="filter-btn"
aria-label="필터"
>
<img
src={IMAGE_ROOT + '/ico_setting.svg'}
alt="검색옵션"
onClick={() => onClickToOpenFilter()}
/>
</button>
</div>
<button
className="download-btn"
aria-label="다운로드"
>
<img
src={IMAGE_ROOT + '/ico_download.svg'}
alt="다운로드"
/>
</button>
</div>
</section>
<section className="filter-section">
<div className="sort-options">
<button className="sort-btn active"></button>
<span className="sort-divider">|</span>
<button className="sort-btn"></button>
</div>
<div className="excrow">
<div className="full-menu-keywords no-padding">
<span className="keyword-tag active"></span>
<span className="keyword-tag"></span>
<span className="keyword-tag"></span>
</div>
</div>
</section>
<section className="transaction-list">
<div className="date-header">25.06.08()</div>
<div className="transaction-item approved">
<div className="transaction-status">
<div className="status-dot blue"></div>
</div>
<div className="transaction-content">
<div className="transaction-title">*(7000)</div>
<div className="transaction-details">
<span></span>
<span className="separator"></span>
<span>SMS</span>
</div>
</div>
<div className="transaction-amount">5,254,000</div>
</div>
<div className="transaction-item approved">
<div className="transaction-status">
<div className="status-dot blue"></div>
</div>
<div className="transaction-content">
<div className="transaction-title">*(7000)</div>
<div className="transaction-details">
<span></span>
<span className="separator"></span>
<span>SMS</span>
</div>
</div>
<div className="transaction-amount">5,254,000</div>
</div>
<div className="transaction-item approved">
<div className="transaction-status">
<div className="status-dot blue"></div>
</div>
<div className="transaction-content">
<div className="transaction-title">*(7000)</div>
<div className="transaction-details">
<span></span>
<span className="separator"></span>
<span></span>
</div>
</div>
<div className="transaction-amount">5,254,000</div>
</div>
<div className="transaction-item approved">
<div className="transaction-status">
<div className="status-dot gray"></div>
</div>
<div className="transaction-content">
<div className="transaction-title">*(7000)</div>
<div className="transaction-details">
<span></span>
<span className="separator"></span>
<span>SMS</span>
</div>
</div>
<div className="transaction-amount">5,254,000</div>
</div>
<div className="transaction-item approved">
<div className="transaction-status">
<div className="status-dot gray"></div>
</div>
<div className="transaction-content">
<div className="transaction-title">*(7000)</div>
<div className="transaction-details">
<span></span>
<span className="separator"></span>
<span>SMS</span>
</div>
</div>
<div className="transaction-amount">5,254,000</div>
</div>
</section>
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={() => onClickToNavigate()}
> </button>
</div>
<LinkPaymentFilter
filterOn={filterOn}
setFilterOn={setFilterOn}
></LinkPaymentFilter>
</>
)
}

View File

@@ -0,0 +1,38 @@
interface DetailDeetsInfoSectionProps {
deetsInfo?: any;
show?: boolean;
onClickToShowInfo?: () => void;
}
export const DetailDeetsInfoSection = ({
deetsInfo,
show,
onClickToShowInfo
}: DetailDeetsInfoSectionProps) => {
return (
<>
<div className="txn-section">
<div className="section-title"> </div>
<ul className="kv-list">
<li className="kv-row">
<span className="k"></span>
<span className="v"></span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v">01073937470</span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v"></span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v">mod201705545050</span>
</li>
</ul>
</div>
</>
)
}

View File

@@ -0,0 +1,50 @@
interface DetailPaymentInfoSectionProps {
paymentInfo?: any;
show?: boolean;
onClickToShowInfo?: () => void;
}
export const DetailPaymentInfoSection = ({
paymentInfo,
show,
onClickToShowInfo
}: DetailPaymentInfoSectionProps) => {
return (
<>
<div className="txn-section">
<div className="section-title"> </div>
<ul className="kv-list">
<li className="kv-row">
<span className="k"></span>
<span className="v">*</span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v">SMS</span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v">2025.06.08</span>
</li>
<li className="kv-row">
<span className="k">()</span>
<span className="v">(2)</span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v"></span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v"></span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v">2025.06.08</span>
</li>
</ul>
</div>
</>
)
}

View File

@@ -0,0 +1,58 @@
interface DetailPendingPaymentInfoSectionProps {
paymentInfo?: any;
show?: boolean;
onClickToShowInfo?: () => void;
}
export const DetailPaymentInfoSection = ({
paymentInfo,
show,
onClickToShowInfo
}: DetailPendingPaymentInfoSectionProps) => {
return (
<>
<div className="txn-section">
<div className="section-title"> </div>
<ul className="kv-list">
<li className="kv-row">
<span className="k"></span>
<span className="v"></span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v">2025.06.05</span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v">2025.06.08</span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v">SMS</span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v">*</span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v"></span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v">01073937470</span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v"></span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v">moid201705545050</span>
</li>
</ul>
</div>
</>
)
}

View File

@@ -0,0 +1,58 @@
import moment from 'moment';
import 'moment/dist/locale/ko';
import { LinkPaymentItem } from './link-payment-item';
import { JSX } from 'react';
interface LinkPaymentTransaction {
transactionId: string;
customerName: string;
status: string;
channel: string;
paymentMethod: string;
amount: number;
}
interface LinkPaymentDateGroupProps {
date: string;
items: LinkPaymentTransaction[];
}
export const LinkPaymentDateGroup = ({
date,
items
}: LinkPaymentDateGroupProps) => {
moment.locale('ko');
const getStateDate = () => {
let stateDate = moment(date).format('YY.MM.DD(ddd)');
return stateDate;
};
const getLinkPaymentItem = () => {
const rs: JSX.Element[] = [];
if (items && items.length > 0) {
items.forEach((item, index) => {
const key = 'LinkPaymentItem-' + index;
rs.push(
<LinkPaymentItem
key={key}
transactionId={item.transactionId}
customerName={item.customerName}
status={item.status}
channel={item.channel}
paymentMethod={item.paymentMethod}
amount={item.amount}
/>
)
});
}
return rs;
};
return (
<>
<div className="date-header">{getStateDate()}</div>
{getLinkPaymentItem()}
</>
);
};

View File

@@ -0,0 +1,143 @@
import { IMAGE_ROOT } from "@/shared/constants/common";
import { useState, useEffect } from "react";
import { LinkPaymentFilter } from "./link-payment-filter";
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { PATHS } from "@/shared/constants/paths";
import { LinkPaymentList } from "./link-payment-list";
import { SortOptionsBox } from "./sort-options-box";
import { SortByKeys } from "../../model/types";
export const LinkPaymentDispatchListWrap = () => {
const { navigate } = useNavigate();
const [filterOn, setFilterOn] = useState<boolean>(false);
const [sortBy, setSortBy] = useState<SortByKeys>(SortByKeys.New);
const [listItems, setListItems] = useState({});
const onClickToOpenFilter = () => {
setFilterOn(!filterOn);
};
const onClickToNavigate = () => {
navigate(PATHS.additionalService.linkPayment.request)
}
const onClickToSort = (sort: SortByKeys) => {
setSortBy(sort);
callList({ sortBy: sort });
};
const callList = (option?: {sortBy?: string, val?: string}) => {
setListItems({
'20250608': [
{
transactionId: 'txn1',
customerName: '김*환(7000)',
status: '결제완료',
channel: 'SMS',
paymentMethod: '신용카드',
amount: 5254000
},
{
transactionId: 'txn2',
customerName: '김*환(7000)',
status: '결제완료',
channel: '이메일',
paymentMethod: '신용카드',
amount: 5254000
},
{
transactionId: 'txn3',
customerName: '김*환(7000)',
status: '입금요청',
channel: '이메일',
paymentMethod: '신용카드',
amount: 5254000
},
{
transactionId: 'txn4',
customerName: '김*환(7000)',
status: '결제중단',
channel: 'SMS',
paymentMethod: '',
amount: 5254000
},
{
transactionId: 'txn5',
customerName: '김*환(7000)',
status: '결제실패',
channel: 'SMS',
paymentMethod: '',
amount: 5254000
}
]
});
};
useEffect(() => {
callList();
}, []);
return (
<>
<section className="summary-section">
<div className="credit-controls">
<div>
<input
className="credit-period"
type="text"
value="2025.06.01 ~ 2025.06.30"
readOnly={true}
/>
<button
className="filter-btn"
aria-label="필터"
>
<img
src={IMAGE_ROOT + '/ico_setting.svg'}
alt="검색옵션"
onClick={() => onClickToOpenFilter()}
/>
</button>
</div>
<button
className="download-btn"
aria-label="다운로드"
>
<img
src={IMAGE_ROOT + '/ico_download.svg'}
alt="다운로드"
/>
</button>
</div>
</section>
<section className="filter-section">
<SortOptionsBox
sortBy={sortBy}
onClickToSort={onClickToSort}
>
</SortOptionsBox>
<div className="excrow">
<div className="full-menu-keywords no-padding">
<span className="keyword-tag active"></span>
<span className="keyword-tag"></span>
<span className="keyword-tag"></span>
</div>
</div>
</section>
<LinkPaymentList
listItems={listItems}
/>
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={() => onClickToNavigate()}
> </button>
</div>
<LinkPaymentFilter
filterOn={filterOn}
setFilterOn={setFilterOn}
></LinkPaymentFilter>
</>
)
}

View File

@@ -0,0 +1,62 @@
import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import moment from 'moment';
interface LinkPaymentItemProps {
transactionId: string;
customerName: string;
status: string;
channel: string;
paymentMethod: string;
amount: number;
}
export const LinkPaymentItem = ({
transactionId,
customerName,
status,
channel,
paymentMethod,
amount
}: LinkPaymentItemProps) => {
const { navigate } = useNavigate();
const onClickToNavigate = () => {
navigate(PATHS.additionalService.linkPayment.detail, {
state: {
transactionId: transactionId
}
});
};
const getStatusDotClass = () => {
if (status === '결제완료' || status === '입금요청') {
return 'status-dot blue';
}
return 'status-dot gray';
};
return (
<>
<div
className="transaction-item approved"
onClick={() => onClickToNavigate()}
>
<div className="transaction-status">
<div className={getStatusDotClass()}></div>
</div>
<div className="transaction-content">
<div className="transaction-title">{customerName}</div>
<div className="transaction-details">
<span>{status}</span>
<span className="separator"></span>
<span>{channel}</span>
<span className="separator"></span>
<span>{paymentMethod}</span>
</div>
</div>
<div className="transaction-amount">{amount.toLocaleString()}</div>
</div>
</>
);
};

View File

@@ -0,0 +1,41 @@
import { LinkPaymentDateGroup } from './link-payment-date-group';
interface LinkPaymentTransaction {
transactionId: string;
customerName: string;
status: string;
channel: string;
paymentMethod: string;
amount: number;
}
interface LinkPaymentListProps {
listItems: Record<string, LinkPaymentTransaction[]>;
}
export const LinkPaymentList = ({
listItems
}: LinkPaymentListProps) => {
const getListDateGroup = () => {
let rs = [];
for (const [key, value] of Object.entries(listItems)) {
rs.push(
<LinkPaymentDateGroup
key={key}
date={key}
items={value}
/>
);
}
return rs;
};
return (
<>
<div className="transaction-list">
{getListDateGroup()}
</div>
</>
)
};

View File

@@ -0,0 +1,56 @@
import moment from 'moment';
import 'moment/dist/locale/ko';
import { LinkPaymentPendingItem } from './link-payment-pending-item';
import { JSX } from 'react';
interface LinkPaymentPendingTransaction {
transactionId: string;
customerName: string;
status: string;
channel: string;
amount: number;
}
interface LinkPaymentPendingDateGroupProps {
date: string;
items: LinkPaymentPendingTransaction[];
}
export const LinkPaymentPendingDateGroup = ({
date,
items
}: LinkPaymentPendingDateGroupProps) => {
moment.locale('ko');
const getStateDate = () => {
let stateDate = moment(date).format('YY.MM.DD(ddd)');
return stateDate;
};
const getLinkPaymentPendingItem = () => {
const rs: JSX.Element[] = [];
if (items && items.length > 0) {
items.forEach((item, index) => {
const key = 'LinkPaymentPendingItem-' + index;
rs.push(
<LinkPaymentPendingItem
key={key}
transactionId={item.transactionId}
customerName={item.customerName}
status={item.status}
channel={item.channel}
amount={item.amount}
/>
)
});
}
return rs;
};
return (
<>
<div className="date-header">{getStateDate()}</div>
{getLinkPaymentPendingItem()}
</>
);
};

View File

@@ -0,0 +1,57 @@
import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
interface LinkPaymentPendingItemProps {
transactionId: string;
customerName: string;
status: string;
channel: string;
amount: number;
}
export const LinkPaymentPendingItem = ({
transactionId,
customerName,
status,
channel,
amount
}: LinkPaymentPendingItemProps) => {
const { navigate } = useNavigate();
const onClickToNavigate = () => {
navigate(PATHS.additionalService.linkPayment.pendingDetail, {
state: {
transactionId: transactionId
}
});
};
const getStatusDotClass = () => {
if (status === '발송요청') {
return 'status-dot blue';
}
return 'status-dot gray';
};
return (
<>
<div
className="transaction-item approved"
onClick={() => onClickToNavigate()}
>
<div className="transaction-status">
<div className={getStatusDotClass()}></div>
</div>
<div className="transaction-content">
<div className="transaction-title">{customerName}</div>
<div className="transaction-details">
<span>{status}</span>
<span className="separator"></span>
<span>{channel}</span>
</div>
</div>
<div className="transaction-amount">{amount.toLocaleString()}</div>
</div>
</>
);
};

View File

@@ -0,0 +1,40 @@
import { LinkPaymentPendingDateGroup } from './link-payment-pending-date-group';
interface LinkPaymentPendingTransaction {
transactionId: string;
customerName: string;
status: string;
channel: string;
amount: number;
}
interface LinkPaymentPendingListProps {
listItems: Record<string, LinkPaymentPendingTransaction[]>;
}
export const LinkPaymentPendingList = ({
listItems
}: LinkPaymentPendingListProps) => {
const getListDateGroup = () => {
let rs = [];
for (const [key, value] of Object.entries(listItems)) {
rs.push(
<LinkPaymentPendingDateGroup
key={key}
date={key}
items={value}
/>
);
}
return rs;
};
return (
<>
<div className="transaction-list">
{getListDateGroup()}
</div>
</>
)
};

View File

@@ -0,0 +1,129 @@
import { IMAGE_ROOT } from "@/shared/constants/common";
import { useState, useEffect } from "react";
import { LinkPaymentFilter } from "./link-payment-filter";
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { PATHS } from "@/shared/constants/paths";
import { LinkPaymentPendingList } from "./link-payment-pending-list";
export const LinkPaymentPendingSendWrap = () => {
const { navigate } = useNavigate();
const [filterOn, setFilterOn] = useState<boolean>(false);
const [listItems, setListItems] = useState({});
const onClickToOpenFilter = () => {
setFilterOn(!filterOn);
};
const onClickToNavigate = () => {
navigate(PATHS.additionalService.linkPayment.request)
}
const callList = () => {
setListItems({
'20250608': [
{
transactionId: 'pending1',
customerName: '김*환(7000)',
status: '발송요청',
channel: 'SMS',
amount: 5254000
},
{
transactionId: 'pending2',
customerName: '김*환(7000)',
status: '발송요청',
channel: 'SMS',
amount: 5254000
},
{
transactionId: 'pending3',
customerName: '김*환(7000)',
status: '발송요청',
channel: '이메일',
amount: 5254000
},
{
transactionId: 'pending4',
customerName: '김*환(7000)',
status: '발송취소',
channel: 'SMS',
amount: 5254000
},
{
transactionId: 'pending5',
customerName: '김*환(7000)',
status: '발송취소',
channel: 'SMS',
amount: 5254000
}
]
});
};
useEffect(() => {
callList();
}, []);
return (
<>
<section className="summary-section">
<div className="credit-controls">
<div>
<input
className="credit-period"
type="text"
value="2025.06.01 ~ 2025.06.30"
readOnly={true}
/>
<button
className="filter-btn"
aria-label="필터"
>
<img
src={IMAGE_ROOT + '/ico_setting.svg'}
alt="검색옵션"
onClick={() => onClickToOpenFilter()}
/>
</button>
</div>
<button
className="download-btn"
aria-label="다운로드"
>
<img
src={IMAGE_ROOT + '/ico_download.svg'}
alt="다운로드"
/>
</button>
</div>
</section>
<section className="filter-section">
<div className="sort-options">
<button className="sort-btn active"></button>
<span className="sort-divider">|</span>
<button className="sort-btn"></button>
</div>
<div className="excrow">
<div className="full-menu-keywords no-padding">
<span className="keyword-tag active"></span>
<span className="keyword-tag"></span>
<span className="keyword-tag"></span>
</div>
</div>
</section>
<LinkPaymentPendingList
listItems={listItems}
/>
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={() => onClickToNavigate()}
> </button>
</div>
<LinkPaymentFilter
filterOn={filterOn}
setFilterOn={setFilterOn}
></LinkPaymentFilter>
</>
)
}

View File

@@ -3,7 +3,7 @@ import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import {
LinkPaymentTabKeys,
LinkPaymentTabProps
} from '../model/types'
} from '../../model/types'
export const LinkPaymentTab = ({
activeTab

View File

@@ -0,0 +1,25 @@
import {
SortByKeys,
SortOptionsBoxProps
} from '../../model/types';
export const SortOptionsBox = ({
sortBy,
onClickToSort
}: SortOptionsBoxProps) => {
return (
<>
<div className="sort-options">
<button
className={ `sort-btn ${(sortBy === SortByKeys.New)? 'active': ''}` }
onClick={ () => onClickToSort(SortByKeys.New) }
></button>
<span className="sort-divider">|</span>
<button
className={ `sort-btn ${(sortBy === SortByKeys.Amount)? 'active': ''}` }
onClick={ () => onClickToSort(SortByKeys.Amount) }
></button>
</div>
</>
);
};

View File

@@ -24,9 +24,11 @@ import { SettlementAgencyDetailPage } from './settlement-agency/detail-page';
import { PaymentAgencyListPage } from './payment-agency/list-page';
import { PaymentAgencyDetailPage } from './payment-agency/detail-page';
import { PaymentAgencyRequestPage } from './payment-agency/request-page';
import { LinkPaymentApplyPage } from './link-payment/link-payment-apply-page';
import { LinkPaymentApplyConfirmPage } from './link-payment/link-payment-apply-confirm-page';
import { LinkPaymentApplySuccessPage } from './link-payment/link-payment-apply-success-page';
import { LinkPaymentApplyPage } from './link-payment/apply/link-payment-apply-page';
import { LinkPaymentApplyConfirmPage } from './link-payment/apply/link-payment-apply-confirm-page';
import { LinkPaymentApplySuccessPage } from './link-payment/apply/link-payment-apply-success-page';
import { LinkPaymentDetailPage } from './link-payment/link-payment-detail-page';
import { LinkPaymentPendingDetailPage } from './link-payment/link-payment-pending-detail-page';
export const AdditionalServicePages = () => {
return (
@@ -49,6 +51,8 @@ export const AdditionalServicePages = () => {
<Route path={ROUTE_NAMES.additionalService.linkPayment.request} element={<LinkPaymentApplyPage />} />
<Route path={ROUTE_NAMES.additionalService.linkPayment.requestConfirm} element={<LinkPaymentApplyConfirmPage />} />
<Route path={ROUTE_NAMES.additionalService.linkPayment.confirmSuccess} element={<LinkPaymentApplySuccessPage />} />
<Route path={ROUTE_NAMES.additionalService.linkPayment.detail} element={<LinkPaymentDetailPage />} />
<Route path={ROUTE_NAMES.additionalService.linkPayment.pendingDetail} element={<LinkPaymentPendingDetailPage />} />
</Route>
<Route path={ROUTE_NAMES.additionalService.kakaoPaymentNotification.base}>
<Route path={ROUTE_NAMES.additionalService.kakaoPaymentNotification.list} element={<KakaoPaymentNotificationListPage />} />

View File

@@ -1,6 +1,6 @@
import {useState} from 'react';
import {LinkPaymentStep1} from '@/entities/additional-service/ui/link-payment-step1';
import {LinkPaymentStep2} from '@/entities/additional-service/ui/link-payment-step2';
import {LinkPaymentStep1} from '@/entities/additional-service/ui/link-payment/apply/link-payment-step1';
import {LinkPaymentStep2} from '@/entities/additional-service/ui/link-payment/apply/link-payment-step2';
import {HeaderType} from '@/entities/common/model/types';
import {ProcessStep} from '@/entities/transaction/model/types';
import {useSetFooterMode, useSetHeaderTitle, useSetHeaderType} from '@/widgets/sub-layout/use-sub-layout';

View File

@@ -0,0 +1,119 @@
import { useEffect, useState } from 'react';
import { PATHS } from '@/shared/constants/paths';
import { useLocation } from 'react-router';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { DetailPaymentInfoSection } from '@/entities/additional-service/ui/link-payment/detail/detail-payment-info-section';
import { HeaderType } from '@/entities/common/model/types';
import { DetailInfoSectionProps } from '@/entities/additional-service/model/types';
import { IMAGE_ROOT } from '@/shared/constants/common';
import {
useSetOnBack,
useSetHeaderTitle,
useSetHeaderType,
useSetFooterMode
} from '@/widgets/sub-layout/use-sub-layout';
import { DetailDeetsInfoSection } from '@/entities/additional-service/ui/link-payment/detail/detail-deets-Info-section';
import { overlay } from 'overlay-kit';
import { Dialog } from '@/shared/ui/dialogs/dialog';
export const LinkPaymentDetailPage = () => {
const { navigate } = useNavigate();
const location = useLocation();
const [transactionId, setTransactionId] = useState<string>(location?.state?.transactionId || '');
const [paymentInfo, setPaymentInfo] = useState<any>();
const [deetsInfo, setDeetsInfo] = useState<any>();
const [showPayment, setShowPayment] = useState<boolean>(false);
const [showDeets, setShowDeets] = useState<boolean>(false);
useSetHeaderTitle('링크결제 상세');
useSetHeaderType(HeaderType.RightClose);
useSetOnBack(() => {
navigate(PATHS.additionalService.linkPayment.dispatchList);
});
useSetFooterMode(false);
const onClickToNavigate = (path: string) => {
let timeout = setTimeout(() => {
clearTimeout(timeout);
navigate(PATHS.additionalService.linkPayment.dispatchList, {
});
}, 10)
};
const onClickToShowInfo = () => {
setShowPayment(!showPayment);
};
const onClickToCancel = () => {
let msg = '재발송 하시겠습니까?';
overlay.open(({
isOpen,
close,
unmount
}) => {
return (
<Dialog
afterLeave={ unmount }
open={ isOpen }
onClose={ close }
onConfirmClick={ () => onClickToNavigate(PATHS.additionalService.linkPayment.dispatchList) }
message={ msg }
buttonLabel={['취소', '확인']}
/>
);
});
};
return (
<>
<main className="full-height">
<div className="tab-content">
<div className="tab-pane sub active">
<div className="option-list">
<div className="txn-detail">
<div className="txn-num-group">
<div className="txn-amount">
<div className="value">5,254,000<span className="unit"></span></div>
</div>
<div className="txn-mid">
<span className="value"></span>
</div>
<div className="txn-mid">
<span className="value">2025.06.08</span>
</div>
</div>
<div className="txn-divider minus"></div>
<DetailPaymentInfoSection
paymentInfo={paymentInfo}
show={showPayment}
onClickToShowInfo={onClickToShowInfo}
/>
<div className="txn-divider minus"></div>
<DetailDeetsInfoSection
deetsInfo={deetsInfo}
show={showDeets}
onClickToShowInfo={onClickToShowInfo}
/>
</div>
</div>
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={ () => onClickToCancel() }
></button>
</div>
</div>
</div>
</main>
</>
)
};

View File

@@ -3,9 +3,9 @@ import { useState } from 'react';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { IMAGE_ROOT } from '@/shared/constants/common';
import { HeaderType } from '@/entities/common/model/types';
import { LinkPaymentTab } from '@/entities/additional-service/ui/link-payment-tab';
import { LinkPaymentTab } from '@/entities/additional-service/ui/link-payment/link-payment-tab';
import { LinkPaymentTabKeys } from '@/entities/additional-service/model/types';
import { LinkPaymentDispatchListWrap } from '../../../entities/additional-service/ui/link-payment-dispatch-list-wrap';
import { LinkPaymentDispatchListWrap } from '../../../entities/additional-service/ui/link-payment/link-payment-dispatch-list-wrap';
import {
useSetHeaderTitle,
useSetHeaderType,

View File

@@ -0,0 +1,110 @@
import { useEffect, useState } from 'react';
import { PATHS } from '@/shared/constants/paths';
import { useLocation } from 'react-router';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { DetailPaymentInfoSection } from '@/entities/additional-service/ui/link-payment/detail/detail-payment-info-section';
import { HeaderType } from '@/entities/common/model/types';
import { IMAGE_ROOT } from '@/shared/constants/common';
import {
useSetOnBack,
useSetHeaderTitle,
useSetHeaderType,
useSetFooterMode
} from '@/widgets/sub-layout/use-sub-layout';
import { DetailDeetsInfoSection } from '@/entities/additional-service/ui/link-payment/detail/detail-deets-Info-section';
import { overlay } from 'overlay-kit';
import { Dialog } from '@/shared/ui/dialogs/dialog';
export const LinkPaymentPendingDetailPage = () => {
const { navigate } = useNavigate();
const location = useLocation();
const [transactionId, setTransactionId] = useState<string>(location?.state?.transactionId || '');
const [paymentInfo, setPaymentInfo] = useState<any>();
const [deetsInfo, setDeetsInfo] = useState<any>();
const [showPayment, setShowPayment] = useState<boolean>(false);
const [showDeets, setShowDeets] = useState<boolean>(false);
useSetHeaderTitle('링크결제 상세_발송대기');
useSetHeaderType(HeaderType.RightClose);
useSetOnBack(() => {
navigate(PATHS.additionalService.linkPayment.pendingSend);
});
useSetFooterMode(false);
const onClickToNavigate = (path: string) => {
let timeout = setTimeout(() => {
clearTimeout(timeout);
navigate(PATHS.additionalService.linkPayment.pendingSend, {
});
}, 10)
};
const onClickToShowInfo = () => {
setShowPayment(!showPayment);
};
const onClickToCancel = () => {
let msg = '삭제 하시겠습니까?';
overlay.open(({
isOpen,
close,
unmount
}) => {
return (
<Dialog
afterLeave={ unmount }
open={ isOpen }
onClose={ close }
onConfirmClick={ () => onClickToNavigate(PATHS.additionalService.linkPayment.pendingSend) }
message={ msg }
buttonLabel={['취소', '확인']}
/>
);
});
};
return (
<>
<main className="full-height">
<div className="tab-content">
<div className="tab-pane sub active">
<div className="option-list">
<div className="txn-detail">
<div className="txn-num-group">
<div className="txn-amount">
<div className="value">3,500,000<span className="unit"></span></div>
</div>
<div className="txn-mid">
<span className="value"></span>
</div>
<div className="txn-mid">
<span className="value">2025.06.09</span>
</div>
</div>
<div className="txn-divider minus"></div>
<DetailPaymentInfoSection
paymentInfo={paymentInfo}
show={showPayment}
onClickToShowInfo={onClickToShowInfo}
/>
</div>
</div>
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={ () => onClickToCancel() }
></button>
</div>
</div>
</div>
</main>
</>
)
};

View File

@@ -3,16 +3,16 @@ import { useState } from 'react';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { IMAGE_ROOT } from '@/shared/constants/common';
import { HeaderType } from '@/entities/common/model/types';
import { LinkPaymentTab } from '@/entities/additional-service/ui/link-payment-tab';
import { LinkPaymentTab } from '@/entities/additional-service/ui/link-payment/link-payment-tab';
import { LinkPaymentTabKeys } from '@/entities/additional-service/model/types';
import { LinkPaymentPendingSendWrap } from '../../../entities/additional-service/ui/link-payment-pending-send-wrap';
import { LinkPaymentPendingSendWrap } from '../../../entities/additional-service/ui/link-payment/link-payment-pending-send-wrap';
import {
useSetHeaderTitle,
useSetHeaderType,
useSetFooterMode,
useSetOnBack
} from '@/widgets/sub-layout/use-sub-layout';
import { LinkPaymentFilter } from '@/entities/additional-service/ui/link-payment-filter';
import { LinkPaymentFilter } from '@/entities/additional-service/ui/link-payment/link-payment-filter';
export const LinkPaymentPendingSendPage = () => {
const { navigate } = useNavigate();

View File

@@ -182,6 +182,14 @@ export const PATHS: RouteNamesType = {
confirmSuccess: generatePath(
`${ROUTE_NAMES.additionalService.base}${ROUTE_NAMES.additionalService.linkPayment.base}`,
ROUTE_NAMES.additionalService.linkPayment.confirmSuccess,
),
detail: generatePath(
`${ROUTE_NAMES.additionalService.base}${ROUTE_NAMES.additionalService.linkPayment.base}`,
ROUTE_NAMES.additionalService.linkPayment.detail,
),
pendingDetail: generatePath(
`${ROUTE_NAMES.additionalService.base}${ROUTE_NAMES.additionalService.linkPayment.base}`,
ROUTE_NAMES.additionalService.linkPayment.pendingDetail,
)
},
kakaoPaymentNotification: {

View File

@@ -86,7 +86,9 @@ export const ROUTE_NAMES = {
pendingSend: 'pending-send',
request: 'request',
requestConfirm: 'request-confirm',
confirmSuccess: 'confirm-success'
confirmSuccess: 'confirm-success',
detail: 'detail',
pendingDetail: 'pending-detail'
},
kakaoPaymentNotification: {
base: '/kakao-payment-notification/*',