상세 수정

This commit is contained in:
focp212@naver.com
2025-11-03 20:57:55 +09:00
parent 344e5c324a
commit d2b477e7bd
38 changed files with 1569 additions and 256 deletions

View File

@@ -16,6 +16,23 @@ export const DEFAULT_PAGE_PARAM = {
sortType: SortTypeKeys.LATEST,
};
export const DetailMotionVariants = {
hidden: {
x: '100%'
},
visible: {
x: '0%'
},
};
export const DetailMotionDuration = {
duration: 0.3
};
export const DetailMotionStyle = {
width: '100%',
height: '100%'
};
export const FilterMotionVariants = {
hidden: {
x: '100%'

View File

@@ -6,21 +6,19 @@ import { useTranslation } from 'react-i18next';
import { IMAGE_ROOT } from '@/shared/constants/common';
export const HomeNoticeItem = ({
seq,
title,
informCl,
regDt,
noticeItem,
setDetailData,
}: NoticeItemProps) => {
const { navigate } = useNavigate();
const { t } = useTranslation();
const onClickToDetail = () => {
navigate(PATHS.support.notice.detail, {
state: {
seq: seq,
from: PATHS.home
}
})
if(setDetailData){
setDetailData({
seq: noticeItem.seq,
detailOn: true
});
}
};
return (
@@ -30,8 +28,8 @@ export const HomeNoticeItem = ({
onClick={ () => onClickToDetail() }
>
<div className="notice-content">
<div className="notice-title">{ title }</div>
<div className="notice-meta">{ t(`support.notice.categories.${informCl}`) }<span>{ moment(regDt).format('YY년 MM월 DD일') }</span></div>
<div className="notice-title">{ noticeItem.title }</div>
<div className="notice-meta">{ t(`support.notice.categories.${noticeItem.informCl}`) }<span>{ noticeItem.regDt? moment(noticeItem.regDt).format('YY년 MM월 DD일'): '' }</span></div>
</div>
<div className="notice-arrow">
<img

View File

@@ -1,31 +1,43 @@
import { useEffect, useState } from 'react';
import { useNoticeListMutation } from '@/entities/support/api/use-notice-list-mutation';
import { DEFAULT_PAGE_PARAM } from '@/entities/common/model/constant';
import { NoticeItem } from '@/entities/support/model/types';
import { DetailData, NoticeItem } from '@/entities/support/model/types';
import { HomeNoticeItem } from './home-notice-item';
import { useTranslation } from 'react-i18next';
import { NoticeDetail } from '@/entities/support/ui/detail/notice-detail';
export const HomeNoticeList = () => {
const { t } = useTranslation();
const [pageParam, setPageParam] = useState(DEFAULT_PAGE_PARAM);
const [resultList, setResultList] = useState<Array<NoticeItem>>([]);
const [detailOn, setDetailOn] = useState<boolean>(false);
const [detailSeq, setDetailSeq] = useState<number>(0);
const { mutateAsync: noticeList } = useNoticeListMutation();
const setDetailData = (detailData: DetailData) => {
setDetailOn(detailData.detailOn);
if(detailData?.seq){
setDetailSeq(detailData?.seq);
}
};
const getItems = () => {
let rs = [];
let maxCnt = (!!resultList && resultList.length < 4)? resultList.length: 4;
for(let i=0;i<maxCnt;i++){
rs.push(
<HomeNoticeItem
key={ `key-home-notice-item-${i}` }
seq={ resultList[i]?.seq }
title={ resultList[i]?.title }
informCl={ resultList[i]?.informCl }
regDt={ resultList[i]?.regDt }
></HomeNoticeItem>
);
let noticeItem = resultList[i];
if(noticeItem){
rs.push(
<HomeNoticeItem
key={ `key-home-notice-item-${i}` }
noticeItem={ noticeItem }
setDetailData={ setDetailData }
></HomeNoticeItem>
);
}
}
return rs;
};
@@ -56,6 +68,11 @@ export const HomeNoticeList = () => {
}
</div>
</div>
<NoticeDetail
detailOn={ detailOn }
setDetailOn={ setDetailOn }
seq={ detailSeq }
></NoticeDetail>
</>
);
};

View File

@@ -21,9 +21,10 @@ export interface FaqListResponse extends DefaulResponsePagination {
hasNext: boolean;
nextCursor: string | null;
};
export interface FaqItemProps extends FaqItem {
}
export interface FaqItemProps {
faqItem: FaqItem,
setDetailData?: (detailData: DetailData) => void;
};
export interface QnaListParams extends SupportParams {
statusCode?: string;
page?: DefaultRequestPagination;
@@ -45,8 +46,15 @@ export interface QnaItem {
export interface QnaListResponse extends DefaulResponsePagination {
content: Array<QnaItem>
};
export interface QnaItemProps extends QnaItem {
export interface DetailData {
qnaItem?: QnaItem;
faqItem?: FaqItem;
seq?: number;
detailOn: boolean;
};
export interface QnaItemProps {
qnaItem: QnaItem;
setDetailData?: (detailData: DetailData) => void;
};
export interface QnaSaveParams extends SupportParams {
requestType: string;
@@ -100,6 +108,7 @@ export interface NoticeDetailParams {
export interface NoticeDetailResponse extends NoticeItem {
};
export interface NoticeItemProps extends NoticeItem {
}
export interface NoticeItemProps {
noticeItem: NoticeItem;
setDetailData?: (detailData: DetailData) => void;
};

View File

@@ -0,0 +1,71 @@
import { useEffect, useState } from 'react';
import { motion } from 'framer-motion';
import { useTranslation } from 'react-i18next';
import { FaqItem } from '../../model/types';
import { DetailMotionDuration, DetailMotionStyle, DetailMotionVariants } from '@/entities/common/model/constant';
import { FullMenuClose } from '@/entities/common/ui/full-menu-close';
export interface FaqDetaillProps {
detailOn: boolean;
setDetailOn: (detailOn: boolean) => void;
faqItem: FaqItem
};
export const FaqDetail = ({
detailOn,
setDetailOn,
faqItem
}: FaqDetaillProps) => {
const { t } = useTranslation();
const [cursorId, setCursorId] = useState<number>();
const [seq, setSeq] = useState<string>();
const [category, setCategory] = useState<string>();
const [title, setTitle] = useState<string>();
const [contents, setContents] = useState<string>();
const onClickToClose = () => {
setDetailOn(false);
};
useEffect(() => {
setCursorId(faqItem?.cursorId);
setSeq(faqItem?.seq);
setCategory(faqItem?.category);
setTitle(faqItem?.title);
setContents(faqItem?.contents);
}, [faqItem]);
return (
<>
<motion.div
className="full-menu-modal"
initial="hidden"
animate={ (detailOn)? 'visible': 'hidden' }
variants={ DetailMotionVariants }
transition={ DetailMotionDuration }
style={ DetailMotionStyle }
>
{ contents &&
<div className="full-menu-container pdw-16">
<div className="full-menu-header">
<div className="full-menu-title center">{ t('support.qna.title') }</div>
<div className="full-menu-actions">
<FullMenuClose
addClass="full-menu-close"
onClickToCallback={ onClickToClose }
></FullMenuClose>
</div>
</div>
<div className="tab-pane sub active">
<div className="faq-detail">
<div className="faq-detail__title">{ title }</div>
<div className="faq-detail__divider"></div>
<div className="faq-detail__body" dangerouslySetInnerHTML={{ __html: contents || '' }}></div>
</div>
</div>
</div>
}
</motion.div>
</>
);
};

View File

@@ -0,0 +1,81 @@
import { useTranslation } from 'react-i18next';
import { motion } from 'framer-motion';
import { useLocation } from 'react-router';
import { NoticeDetailParams, NoticeDetailResponse, NoticeItem } from '../../model/types';
import { useEffect, useState } from 'react';
import { useNoticeDetailMutation } from '../../api/use-notice-detail-mutation';
import moment from 'moment';
import { DetailMotionDuration, DetailMotionStyle, DetailMotionVariants } from '@/entities/common/model/constant';
import { FullMenuClose } from '@/entities/common/ui/full-menu-close';
export interface NoticeDetaillProps {
detailOn: boolean;
setDetailOn: (detailOn: boolean) => void;
seq: number;
};
export const NoticeDetail = ({
detailOn,
setDetailOn,
seq
}: NoticeDetaillProps) => {
const location = useLocation();
const { t } = useTranslation();
const [result, setResult] = useState<NoticeItem>({});
const { mutateAsync: noticeDetail } = useNoticeDetailMutation();
const callDetail = () => {
let detailParams: NoticeDetailParams = {
seq: seq,
};
noticeDetail(detailParams).then((rs: NoticeDetailResponse) => {
setResult(rs);
});
};
const onClickToClose = () => {
setDetailOn(false);
};
useEffect(() => {
callDetail();
}, [seq]);
return (
<>
<motion.div
className="full-menu-modal"
initial="hidden"
animate={ (detailOn)? 'visible': 'hidden' }
variants={ DetailMotionVariants }
transition={ DetailMotionDuration }
style={ DetailMotionStyle }
>
{ result.informCl &&
<div className="full-menu-container pdw-16">
<div className="full-menu-header">
<div className="full-menu-title center">{ t('support.notice.title') }</div>
<div className="full-menu-actions">
<FullMenuClose
addClass="full-menu-close"
onClickToCallback={ onClickToClose }
></FullMenuClose>
</div>
</div>
<div className="tab-pane sub active">
<div className="option-list">
<div className="notice-detail">
<div className="notice-detail__title">{ result.title }</div>
<div className="notice-detail__meta">{ result.regDt? moment(result.regDt).format('YYYY.MM.DD'): '' } | { t(`support.notice.categories.${result.informCl}`) }</div>
<div className="notice-detail__divider"></div>
<div className="notice-detail__body" dangerouslySetInnerHTML={{ __html: result.contents || '' }}></div>
</div>
</div>
</div>
</div>
}
</motion.div>
</>
);
};

View File

@@ -0,0 +1,110 @@
import moment from 'moment';
import { motion } from 'framer-motion';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { QnaItem } from '../../model/types';
import { DetailMotionDuration, DetailMotionStyle, DetailMotionVariants } from '@/entities/common/model/constant';
import { FullMenuClose } from '@/entities/common/ui/full-menu-close';
export interface qnaDetaillProps {
detailOn: boolean;
setDetailOn: (detailOn: boolean) => void;
qnaItem: QnaItem;
};
export const QnaDetail = ({
detailOn,
setDetailOn,
qnaItem
}: qnaDetaillProps) => {
const { t } = useTranslation();
const [answer, setAnswer] = useState<string>();
const [answerDate, setAnswerDate] = useState<string>();
const [contents, setContents] = useState<string>();
const [corpName, setCorpName] = useState<string | null>();
const [cursorId, setCursorId] = useState<number>();
const [requestDate, setRequestDate] = useState<string>();
const [requestName, setRequestName] = useState<string>();
const [requestType, setRequestType] = useState<string>();
const [sendEmail, setSendEmail] = useState<string | null>();
const [seq, setSeq] = useState<string>();
const [statusCode, setStatusCode] = useState<string>();
const [title, setTitle] = useState<string>();
const onClickToClose = () => {
setDetailOn(false);
};
useEffect(() => {
setAnswer(qnaItem?.answer);
setAnswerDate(qnaItem?.answerDate);
setContents(qnaItem?.contents);
setCorpName(qnaItem?.corpName);
setCursorId(qnaItem?.cursorId);
setRequestDate(qnaItem?.requestDate);
setRequestName(qnaItem?.requestName);
setRequestType(qnaItem?.requestType);
setSendEmail(qnaItem?.sendEmail);
setSeq(qnaItem?.seq);
setStatusCode(qnaItem?.statusCode);
setTitle(qnaItem?.title);
}, [qnaItem]);
return (
<>
<motion.div
className="full-menu-modal"
initial="hidden"
animate={ (detailOn)? 'visible': 'hidden' }
variants={ DetailMotionVariants }
transition={ DetailMotionDuration }
style={ DetailMotionStyle }
>
{ statusCode &&
<div className="full-menu-container pdw-16">
<div className="full-menu-header">
<div className="full-menu-title center">{ t('support.qna.title') }</div>
<div className="full-menu-actions">
<FullMenuClose
addClass="full-menu-close"
onClickToCallback={ onClickToClose }
></FullMenuClose>
</div>
</div>
<div className="tab-pane active">
<div className="inq-detail">
<div className="inq-detail__head">
<div className="inq-detail__row">
<span className="inq-badge">{t('support.qna.detailLabels.title')}</span>
<span className="inq-head-text bold">{ title }</span>
</div>
<div className="inq-detail__row">
<span className="inq-badge">{t('support.qna.detailLabels.type')}</span>
<span className="inq-head-text">{ t(`support.qna.categories.${requestType}`) }</span>
</div>
<div className="inq-detail__row">
<span className="inq-badge">{t('support.qna.detailLabels.registrationDate')}</span>
<span className="inq-head-text">{ !!requestDate? moment(requestDate).format('YYYY.MM.DD'): '' }</span>
</div>
<div className="inq-detail__row">
<span className="inq-badge">{t('support.qna.detailLabels.answerDate')}</span>
<span className="inq-head-text">{ !!answerDate? moment(answerDate).format('YYYY.MM.DD'): '' }</span>
</div>
</div>
<div className="inq-detail__divider"></div>
<div className="inq-detail__section">
<div className="inq-detail__section-title">{t('support.qna.detailLabels.inquiryAnswer')}</div>
<div className="inq-detail__body" dangerouslySetInnerHTML={{ __html: answer || '' }}></div>
</div>
<div className="inq-detail__section">
<div className="inq-detail__section-title">{t('support.qna.detailLabels.inquiryContents')}</div>
<div className="inq-detail__body" dangerouslySetInnerHTML={{ __html: contents || '' }}></div>
</div>
</div>
</div>
</div>
}
</motion.div>
</>
);
};

View File

@@ -4,36 +4,29 @@ import { FaqItemProps } from '../model/types';
import { useTranslation } from 'react-i18next';
export const SupportFaqItem = ({
cursorId,
seq,
category,
title,
contents,
faqItem,
setDetailData
}: FaqItemProps) => {
const { navigate } = useNavigate();
const { t } = useTranslation();
const onClickToDetail = () => {
navigate(PATHS.support.faq.detail, {
state: {
cursorId,
seq,
category,
title,
contents
}
});
if(setDetailData){
setDetailData({
faqItem: faqItem,
detailOn: true
});
}
};
return (
<>
<div
className="faq-row"
onClick={ () => onClickToDetail() }
onClick={ onClickToDetail }
>
<div className="faq-txt">
<div className="faq-title">{ title }</div>
<div className="faq-tag">{ t('support.faq.categories.' + category) }</div>
<div className="faq-title">{ faqItem.title }</div>
<div className="faq-tag">{ t('support.faq.categories.' + faqItem.category) }</div>
</div>
</div>
</>

View File

@@ -5,21 +5,19 @@ import { NoticeItemProps } from '../model/types';
import { useTranslation } from 'react-i18next';
export const SupportNoticeItem = ({
seq,
title,
informCl,
regDt,
noticeItem,
setDetailData,
}: NoticeItemProps) => {
const { navigate } = useNavigate();
const { t } = useTranslation();
const onClickToDetail = () => {
navigate(PATHS.support.notice.detail, {
state: {
seq: seq,
from: PATHS.support.notice.list
}
})
if(setDetailData){
setDetailData({
seq: noticeItem.seq,
detailOn: true
});
}
};
return (
@@ -29,9 +27,9 @@ export const SupportNoticeItem = ({
onClick={ () => onClickToDetail() }
>
<div className="notice-txt">
<div className="notice-title-114">{ title }</div>
<div className="notice-title-114">{ noticeItem.title }</div>
<div className="notice-meta-114">
<span className="blue">{ t(`support.notice.categories.${informCl}`) }</span> <span>{ moment(regDt).format('YYYY.MM.DD HH:mm:ss') }</span>
<span className="blue">{ t(`support.notice.categories.${noticeItem.informCl}`) }</span> <span>{ noticeItem.regDt? moment(noticeItem.regDt).format('YYYY.MM.DD HH:mm:ss'): '' }</span>
</div>
</div>
</div>

View File

@@ -1,42 +1,19 @@
import moment from 'moment';
import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { QnaItemProps } from '../model/types';
import { useTranslation } from 'react-i18next';
export const SupportQnaItem = ({
answer,
answerDate,
contents,
corpName,
cursorId,
requestDate,
requestName,
requestType,
sendEmail,
seq,
statusCode,
title
qnaItem,
setDetailData
}: QnaItemProps) => {
const { navigate } = useNavigate();
const { t } = useTranslation();
const onClickToDetail = () => {
navigate(PATHS.support.qna.detail, {
state: {
answer: answer,
answerDate: answerDate,
contents: contents,
corpName: corpName,
cursorId: cursorId,
requestDate: requestDate,
requestName: requestName,
requestType: requestType,
sendEmail: sendEmail,
seq: seq,
statusCode: statusCode,
title: title
}
});
if(setDetailData){
setDetailData({
qnaItem: qnaItem,
detailOn: true
});
}
};
return (
@@ -46,12 +23,12 @@ export const SupportQnaItem = ({
onClick={ () => onClickToDetail() }
>
<div className="inq-line">
<div className="inq-title-text">{ title }</div>
<div className="inq-title-text">{ qnaItem.title }</div>
<div className="inq-meta">
{t('support.qna.registrationDate')}<span>{ moment(requestDate).format('YYYY.MM.DD') }</span>
<span className="sai"></span>{t('support.qna.status')} <span>[{t(`support.qna.statusCode.${statusCode}`)}]</span>
{t('support.qna.registrationDate')}<span>{ qnaItem.requestDate? moment(qnaItem.requestDate).format('YYYY.MM.DD'): '' }</span>
<span className="sai"></span>{t('support.qna.status')} <span>[{t(`support.qna.statusCode.${qnaItem.statusCode}`)}]</span>
</div>
<span className={`dot ${(statusCode === '03')? 'blue': 'gray'}`}></span>
<span className={`dot ${(qnaItem.statusCode === '03')? 'blue': 'gray'}`}></span>
</div>
</div>
</>

View File

@@ -136,29 +136,40 @@ export enum BillingPaymentMethod {
MOBILE_PAYMENT = 'MOBILE_PAYMENT'
};
export interface DetailData {
tid: string;
serviceCode?: string;
detailOn: boolean;
}
export interface ListItemProps extends AllTransactionListItem, CashReceiptListItem, EscrowListItem, BillingListItem {
transactionCategory?: TransactionCategory;
setDetailData?: (detailData: DetailData) => void;
};
export interface ListDateGroupProps {
transactionCategory?: TransactionCategory;
date?: string;
items?: Array<ListItemProps>;
setDetailData?: (detailData: DetailData) => void;
};
export interface AllTransactionListProps {
transactionCategory: TransactionCategory;
listItems: Array<ListItemProps>;
setDetailData: (detailData: DetailData) => void;
};
export interface CashReceiptListProps {
transactionCategory: TransactionCategory;
listItems: Array<ListItemProps>;
setDetailData: (detailData: DetailData) => void;
};
export interface EscrowListProps {
transactionCategory: TransactionCategory;
listItems: Array<ListItemProps>;
setDetailData: (detailData: DetailData) => void;
};
export interface BillingListProps {
transactionCategory: TransactionCategory;
listItems: Array<ListItemProps>;
setDetailData: (detailData: DetailData) => void;
};
export interface AllTransactionListItem {
tid?: string;

View File

@@ -28,12 +28,7 @@ export const AllTransactionCancelPreventBond = ({
const { navigate } = useNavigate();
const [item, setItem] = useState<DebtPreventionCancelDisplayInfo | null | undefined>(debtPreventionCancelDisplayInfo);
const onClickToClose = () => {
navigate(PATHS.transaction.allTransaction.detail, {
state: {
serviceCode: serviceCode,
tid: tid
}
});
setCancelPreventBondOn(false);
};
const callTransactionCancel = () => {

View File

@@ -3,7 +3,8 @@ import { ListDateGroup } from './list-date-group';
export const AllTransactionList = ({
transactionCategory,
listItems
listItems,
setDetailData
}: AllTransactionListProps) => {
const getListDateGroup = () => {
let rs = [];
@@ -26,6 +27,7 @@ export const AllTransactionList = ({
key={ date + '-' + i }
date={ date }
items={ list }
setDetailData={ setDetailData }
></ListDateGroup>
);
}
@@ -43,6 +45,7 @@ export const AllTransactionList = ({
key={ date + '-last' }
date={ date }
items={ list }
setDetailData={ setDetailData }
></ListDateGroup>
);
}

View File

@@ -6,10 +6,9 @@ import { useTranslation } from 'react-i18next';
export const BillingList = ({
transactionCategory,
listItems
listItems,
setDetailData
}: BillingListProps) => {
const { navigate } = useNavigate();
const { t } = useTranslation();
const getListDateGroup = () => {
let rs = [];
@@ -31,6 +30,7 @@ export const BillingList = ({
key={ date + '-' + i }
date={ date }
items={ list }
setDetailData={ setDetailData }
></ListDateGroup>
);
}
@@ -48,27 +48,20 @@ export const BillingList = ({
key={ date + '-last' }
date={ date }
items={ list }
setDetailData={ setDetailData }
></ListDateGroup>
);
}
return rs;
};
const onClickToNavigate = () => {
navigate(PATHS.transaction.billing.charge);
};
return (
<>
<div className="transaction-list">
{ getListDateGroup() }
</div>
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={ () => onClickToNavigate() }
>{ t('transaction.list.paymentRequest') }</button>
</div>
</>
);
};

View File

@@ -6,7 +6,8 @@ import { useTranslation } from 'react-i18next';
export const CashReceiptList = ({
transactionCategory,
listItems
listItems,
setDetailData
}: CashReceiptListProps) => {
const { navigate } = useNavigate();
const { t } = useTranslation();
@@ -31,6 +32,7 @@ export const CashReceiptList = ({
key={ date + '-' + i }
date={ date }
items={ list }
setDetailData={ setDetailData }
></ListDateGroup>
);
}
@@ -48,27 +50,19 @@ export const CashReceiptList = ({
key={ date + '-last' }
date={ date }
items={ list }
setDetailData={ setDetailData }
></ListDateGroup>
);
}
return rs;
};
const onClickToNavigate = () => {
navigate(PATHS.transaction.cashReceipt.handWrittenIssuance);
};
return (
<>
<div className="transaction-list">
{ getListDateGroup() }
</div>
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={ () => onClickToNavigate() }
>{ t('transaction.list.manualIssuance') }</button>
</div>
</>
);
};

View File

@@ -0,0 +1,238 @@
import { useEffect, useState } from 'react';
import { motion } from 'framer-motion';
import { PATHS } from '@/shared/constants/paths';
import { Dialog } from '@/shared/ui/dialogs/dialog';
import { overlay } from 'overlay-kit';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { useAllTransactionDetailMutation } from '@/entities/transaction/api/use-all-transaction-detail-mutation';
import { AmountInfoSection } from '@/entities/transaction/ui/section/amount-info-section';
import { ImportantInfoSection } from '@/entities/transaction/ui/section/important-info-section';
import { PaymentInfoSection } from '@/entities/transaction/ui/section/payment-info-section';
import { TransactionInfoSection } from '@/entities/transaction/ui/section/transaction-info-section';
import { SettlementInfoSection } from '@/entities/transaction/ui/section/settlement-info-section';
import { PartCancelInfoSection } from '@/entities/transaction/ui/section/part-cancel-info-section';
import {
TransactionCategory,
AllTransactionDetailParams,
DetailResponse,
AmountInfo,
ImportantInfo,
PaymentInfo,
TransactionInfo,
SettlementInfo,
PartCancelInfo,
InfoSectionKeys
} from '@/entities/transaction/model/types';
import { useTranslation } from 'react-i18next';
import {
DetailMotionDuration,
DetailMotionStyle,
DetailMotionVariants
} from '@/entities/common/model/constant';
import { FullMenuClose } from '@/entities/common/ui/full-menu-close';
export interface AllTransactionDetailProps {
detailOn: boolean;
setDetailOn: (detailOn: boolean) => void;
tid: string;
serviceCode: string;
};
export const AllTransactionDetail = ({
detailOn,
setDetailOn,
tid,
serviceCode
}: AllTransactionDetailProps) => {
const { navigate } = useNavigate();
const { t } = useTranslation();
const [amountInfo, setAmountInfo] = useState<AmountInfo>();
const [importantInfo, setImportantInfo] = useState<ImportantInfo>();
const [paymentInfo, setPaymentInfo] = useState<PaymentInfo>();
const [transactionInfo, setTransactionInfo] = useState<TransactionInfo>();
const [settlementInfo, setSettlementInfo] = useState<SettlementInfo>();
const [partCancelInfo, setPartCancelInfo] = useState<PartCancelInfo>();
const [showAmountInfo, setShowAmountInfo] = useState<boolean>(false);
const [showPaymentInfo, setShowPaymentInfo] = useState<boolean>(false);
const [showTransactionInfo, setShowTransactionInfo] = useState<boolean>(false);
const [showSettlementInfo, setShowSettlementInfo] = useState<boolean>(false);
const [showPartCancelInfo, setShowPartCancelInfo] = useState<boolean>(false);
const { mutateAsync: allTransactionDetail } = useAllTransactionDetailMutation();
const callDetail = () => {
let allTransactionDetailParams: AllTransactionDetailParams = {
serviceCode: serviceCode,
tid: tid
};
allTransactionDetail(allTransactionDetailParams).then((rs: DetailResponse) => {
setAmountInfo(rs.amountInfo);
setImportantInfo(rs.importantInfo);
setPaymentInfo(rs.paymentInfo);
setTransactionInfo(rs.transactionInfo);
setSettlementInfo(rs.settlementInfo);
setPartCancelInfo(rs.partCancelInfo);
});
};
useEffect(() => {
if(!!detailOn && serviceCode && tid){
callDetail();
}
}, [detailOn]);
const onClickToNavigate = (path: string) => {
let timeout = setTimeout(() => {
clearTimeout(timeout);
navigate(PATHS.transaction.allTransaction.cancel, {
state: {
serviceCode: serviceCode,
tid: tid
}
});
}, 10)
};
const onClickToCancel = () => {
let msg = t('transaction.confirmCancel');
overlay.open(({
isOpen,
close,
unmount
}) => {
return (
<Dialog
afterLeave={ unmount }
open={ isOpen }
onClose={ close }
onConfirmClick={ () => onClickToNavigate(PATHS.transaction.allTransaction.cancel) }
// onConfirmClick={ () => callCancelInfo() }
message={ msg }
buttonLabel={[t('common.cancel'), t('common.confirm')]}
/>
);
});
};
const onClickToClose = () => {
setDetailOn(false);
};
const onClickToOpenInfo = (infoSectionKey: InfoSectionKeys) => {
if(infoSectionKey === InfoSectionKeys.Amount){
setShowAmountInfo(!showAmountInfo);
}
else if(infoSectionKey === InfoSectionKeys.Payment){
setShowPaymentInfo(!showPaymentInfo);
}
else if(infoSectionKey === InfoSectionKeys.Transaction){
setShowTransactionInfo(!showTransactionInfo);
}
else if(infoSectionKey === InfoSectionKeys.Settlement){
setShowSettlementInfo(!showSettlementInfo);
}
else if(infoSectionKey === InfoSectionKeys.PartCancel){
setShowPartCancelInfo(!showPartCancelInfo);
}
};
return (
<>
<motion.div
className="full-menu-modal"
initial="hidden"
animate={ (detailOn)? 'visible': 'hidden' }
variants={ DetailMotionVariants }
transition={ DetailMotionDuration }
style={ DetailMotionStyle }
>
<div className="full-menu-container pdw-16">
<div className="full-menu-header">
<div className="full-menu-title center">{ t('transaction.detailTitle') }</div>
<div className="full-menu-actions">
<FullMenuClose
addClass="full-menu-close"
onClickToCallback={ onClickToClose }
></FullMenuClose>
</div>
</div>
<div className="tab-pane sub active">
<div className="option-list pb-86">
<div className="txn-detail">
<AmountInfoSection
transactionCategory={ TransactionCategory.AllTransaction }
amountInfo={ amountInfo }
isOpen={ showAmountInfo }
tid={ tid }
serviceCode={ serviceCode }
onClickToOpenInfo={ (infoSectionKey) => onClickToOpenInfo(infoSectionKey) }
></AmountInfoSection>
<div className="txn-divider minus"></div>
<ImportantInfoSection
transactionCategory={ TransactionCategory.AllTransaction }
importantInfo={ importantInfo }
serviceCode={ serviceCode }
></ImportantInfoSection>
{ !!paymentInfo &&
<>
<div className="txn-divider"></div>
<PaymentInfoSection
transactionCategory={ TransactionCategory.AllTransaction }
paymentInfo={ paymentInfo }
serviceCode={ serviceCode }
isOpen={ showPaymentInfo }
onClickToOpenInfo={ (infoSectionKey) => onClickToOpenInfo(infoSectionKey) }
></PaymentInfoSection>
</>
}
{ !!transactionInfo &&
<>
<div className="txn-divider"></div>
<TransactionInfoSection
transactionCategory={ TransactionCategory.AllTransaction }
transactionInfo={ transactionInfo }
serviceCode={ serviceCode }
isOpen={ showTransactionInfo }
onClickToOpenInfo={ (infoSectionKey) => onClickToOpenInfo(infoSectionKey) }
></TransactionInfoSection>
</>
}
{ !!settlementInfo &&
<>
<div className="txn-divider"></div>
<SettlementInfoSection
transactionCategory={ TransactionCategory.AllTransaction }
settlementInfo={ settlementInfo }
serviceCode={ serviceCode }
isOpen={ showSettlementInfo }
onClickToOpenInfo={ (infoSectionKey) => onClickToOpenInfo(infoSectionKey) }
></SettlementInfoSection>
</>
}
{ !!partCancelInfo &&
<>
<div className="txn-divider"></div>
<PartCancelInfoSection
transactionCategory={ TransactionCategory.AllTransaction }
partCancelInfo={ partCancelInfo }
serviceCode={ serviceCode }
isOpen={ showPartCancelInfo }
onClickToOpenInfo={ (infoSectionKey) => onClickToOpenInfo(infoSectionKey) }
></PartCancelInfoSection>
</>
}
</div>
</div>
</div>
</div>
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={ () => onClickToCancel() }
>{t('transaction.cancelTransaction')}</button>
</div>
</motion.div>
</>
);
};

View File

@@ -0,0 +1,107 @@
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { motion } from 'framer-motion';
import { useBillingDetailMutation } from '@/entities/transaction/api/use-billing-detail-mutation';
import { BillingInfoSection } from '@/entities/transaction/ui/section/billing-info-section';
import {
TransactionCategory,
BillingDetailParams,
BillingDetailResponse,
BillingInfo,
AmountInfo
} from '@/entities/transaction/model/types';
import { NumericFormat } from 'react-number-format';
import { DetailMotionDuration, DetailMotionStyle, DetailMotionVariants } from '@/entities/common/model/constant';
import { FullMenuClose } from '@/entities/common/ui/full-menu-close';
export interface BillingDetailProps {
detailOn: boolean;
setDetailOn: (detailOn: boolean) => void;
tid: string;
};
export const BillingDetail = ({
detailOn,
setDetailOn,
tid
}: BillingDetailProps) => {
const { t, i18n } = useTranslation();
const [billingInfo, setBillingInfo] = useState<BillingInfo>();
const [amountInfo, setAmountInfo] = useState<AmountInfo>();
const { mutateAsync: billingDetail } = useBillingDetailMutation();
const callDetail = () => {
let billingDetailParams: BillingDetailParams = {
tid: tid
};
billingDetail(billingDetailParams).then((rs: BillingDetailResponse) => {
setBillingInfo(rs);
setAmountInfo({
transactionAmount: rs.transactionAmount,
buyerName: rs.buyerName
})
});
};
const onClickToClose = () => {
setDetailOn(false);
};
useEffect(() => {
if(!!detailOn && tid){
callDetail();
}
}, [detailOn]);
return (
<>
<motion.div
className="full-menu-modal"
initial="hidden"
animate={ (detailOn)? 'visible': 'hidden' }
variants={ DetailMotionVariants }
transition={ DetailMotionDuration }
style={ DetailMotionStyle }
>
<div className="full-menu-container pdw-16">
<div className="full-menu-header">
<div className="full-menu-title center">{ t('billing.detailTitle') }</div>
<div className="full-menu-actions">
<FullMenuClose
addClass="full-menu-close"
onClickToCallback={ onClickToClose }
></FullMenuClose>
</div>
</div>
<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">
{ i18n.language === 'en' && <span className="unit">{ t('home.currencySymbol') }</span> }
<NumericFormat
value={ amountInfo?.transactionAmount }
thousandSeparator
displayType="text"
></NumericFormat>
{ i18n.language !== 'en' && <span className="unit">{ t('home.currencyWon') }</span> }
</div>
</div>
<div className="txn-mid">
<span className="value">{ amountInfo?.buyerName }</span>
</div>
<div className="txn-doc"></div>
</div>
<div className="txn-divider"></div>
<BillingInfoSection
billingInfo={ billingInfo }
></BillingInfoSection>
</div>
</div>
</div>
</div>
</motion.div>
</>
);
};

View File

@@ -0,0 +1,178 @@
import { useEffect, useState } from 'react';
import { motion } from 'framer-motion';
import { useTranslation } from 'react-i18next';
import { useLocation } from 'react-router';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { useCashReceiptDetailMutation } from '@/entities/transaction/api/use-cash-receipt-detail-mutation';
import { IssueInfoSection } from '@/entities/transaction/ui/section/issue-info-section';
import { DetailInfoSection } from '@/entities/transaction/ui/section/detail-info-section';
import {
TransactionCategory,
CashReceiptDetailParams,
DetailResponse,
IssueInfo,
DetailInfo,
InfoSectionKeys,
CashReceiptPurposeType,
AmountInfo,
CashReceiptPurposeUpdateParams,
CashReceiptTransactionType
} from '@/entities/transaction/model/types';
import { CashReceitPurposeUpdateBottomSheet } from '@/entities/transaction/ui/cash-receit-purpose-update-bottom-sheet';
import { useCashReceiptPurposeUpdateMutation } from '@/entities/transaction/api/use-cash-receipt-purpose-update-mutation';
import { AmountInfoSection } from '@/entities/transaction/ui/section/amount-info-section';
import { snackBar } from '@/shared/lib';
import { DetailMotionDuration, DetailMotionStyle, DetailMotionVariants } from '@/entities/common/model/constant';
import { FullMenuClose } from '@/entities/common/ui/full-menu-close';
export interface CashReceiptDetailProps {
detailOn: boolean;
setDetailOn: (detailOn: boolean) => void;
tid: string;
};
export const CashReceiptDetail = ({
detailOn,
setDetailOn,
tid
}: CashReceiptDetailProps) => {
const { navigate, reload } = useNavigate();
const { t } = useTranslation();
const location = useLocation();
const [amountInfo, setAmountInfo] = useState<AmountInfo>();
const [issueInfo, setIssueInfo] = useState<IssueInfo>();
const [detailInfo, setDetailInfo] = useState<DetailInfo>();
const [showAmountInfo, setShowAmountInfo] = useState<boolean>(false);
const [showDetailInfo, setShowDetailInfo] = useState<boolean>(false);
const [bottomSheetOn, setBottomSheetOn] = useState<boolean>(false);
const [purposeType, setPurposeType] = useState<string>();
const [canDownloadReceipt, setCanDownloadReceipt] = useState<boolean>(false);
const { mutateAsync: cashReceiptDetail } = useCashReceiptDetailMutation();
const { mutateAsync: cashReceiptPurposeUpdate } = useCashReceiptPurposeUpdateMutation();
const callPurposeUpdate = () => {
let newPurpose = (purposeType === CashReceiptPurposeType.EXPENSE_PROOF)
? CashReceiptPurposeType.INCOME_DEDUCTION: CashReceiptPurposeType.EXPENSE_PROOF;
let params: CashReceiptPurposeUpdateParams = {
tid: tid,
newPurpose: newPurpose
};
cashReceiptPurposeUpdate(params).then((rs) => {
setPurposeType(rs.afterPurposeType);
setBottomSheetOn(false);
snackBar('용도 변경을 성공하였습니다.', function(){
reload();
}, 2000);
});
};
const callDetail = () => {
let cashReceitDetailParams: CashReceiptDetailParams = {
tid: tid
};
cashReceiptDetail(cashReceitDetailParams).then((rs: DetailResponse) => {
if(rs.amountDetail){
rs.amountDetail.customerName = rs.customerName;
}
setAmountInfo(rs.amountDetail || {});
setIssueInfo(rs.issueInfo || {});
setDetailInfo(rs.detailInfo || {});
setCanDownloadReceipt(rs.detailInfo?.canDownloadReceipt || false);
if(rs.issueInfo){
setPurposeType(rs.issueInfo.purpose);
}
});
};
useEffect(() => {
if(!!detailOn && tid){
callDetail();
}
}, [tid]);
const onClickToOpenInfo = (infoSectionKey: InfoSectionKeys) => {
if(infoSectionKey === InfoSectionKeys.Amount){
setShowAmountInfo(!showAmountInfo);
}
else if(infoSectionKey === InfoSectionKeys.Detail){
setShowDetailInfo(!showDetailInfo);
}
};
const onClickToClose = () => {
setDetailOn(false);
};
const onClickToPurposeUpdate = () => {
setBottomSheetOn(true);
};
return (
<>
<motion.div
className="full-menu-modal"
initial="hidden"
animate={ (detailOn)? 'visible': 'hidden' }
variants={ DetailMotionVariants }
transition={ DetailMotionDuration }
style={ DetailMotionStyle }
>
<div className="full-menu-container pdw-16">
<div className="full-menu-header">
<div className="full-menu-title center">{ t('cashReceipt.detailTitle') }</div>
<div className="full-menu-actions">
<FullMenuClose
addClass="full-menu-close"
onClickToCallback={ onClickToClose }
></FullMenuClose>
</div>
</div>
<div className="tab-pane sub active">
<div className={ `option-list ${(detailInfo?.canDownloadReceipt)? 'pb-86': ''}` }>
<div className="txn-detail">
<AmountInfoSection
transactionCategory={ TransactionCategory.CashReceipt }
amountInfo={ amountInfo }
isOpen={ showAmountInfo }
onClickToOpenInfo={ (infoSectionKey) => onClickToOpenInfo(infoSectionKey) }
purposeType={ purposeType }
canDownloadReceipt={ canDownloadReceipt }
></AmountInfoSection>
<div className="txn-divider"></div>
<IssueInfoSection
transactionCategory={ TransactionCategory.CashReceipt }
issueInfo={ issueInfo }
purposeType={ purposeType }
></IssueInfoSection>
<div className="txn-divider minus"></div>
{ !!detailInfo &&
<DetailInfoSection
transactionCategory={ TransactionCategory.CashReceipt }
detailInfo={ detailInfo }
isOpen={ showDetailInfo }
onClickToOpenInfo={ (infoSectionKey) => onClickToOpenInfo(infoSectionKey) }
></DetailInfoSection>
}
</div>
</div>
{ (issueInfo?.transactionType === CashReceiptTransactionType.APPROVAL) &&
(issueInfo?.processResult === '발급완료') &&
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={ () => onClickToPurposeUpdate() }
>{ t('cashReceipt.changePurpose') }</button>
</div>
}
</div>
</div>
</motion.div>
<CashReceitPurposeUpdateBottomSheet
setBottomSheetOn={ setBottomSheetOn }
bottomSheetOn={ bottomSheetOn }
callPurposeUpdate={ callPurposeUpdate }
></CashReceitPurposeUpdateBottomSheet>
</>
);
};

View File

@@ -0,0 +1,225 @@
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { motion } from 'framer-motion';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { useEscrowDetailMutation } from '@/entities/transaction/api/use-escrow-detail-mutation';
import { ImportantInfoSection } from '@/entities/transaction/ui/section/important-info-section';
import { EscrowInfoSection } from '@/entities/transaction/ui/section/escrow-info-section';
import { PaymentInfoSection } from '@/entities/transaction/ui/section/payment-info-section';
import { TransactionInfoSection } from '@/entities/transaction/ui/section/transaction-info-section';
import { SettlementInfoSection } from '@/entities/transaction/ui/section/settlement-info-section';
import {
TransactionCategory,
EscrowDetailParams,
DetailResponse,
ImportantInfo,
EscrowInfo,
PaymentInfo,
TransactionInfo,
SettlementInfo,
InfoSectionKeys,
MerchantInfo,
AmountInfo
} from '@/entities/transaction/model/types';
import { useEscrowMailResendMutation } from '@/entities/transaction/api/use-escrow-mail-resend-mutation';
import { MerchantInfoSection } from '@/entities/transaction/ui/section/merchant-info-section';
import { AmountInfoSection } from '@/entities/transaction/ui/section/amount-info-section';
import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet';
import { DetailMotionDuration, DetailMotionStyle, DetailMotionVariants } from '@/entities/common/model/constant';
import { FullMenuClose } from '@/entities/common/ui/full-menu-close';
export interface EscrowDetailProps {
detailOn: boolean;
setDetailOn: (detailOn: boolean) => void;
tid: string;
serviceCode: string;
};
export const EscrowDetail = ({
detailOn,
setDetailOn,
tid,
serviceCode
}: EscrowDetailProps) => {
const { navigate } = useNavigate();
const { t } = useTranslation();
const [amountInfo, setAmountInfo] = useState<AmountInfo>();
const [importantInfo, setImportantInfo] = useState<ImportantInfo>();
const [escrowInfo, setEscrowInfo] = useState<EscrowInfo>();
const [paymentInfo, setPaymentInfo] = useState<PaymentInfo>();
const [transactionInfo, setTransactionInfo] = useState<TransactionInfo>();
const [settlementInfo, setSettlementInfo] = useState<SettlementInfo>();
const [merchantInfo, setMerchantInfo] = useState<MerchantInfo>();
const [showAmountInfo, setShowAmountInfo] = useState<boolean>(false);
const [showImportantInfo, setShowImportantInfo] = useState<boolean>(false);
const [showEscroInfo, setShowEscroInfo] = useState<boolean>(false);
const [showPaymentInfo, setShowPaymentInfo] = useState<boolean>(false);
const [showTransactionInfo, setShowTransactionInfo] = useState<boolean>(false);
const [showSettlementInfo, setShowSettlementInfo] = useState<boolean>(false);
const [showMerchantInfo, setShowMerchantInfo] = useState<boolean>(false);
const [bottomSheetOn, setBottomSheetOn] = useState<boolean>(false);
const [orderNumber, setOrderNumber] = useState<string>();
const { mutateAsync: escrowDetail } = useEscrowDetailMutation();
const { mutateAsync: escrowMailResend } = useEscrowMailResendMutation()
const callDetail = () => {
let escroDetailParams: EscrowDetailParams = {
tid: tid,
};
escrowDetail(escroDetailParams).then((rs: DetailResponse) => {
setAmountInfo(rs.paymentInfo || {});
setImportantInfo(rs.importantInfo || {});
setEscrowInfo(rs.escrowInfo || {});
setPaymentInfo(rs.paymentInfo || {});
setTransactionInfo(rs.transactionInfo || {});
setSettlementInfo(rs.settlementInfo || {});
setMerchantInfo(rs.merchantInfo || {});
setOrderNumber(rs.importantInfo?.orderNumber);
});
};
useEffect(() => {
if(!!detailOn && serviceCode && tid){
callDetail();
}
}, [detailOn]);
const onClickToShowMailResend = () => {
setBottomSheetOn(true);
};
const callMailResend = () => {
let params = {
orderNumber: orderNumber,
tid: tid,
};
escrowMailResend(params).then((rs: any) => {
console.log(rs);
});
};
const onClickToClose = () => {
setDetailOn(false);
};
const onClickToOpenInfo = (infoSectionKey: InfoSectionKeys) => {
if(infoSectionKey === InfoSectionKeys.Amount){
setShowAmountInfo(!showAmountInfo);
}
else if(infoSectionKey === InfoSectionKeys.Important){
setShowImportantInfo(!showImportantInfo);
}
else if(infoSectionKey === InfoSectionKeys.Escrow){
setShowEscroInfo(!showEscroInfo);
}
else if(infoSectionKey === InfoSectionKeys.Payment){
setShowPaymentInfo(!showPaymentInfo);
}
else if(infoSectionKey === InfoSectionKeys.Transaction){
setShowTransactionInfo(!showTransactionInfo);
}
else if(infoSectionKey === InfoSectionKeys.Settlement){
setShowSettlementInfo(!showSettlementInfo);
}
else if(infoSectionKey === InfoSectionKeys.Merchant){
setShowMerchantInfo(!showMerchantInfo);
}
};
return (
<>
<motion.div
className="full-menu-modal"
initial="hidden"
animate={ (detailOn)? 'visible': 'hidden' }
variants={ DetailMotionVariants }
transition={ DetailMotionDuration }
style={ DetailMotionStyle }
>
<div className="full-menu-container pdw-16">
<div className="full-menu-header">
<div className="full-menu-title center">{ t('escrow.detailTitle') }</div>
<div className="full-menu-actions">
<FullMenuClose
addClass="full-menu-close"
onClickToCallback={ onClickToClose }
></FullMenuClose>
</div>
</div>
<div className="tab-pane sub active">
<div className="option-list">
<div className="txn-detail">
<AmountInfoSection
transactionCategory={ TransactionCategory.Escrow }
amountInfo={ amountInfo }
isOpen={ showAmountInfo }
tid={ tid }
serviceCode={ serviceCode }
onClickToOpenInfo={ (infoSectionKey) => onClickToOpenInfo(infoSectionKey) }
></AmountInfoSection>
<div className="txn-divider minus"></div>
<ImportantInfoSection
transactionCategory={ TransactionCategory.Escrow }
importantInfo={ importantInfo }
></ImportantInfoSection>
<div className="txn-divider minus"></div>
<EscrowInfoSection
escrowInfo={ escrowInfo }
isOpen={ showEscroInfo }
onClickToOpenInfo={ (infoSectionKey) => onClickToOpenInfo(infoSectionKey) }
></EscrowInfoSection>
<div className="txn-divider minus"></div>
<PaymentInfoSection
transactionCategory={ TransactionCategory.Escrow }
paymentInfo={ paymentInfo }
isOpen={ showPaymentInfo }
serviceCode={ serviceCode }
onClickToOpenInfo={ (infoSectionKey) => onClickToOpenInfo(infoSectionKey) }
></PaymentInfoSection>
<div className="txn-divider"></div>
<TransactionInfoSection
transactionCategory={ TransactionCategory.Escrow }
transactionInfo={ transactionInfo }
isOpen={ showTransactionInfo }
onClickToOpenInfo={ (infoSectionKey) => onClickToOpenInfo(infoSectionKey) }
></TransactionInfoSection>
<div className="txn-divider"></div>
<SettlementInfoSection
transactionCategory={ TransactionCategory.Escrow }
settlementInfo={ settlementInfo }
isOpen={ showSettlementInfo }
onClickToOpenInfo={ (infoSectionKey) => onClickToOpenInfo(infoSectionKey) }
></SettlementInfoSection>
<div className="txn-divider"></div>
<MerchantInfoSection
merchantInfo={ merchantInfo }
isOpen={ showMerchantInfo }
onClickToOpenInfo={ (infoSectionKey) => onClickToOpenInfo(infoSectionKey) }
></MerchantInfoSection>
</div>
</div>
</div>
</div>
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={ () => onClickToShowMailResend() }
> </button>
</div>
</motion.div>
<EmailBottomSheet
setBottomSheetOn={ setBottomSheetOn }
bottomSheetOn={ bottomSheetOn }
imageSave={ false }
sendEmail={ true }
sendRequest={ callMailResend }
></EmailBottomSheet>
</>
);
};

View File

@@ -3,7 +3,8 @@ import { ListDateGroup } from './list-date-group';
export const EscrowList = ({
transactionCategory,
listItems
listItems,
setDetailData
}: EscrowListProps) => {
const getListDateGroup = () => {
@@ -26,6 +27,7 @@ export const EscrowList = ({
key={ date + '-' + i }
date={ date }
items={ list }
setDetailData={ setDetailData }
></ListDateGroup>
);
}
@@ -43,6 +45,7 @@ export const EscrowList = ({
key={ date + '-last' }
date={ date }
items={ list }
setDetailData={ setDetailData }
></ListDateGroup>
);
}

View File

@@ -9,7 +9,8 @@ import { useTranslation } from 'react-i18next';
export const ListDateGroup = ({
transactionCategory,
date,
items
items,
setDetailData
}: ListDateGroupProps) => {
const { t, i18n } = useTranslation();
@@ -93,6 +94,8 @@ export const ListDateGroup = ({
billKey={ items[i]?.billKey }
orderNumber={ items[i]?.orderNumber }
setDetailData={ setDetailData }
></ListItem>
)
}

View File

@@ -1,9 +1,6 @@
import { NumericFormat } from 'react-number-format';
import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { BillingRequestStatus, CashReceiptTransactionType, EscrowDeliveryStatus, ListItemProps, TransactionCategory } from '../model/types';
import moment from 'moment';
import { useStore } from '@/shared/model/store';
import { getAllTransactionStatusCode, getPaymentMethodName } from '../model/contant';
import { useTranslation } from 'react-i18next';
@@ -16,9 +13,9 @@ export const ListItem = ({
paymentMethod, processResult, transactionType,
transactionDateTime, transactionAmount,
deliveryStatus, settlementStatus,
cancelStatus, billKey, orderNumber, requestStatus
cancelStatus, billKey, orderNumber, requestStatus,
setDetailData
}: ListItemProps) => {
const { navigate } = useNavigate();
const { t } = useTranslation();
const getItemClass = () => {
let rs = '';
@@ -88,34 +85,38 @@ export const ListItem = ({
const onClickToNavigate = () => {
if(transactionCategory === TransactionCategory.AllTransaction){
navigate(PATHS.transaction.allTransaction.detail, {
state: {
if(setDetailData && tid){
setDetailData({
tid: tid,
serviceCode: serviceCode
}
});
serviceCode: serviceCode,
detailOn: true
});
}
}
else if(transactionCategory === TransactionCategory.CashReceipt){
navigate(PATHS.transaction.cashReceipt.detail, {
state: {
tid: tid
}
});
if(setDetailData && tid){
setDetailData({
tid: tid,
detailOn: true
});
}
}
else if(transactionCategory === TransactionCategory.Escrow){
navigate(PATHS.transaction.escrow.detail, {
state: {
tid: tid,
serviceCode: serviceCode
}
});
if(setDetailData && tid){
setDetailData({
tid: tid,
serviceCode: serviceCode,
detailOn: true
});
}
}
else if(transactionCategory === TransactionCategory.Billing){
navigate(PATHS.transaction.billing.detail, {
state: {
if(setDetailData && tid){
setDetailData({
tid: tid,
}
});
detailOn: true
});
}
}
else{
alert(t('common.error'));

View File

@@ -51,7 +51,8 @@ export interface VatReturnListResponse extends DefaulResponsePagination {
};
export interface VatReturnListContent {
id?: number
id?: number;
taxInvoiceNumber?: string;
companyName?: string;
mid?: string;
issueDate?: string;
@@ -61,15 +62,22 @@ export interface VatReturnListContent {
export interface ListDateGroupProps {
date?: string;
items?: Array<VatReturnListContent>
}
items?: Array<VatReturnListContent>;
setDetailData?: (detailData: DetailData) => void;
};
export interface DetailData {
taxInvoiceNumber: string;
detailOn: boolean;
};
export interface ListItemProps {
id?: number;
taxInvoiceNumber?: string;
companyName?: string;
mid?: string;
issueDate?: string;
paymentMethod?: string;
amount?: number;
setDetailData?: (detailData: DetailData) => void;
}
export interface VatReturnDetailParams {
taxInvoiceNumber?: string;

View File

@@ -0,0 +1,162 @@
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { motion } from 'framer-motion';
import { PATHS } from '@/shared/constants/paths';
import { useLocation } from 'react-router';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { useVatReturnDetailMutation } from '@/entities/vat-return/api/use-vat-return-detail-mutation';
import { HeaderType } from '@/entities/common/model/types';
import {
Breakdown,
VatReturnBreakdownParams,
VatReturnBreakdownResponse,
VatReturnDetailParams,
VatReturnDetailResponse
} from '@/entities/vat-return/model/types';
import {
useSetOnBack,
useSetHeaderTitle,
useSetHeaderType,
useSetFooterMode
} from '@/widgets/sub-layout/use-sub-layout';
import { SupplierSection } from '@/entities/vat-return/ui/section/supplier-section';
import { ReceiverSection } from '@/entities/vat-return/ui/section/receiver-section';
import { IssueSection } from '@/entities/vat-return/ui/section/issue-section';
import { AmountSection } from '@/entities/vat-return/ui/section/amount-section';
import { useVatReturnTaxInvoiceMutation } from '@/entities/vat-return/api/use-vat-return-tax-invoice-mutation';
import { VatReturnListDetailBottomSheet } from '@/entities/vat-return/ui/list-detail-bottom-sheet';
import { useVatReturnBreakdownMutation } from '@/entities/vat-return/api/use-vat-return-breakdown-mutation';
import { DetailMotionDuration, DetailMotionStyle, DetailMotionVariants } from '@/entities/common/model/constant';
import { FullMenuClose } from '@/entities/common/ui/full-menu-close';
export interface TaxInvoiceDetailProps {
detailOn: boolean;
setDetailOn: (detailOn: boolean) => void;
taxInvoiceNumber: string;
};
export const TaxInvoiceDetail = ({
detailOn,
setDetailOn,
taxInvoiceNumber
}: TaxInvoiceDetailProps) => {
const { t } = useTranslation();
const { navigate } = useNavigate();
const location = useLocation();
// taxInvoiceNumber = 'TAX202506300001';
const [openAmount, setOpenAmount] = useState<boolean>(false);
const [bottomSheetOn, setBottomSheetOn] = useState<boolean>(false);
const [detail, setDetail] = useState<VatReturnDetailResponse>({});
const [breakdown, setBreakdown] = useState<Array<Breakdown>>([]);
useSetHeaderTitle(t('vatReturn.taxInvoiceDetail'));
useSetHeaderType(HeaderType.RightClose);
useSetOnBack(() => {
navigate(PATHS.vatReturn.list);
});
useSetFooterMode(false);
const { mutateAsync: vatReturnTaxInvoice } = useVatReturnTaxInvoiceMutation();
const { mutateAsync: vatReturnDetail } = useVatReturnDetailMutation();
const { mutateAsync: vatReturnBreakdown } = useVatReturnBreakdownMutation();
const callTaxInvoice = () => {
if(taxInvoiceNumber){
let params: VatReturnDetailParams = {
taxInvoiceNumber: taxInvoiceNumber,
};
vatReturnDetail(params).then((rs: VatReturnDetailResponse) => {
setDetail(rs);
});
}
};
const callVatReturnBreakdown = async() => {
let params: VatReturnBreakdownParams = {
taxInvoiceNumber: taxInvoiceNumber,
};
vatReturnBreakdown(params).then((rs: VatReturnBreakdownResponse) => {
setBreakdown(rs.breakdown);
});
};
const onClickToOpenBottomSheet = () => {
setBottomSheetOn(true);
};
const onClickToClose = () => {
setDetailOn(false);
};
useEffect(() => {
if(!!detailOn && taxInvoiceNumber){
callTaxInvoice();
callVatReturnBreakdown();
}
}, [detailOn]);
return (
<>
<motion.div
className="full-menu-modal"
initial="hidden"
animate={ (detailOn)? 'visible': 'hidden' }
variants={ DetailMotionVariants }
transition={ DetailMotionDuration }
style={ DetailMotionStyle }
>
<div className="full-menu-container pdw-16">
<div className="full-menu-header">
<div className="full-menu-title center">{ t('transaction.detailTitle') }</div>
<div className="full-menu-actions">
<FullMenuClose
addClass="full-menu-close"
onClickToCallback={ onClickToClose }
></FullMenuClose>
</div>
</div>
<div className="tab-pane sub active">
<div className="option-list">
<div className="txn-detail">
<AmountSection
detail={ detail }
></AmountSection>
<div className="txn-divider minus"></div>
<IssueSection
detail={ detail }
></IssueSection>
<div className="txn-divider minus"></div>
<ReceiverSection
detail={ detail }
></ReceiverSection>
<div className="txn-divider"></div>
<SupplierSection
detail={ detail }
></SupplierSection>
</div>
</div>
</div>
</div>
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={ onClickToOpenBottomSheet }
>{t('vatReturn.viewDetails')}</button>
</div>
</motion.div>
{ !!bottomSheetOn &&
<VatReturnListDetailBottomSheet
bottomSheetOn={ bottomSheetOn }
setBottomSheetOn={ setBottomSheetOn }
breakdown={ breakdown }
transactionAmount={ detail?.transactionAmount }
supplyAmount={ detail?.supplyAmount }
vatAmount={ detail?.vatAmount }
totalAmount={ detail?.totalAmount }
></VatReturnListDetailBottomSheet>
}
</>
)
};

View File

@@ -5,7 +5,8 @@ import { ListItem } from './list-item';
export const ListDateGroup = ({
date,
items
items,
setDetailData
}: ListDateGroupProps) => {
moment.locale('ko');
const getStateDate = () => {
@@ -21,12 +22,13 @@ export const ListDateGroup = ({
rs.push(
<ListItem
key={ key }
id={ items[i]?.id || 0 }
taxInvoiceNumber={ items[i]?.taxInvoiceNumber || '' }
companyName={ items[i]?.companyName || '' }
mid={ items[i]?.mid || '' }
issueDate={ items[i]?.issueDate || '' }
paymentMethod={ items[i]?.paymentMethod || '' }
amount={ items[i]?.amount || 0 }
setDetailData={ setDetailData }
></ListItem>
)
}

View File

@@ -1,27 +1,25 @@
import { NumericFormat } from 'react-number-format';
import { useTranslation } from 'react-i18next';
import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { ListItemProps } from '../model/types';
import moment from 'moment';
export const ListItem = ({
id,
taxInvoiceNumber,
companyName,
mid,
issueDate,
paymentMethod,
amount
amount,
setDetailData
}: ListItemProps) => {
const { t, i18n } = useTranslation();
const { navigate } = useNavigate();
const onClickToNavigate = () => {
navigate(PATHS.vatReturn.detail, {
state: {
taxInvoiceNumber: id
}
});
if(setDetailData && taxInvoiceNumber){
setDetailData({
taxInvoiceNumber: taxInvoiceNumber,
detailOn: true
});
}
};
return (

View File

@@ -7,6 +7,7 @@ import { SortTypeBox } from '@/entities/common/ui/sort-type-box';
import { DefaultRequestPagination, SortTypeKeys } from '@/entities/common/model/types';
import { DEFAULT_PAGE_PARAM } from '@/entities/common/model/constant';
import {
DetailData,
VatReturnListContent,
VatReturnListParams,
VatReturnListResponse,
@@ -18,6 +19,7 @@ import { ListDateGroup } from './list-date-group';
import { useStore } from '@/shared/model/store';
import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet';
import useIntersectionObserver from '@/widgets/intersection-observer';
import { TaxInvoiceDetail } from './detail/tax-invoice-detail';
export const ListWrap = () => {
const { t } = useTranslation();
@@ -36,7 +38,10 @@ export const ListWrap = () => {
const [emailBottomSheetOn, setEmailBottomSheetOn] = useState<boolean>(false);
const [detailOn, setDetailOn] = useState<boolean>(false);
const [detailTaxInvoiceNumber, setDetailTaxInvoiceNumber] = useState<string>('');
const { mutateAsync: vatReturnList } = useVatReturnListMutation();
const onIntersect: IntersectionObserverCallback = (entries: Array<IntersectionObserverEntry>) => {
entries.forEach((entry: IntersectionObserverEntry) => {
if(entry.isIntersecting){
@@ -122,6 +127,11 @@ export const ListWrap = () => {
mid, startMonth, endMonth,
receiptType, targetType, sortType
]);
const setDetailData = (detailData: DetailData) => {
setDetailOn(detailData.detailOn);
setDetailTaxInvoiceNumber(detailData.taxInvoiceNumber);
};
const getListDateGroup = () => {
let rs = [];
@@ -144,6 +154,7 @@ export const ListWrap = () => {
key={ date + '-' + i }
date={ date }
items={ list }
setDetailData={ setDetailData }
></ListDateGroup>
);
}
@@ -160,6 +171,7 @@ export const ListWrap = () => {
key={ date + '-last' }
date={ date }
items={ list }
setDetailData={ setDetailData }
></ListDateGroup>
);
}
@@ -220,6 +232,12 @@ export const ListWrap = () => {
setReceiptType={ setReceiptType }
setTargetType={ setTargetType }
></ListFilter>
<TaxInvoiceDetail
detailOn={ detailOn }
setDetailOn={ setDetailOn }
taxInvoiceNumber={ detailTaxInvoiceNumber }
>
</TaxInvoiceDetail>
{ !!emailBottomSheetOn &&
<EmailBottomSheet
bottomSheetOn={ emailBottomSheetOn }

View File

@@ -5,7 +5,7 @@ import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { DefaultRequestPagination, HeaderType } from '@/entities/common/model/types';
import { useFaqListMutation } from '@/entities/support/api/use-faq-list-mutation';
import { DEFAULT_PAGE_PARAM } from '@/entities/common/model/constant';
import { FaqItem, FaqListParams, FaqListResponse, SearchCl } from '@/entities/support/model/types';
import { DetailData, FaqItem, FaqListParams, FaqListResponse, SearchCl } from '@/entities/support/model/types';
import { SupportFaqItem } from '@/entities/support/ui/faq-item';
import {
useSetHeaderTitle,
@@ -14,6 +14,7 @@ import {
useSetOnBack
} from '@/widgets/sub-layout/use-sub-layout';
import useIntersectionObserver from '@/widgets/intersection-observer';
import { FaqDetail } from '@/entities/support/ui/detail/faq-detail';
export const FaqListPage = () => {
const { navigate } = useNavigate();
@@ -24,6 +25,8 @@ export const FaqListPage = () => {
const [searchValue, setSearchValue] = useState<string>('');
const [selectedCategory, setSelectedCategory] = useState<string>('');
const [resultList, setResultList] = useState<Array<FaqItem>>([]);
const [detailOn, setDetailOn] = useState<boolean>(false);
const [detailFaqItem, setDetailFaqItem] = useState<FaqItem>({});
useSetHeaderTitle(t('support.faq.title'));
useSetHeaderType(HeaderType.LeftArrow);
@@ -103,19 +106,26 @@ export const FaqListPage = () => {
callList();
};
const setDetailData = (detailData: DetailData) => {
setDetailOn(detailData.detailOn);
if(detailData?.faqItem){
setDetailFaqItem(detailData?.faqItem);
}
};
const getFaqList = () => {
let rs = [];
for(let i=0;i<resultList.length;i++){
rs.push(
<SupportFaqItem
key={ `key-support-faq-item-${i}` }
cursorId={ resultList[i]?.cursorId }
seq={ resultList[i]?.seq }
category={ resultList[i]?.category }
title={ resultList[i]?.title }
contents={ resultList[i]?.contents }
></SupportFaqItem>
)
let faqItem = resultList[i];
if(faqItem){
rs.push(
<SupportFaqItem
key={ `key-support-faq-item-${i}` }
faqItem={ faqItem }
setDetailData={ setDetailData }
></SupportFaqItem>
);
}
}
return rs;
};
@@ -175,15 +185,20 @@ export const FaqListPage = () => {
</div>
<div ref={ setTarget }></div>
</div>
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={ () => onClickToNavigation() }
>{t('support.faq.inquiryButton')}</button>
</div>
</div>
</div>
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={ () => onClickToNavigation() }
>{t('support.faq.inquiryButton')}</button>
</div>
</main>
<FaqDetail
detailOn={ detailOn }
setDetailOn={ setDetailOn }
faqItem={ detailFaqItem }
></FaqDetail>
</>
);
};

View File

@@ -4,7 +4,7 @@ import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { useNoticeListMutation } from '@/entities/support/api/use-notice-list-mutation';
import { DEFAULT_PAGE_PARAM } from '@/entities/common/model/constant';
import { InformCl, NoticeItem, NoticeListParams, NoticeListResponse, SearchCl } from '@/entities/support/model/types';
import { DetailData, InformCl, NoticeItem, NoticeListParams, NoticeListResponse, SearchCl } from '@/entities/support/model/types';
import { SupportNoticeItem } from '@/entities/support/ui/notice-item';
import { DefaultRequestPagination, HeaderType } from '@/entities/common/model/types';
import {
@@ -14,6 +14,7 @@ import {
useSetOnBack
} from '@/widgets/sub-layout/use-sub-layout';
import useIntersectionObserver from '@/widgets/intersection-observer';
import { NoticeDetail } from '@/entities/support/ui/detail/notice-detail';
export const NoticeListPage = () => {
const { navigate } = useNavigate();
@@ -24,6 +25,8 @@ export const NoticeListPage = () => {
const [informCl, setInformCl] = useState<InformCl | string>('');
const [searchKeyword, setSearchKeyword] = useState<string>('');
const [resultList, setResultList] = useState<Array<NoticeItem>>([]);
const [detailOn, setDetailOn] = useState<boolean>(false);
const [detailSeq, setDetailSeq] = useState<number>(0);
useSetHeaderTitle(t('support.notice.title'));
useSetHeaderType(HeaderType.LeftArrow);
@@ -102,19 +105,27 @@ export const NoticeListPage = () => {
}
callList();
};
const setDetailData = (detailData: DetailData) => {
setDetailOn(detailData.detailOn);
if(detailData?.seq){
setDetailSeq(detailData?.seq);
}
};
const getNoticeList = () => {
let rs = [];
for(let i=0;i<resultList.length;i++){
rs.push(
<SupportNoticeItem
key={ `key-support-notice-item-${i}` }
seq={ resultList[i]?.seq }
title={ resultList[i]?.title }
informCl={ resultList[i]?.informCl }
regDt={ resultList[i]?.regDt }
></SupportNoticeItem>
)
let noticeItem = resultList[i];
if(noticeItem){
rs.push(
<SupportNoticeItem
key={ `key-support-notice-item-${i}` }
noticeItem={ noticeItem }
setDetailData={ setDetailData }
></SupportNoticeItem>
);
}
}
return rs;
};
@@ -173,6 +184,11 @@ export const NoticeListPage = () => {
</div>
</div>
</div>
<NoticeDetail
detailOn={ detailOn }
setDetailOn={ setDetailOn }
seq={ detailSeq }
></NoticeDetail>
</main>
</>
);

View File

@@ -6,7 +6,7 @@ import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { DefaultRequestPagination, HeaderType } from '@/entities/common/model/types';
import { useQnaListMutation } from '@/entities/support/api/use-qna-list-mutation';
import { DEFAULT_PAGE_PARAM } from '@/entities/common/model/constant';
import { QnaItem, QnaListParams, QnaListResponse } from '@/entities/support/model/types';
import { DetailData, QnaItem, QnaListParams, QnaListResponse } from '@/entities/support/model/types';
import { SupportQnaItem } from '@/entities/support/ui/qna-item';
import useIntersectionObserver from '@/widgets/intersection-observer';
import {
@@ -15,6 +15,7 @@ import {
useSetFooterMode,
useSetOnBack
} from '@/widgets/sub-layout/use-sub-layout';
import { QnaDetail } from '@/entities/support/ui/detail/qna-detail';
export const QnaListPage = () => {
const { navigate } = useNavigate();
@@ -31,6 +32,8 @@ export const QnaListPage = () => {
const [pageParam, setPageParam] = useState<DefaultRequestPagination>(DEFAULT_PAGE_PARAM);
const [statusCode, setStatusCode] = useState<string>(''); // 02, 03
const [resultList, setResultList] = useState<Array<QnaItem>>([]);
const [detailOn, setDetailOn] = useState<boolean>(false);
const [detailQnaItem, setDetailQnaItem] = useState<QnaItem>({});
useSetHeaderTitle(t('support.qna.title'));
useSetHeaderType(HeaderType.LeftArrow);
@@ -102,27 +105,27 @@ export const QnaListPage = () => {
);
});
};
const setDetailData = (detailData: DetailData) => {
setDetailOn(detailData.detailOn);
if(detailData?.qnaItem){
setDetailQnaItem(detailData?.qnaItem);
}
};
const getQnaList = () => {
let rs = [];
for(let i=0;i<resultList.length;i++){
rs.push(
<SupportQnaItem
key={ `key-support-faq-item-${i}` }
answer={ resultList[i]?.answer }
answerDate={ resultList[i]?.answerDate }
contents={ resultList[i]?.contents }
corpName={ resultList[i]?.corpName }
cursorId={ resultList[i]?.cursorId }
requestDate={ resultList[i]?.requestDate }
requestName={ resultList[i]?.requestName }
requestType={ resultList[i]?.requestType }
sendEmail={ resultList[i]?.sendEmail }
seq={ resultList[i]?.seq }
statusCode={ resultList[i]?.statusCode }
title={ resultList[i]?.title }
></SupportQnaItem>
);
let qnaItem = resultList[i];
if(qnaItem){
rs.push(
<SupportQnaItem
key={ `key-support-faq-item-${i}` }
qnaItem={ qnaItem }
setDetailData={ setDetailData }
></SupportQnaItem>
);
}
}
return rs;
};
@@ -176,16 +179,20 @@ export const QnaListPage = () => {
</div>
<div ref={ setTarget }></div>
</div>
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={ () => onClickToNavigation() }
>{t('support.qna.inquiryButton')}</button>
</div>
</div>
</div>
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={ () => onClickToNavigation() }
>{t('support.qna.inquiryButton')}</button>
</div>
</main>
<QnaDetail
detailOn={ detailOn }
setDetailOn={ setDetailOn }
qnaItem={ detailQnaItem }
></QnaDetail>
</>
);
};

View File

@@ -13,7 +13,8 @@ import {
ListItemProps,
AllTransactionListSummaryParams,
AllTransactionListResponse,
AllTransactionListSummaryResponse
AllTransactionListSummaryResponse,
DetailData
} from '@/entities/transaction/model/types';
import { useAllTransactionListMutation } from '@/entities/transaction/api/use-all-transaction-list-mutation';
import { useAllTransactionListSummaryMutation } from '@/entities/transaction/api/use-all-transaction-list-summary-mutation';
@@ -31,6 +32,7 @@ import {
import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet';
import useIntersectionObserver from '@/widgets/intersection-observer';
import { useTranslation } from 'react-i18next';
import { AllTransactionDetail } from '@/entities/transaction/ui/detail/all-transaction-detail';
export const AllTransactionListPage = () => {
const { navigate } = useNavigate();
@@ -65,6 +67,10 @@ export const AllTransactionListPage = () => {
const [totalAmount, setTotalAmount] = useState<number>(0);
const [emailBottomSheetOn, setEmailBottomSheetOn] = useState<boolean>(false);
const [detailOn, setDetailOn] = useState<boolean>(false);
const [detailTid, setDetailTid] = useState<string>('');
const [detailServiceCode, setDetailServiceCode] = useState<string>('');
useSetHeaderTitle(t('transaction.listTitle'));
useSetHeaderType(HeaderType.LeftArrow);
@@ -209,6 +215,14 @@ export const AllTransactionListPage = () => {
return rs;
};
const setDetailData = (detailData: DetailData) => {
setDetailOn(detailData.detailOn);
setDetailTid(detailData.tid);
if(detailData?.serviceCode){
setDetailServiceCode(detailData?.serviceCode);
}
};
const getLocalizedServiceCodeName = (name?: string): string => {
if (!name) return '';
@@ -307,6 +321,7 @@ export const AllTransactionListPage = () => {
<AllTransactionList
listItems={ listItems }
transactionCategory={ TransactionCategory.AllTransaction }
setDetailData={ setDetailData }
></AllTransactionList>
<div ref={ setTarget }></div>
</div>
@@ -341,7 +356,12 @@ export const AllTransactionListPage = () => {
setSearchValue={ setSearchValue }
serviceCodeOptions={ serviceCodeOptions }
></AllTransactionFilter>
<AllTransactionDetail
detailOn={ detailOn }
setDetailOn={ setDetailOn }
tid={ detailTid }
serviceCode={ detailServiceCode }
></AllTransactionDetail>
{ !!emailBottomSheetOn &&
<EmailBottomSheet
bottomSheetOn={ emailBottomSheetOn }

View File

@@ -14,7 +14,8 @@ import {
BillingSearchType,
ListItemProps,
BillingListParams,
BillingListResponse
BillingListResponse,
DetailData
} from '@/entities/transaction/model/types';
import { useBillingListMutation } from '@/entities/transaction/api/use-billing-list-mutation';
import { useDownloadExcelMutation } from '@/entities/transaction/api/use-download-excel-mutation';
@@ -31,6 +32,7 @@ import {
} from '@/widgets/sub-layout/use-sub-layout';
import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet';
import useIntersectionObserver from '@/widgets/intersection-observer';
import { BillingDetail } from '@/entities/transaction/ui/detail/billing-detail';
export const BillingListPage = () => {
const { navigate } = useNavigate();
@@ -55,6 +57,8 @@ export const BillingListPage = () => {
const [maxAmount, setMaxAmount] = useState<number>();
const [downloadBottomSheetOn, setDownloadBottomSheetOn] = useState<boolean>(false);
const [detailOn, setDetailOn] = useState<boolean>(false);
const [detailTid, setDetailTid] = useState<string>('');
useSetHeaderTitle(t('billing.title'));
useSetHeaderType(HeaderType.LeftArrow);
@@ -149,10 +153,17 @@ export const BillingListPage = () => {
const onClickToRequestStatus = (val: BillingRequestStatus) => {
setRequestStatus(val);
};
const onClickToNavigate = () => {
navigate(PATHS.transaction.billing.charge);
};
const onRequestDownload = (userEmail?: string) => {
};
const setDetailData = (detailData: DetailData) => {
setDetailOn(detailData.detailOn);
setDetailTid(detailData.tid);
};
useEffect(() => {
callList();
@@ -217,11 +228,18 @@ export const BillingListPage = () => {
<BillingList
listItems={ listItems }
transactionCategory={ TransactionCategory.Billing }
setDetailData={ setDetailData }
></BillingList>
<div ref={ setTarget }></div>
</div>
</div>
</main>
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={ () => onClickToNavigate() }
>{ t('transaction.list.paymentRequest') }</button>
</div>
<BillingFilter
filterOn={ filterOn }
setFilterOn={ setFilterOn }
@@ -246,6 +264,11 @@ export const BillingListPage = () => {
setMinAmount={ setMinAmount }
setMaxAmount={ setMaxAmount }
></BillingFilter>
<BillingDetail
detailOn={ detailOn }
setDetailOn={ setDetailOn }
tid={ detailTid }
></BillingDetail>
{ !!downloadBottomSheetOn &&
<EmailBottomSheet
bottomSheetOn={ downloadBottomSheetOn }

View File

@@ -16,7 +16,8 @@ import {
CashReceiptSearchNumberType,
CashReceiptSummaryParams,
CashReceiptListResponse,
CashReceiptSummaryResponse
CashReceiptSummaryResponse,
DetailData
} from '@/entities/transaction/model/types';
import { useCashReceiptListMutation } from '@/entities/transaction/api/use-cash-receipt-list-mutation';
import { useDownloadExcelMutation } from '@/entities/transaction/api/use-download-excel-mutation';
@@ -35,6 +36,7 @@ import { useStore } from '@/shared/model/store';
import { useCashReceiptSummaryMutation } from '@/entities/transaction/api/use-cash-receipt-summary-mutation';
import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet';
import useIntersectionObserver from '@/widgets/intersection-observer';
import { CashReceiptDetail } from '@/entities/transaction/ui/detail/cash-receit-detail';
export const CashReceiptListPage = () => {
const { navigate } = useNavigate();
@@ -62,12 +64,16 @@ export const CashReceiptListPage = () => {
const [emailBottomSheetOn, setEmailBottomSheetOn] = useState<boolean>(false);
const [detailOn, setDetailOn] = useState<boolean>(false);
const [detailTid, setDetailTid] = useState<string>('');
const [detailServiceCode, setDetailServiceCode] = useState<string>('');
useSetHeaderTitle(t('cashReceipt.title'));
useSetHeaderType(HeaderType.LeftArrow);
useSetOnBack(() => {
navigate(PATHS.home);
});
useSetFooterMode(false);
useSetFooterMode(false);
const { mutateAsync: cashReceiptList } = useCashReceiptListMutation();
const { mutateAsync: cashReceiptSummary } = useCashReceiptSummaryMutation();
@@ -157,6 +163,14 @@ export const CashReceiptListPage = () => {
setEmailBottomSheetOn(true);
};
const setDetailData = (detailData: DetailData) => {
setDetailOn(detailData.detailOn);
setDetailTid(detailData.tid);
if(detailData?.serviceCode){
setDetailServiceCode(detailData?.serviceCode);
}
};
const onClickToOpenFilter = () => {
setFilterOn(!filterOn);
};
@@ -175,6 +189,9 @@ export const CashReceiptListPage = () => {
const onClickToTransactionType = (val: CashReceiptTransactionType) => {
setTransactionType(val);
};
const onClickToNavigate = () => {
navigate(PATHS.transaction.cashReceipt.handWrittenIssuance);
};
useEffect(() => {
callList();
@@ -271,11 +288,18 @@ export const CashReceiptListPage = () => {
<CashReceiptList
listItems={ listItems }
transactionCategory={ TransactionCategory.CashReceipt }
setDetailData={ setDetailData }
></CashReceiptList>
<div ref={ setTarget }></div>
</div>
</div>
</main>
<div className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={ () => onClickToNavigate() }
>{ t('transaction.list.manualIssuance') }</button>
</div>
<CashReceiptFilter
filterOn={ filterOn }
setFilterOn={ setFilterOn }
@@ -296,6 +320,11 @@ export const CashReceiptListPage = () => {
setSearchNumberType={ setSearchNumberType }
setSearchNumber={ setSearchNumber }
></CashReceiptFilter>
<CashReceiptDetail
detailOn={ detailOn }
setDetailOn={ setDetailOn }
tid={ detailTid }
></CashReceiptDetail>
{ !!emailBottomSheetOn &&
<EmailBottomSheet
bottomSheetOn={ emailBottomSheetOn }

View File

@@ -13,7 +13,8 @@ import {
EscrowSettlementStatus,
ListItemProps,
EscrowListParams,
EscrowListResponse
EscrowListResponse,
DetailData
} from '@/entities/transaction/model/types';
import { useEscrowListMutation } from '@/entities/transaction/api/use-escrow-list-mutation';
import { useDownloadExcelMutation } from '@/entities/transaction/api/use-download-excel-mutation';
@@ -30,6 +31,7 @@ import {
} from '@/widgets/sub-layout/use-sub-layout';
import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet';
import useIntersectionObserver from '@/widgets/intersection-observer';
import { EscrowDetail } from '@/entities/transaction/ui/detail/escrow-detail';
export const EscrowListPage = () => {
const { navigate } = useNavigate();
@@ -54,6 +56,10 @@ export const EscrowListPage = () => {
const [maxAmount, setMaxAmount] = useState<number>();
const [emailBottomSheetOn, setEmailBottomSheetOn] = useState<boolean>(false);
const [detailOn, setDetailOn] = useState<boolean>(false);
const [detailTid, setDetailTid] = useState<string>('');
const [detailServiceCode, setDetailServiceCode] = useState<string>('');
useSetHeaderTitle(t('escrow.title'));
useSetHeaderType(HeaderType.LeftArrow);
@@ -150,6 +156,15 @@ export const EscrowListPage = () => {
});
*/
};
const setDetailData = (detailData: DetailData) => {
setDetailOn(detailData.detailOn);
setDetailTid(detailData.tid);
if(detailData?.serviceCode){
setDetailServiceCode(detailData?.serviceCode);
}
};
const onClickToSort = (sort: SortTypeKeys) => {
setSortType(sort);
};
@@ -221,6 +236,7 @@ export const EscrowListPage = () => {
<EscrowList
listItems={ listItems }
transactionCategory={ TransactionCategory.Escrow }
setDetailData={ setDetailData }
></EscrowList>
<div ref={ setTarget }></div>
</div>
@@ -248,6 +264,12 @@ export const EscrowListPage = () => {
setMinAmount={ setMinAmount }
setMaxAmount={ setMaxAmount }
></EscrowFilter>
<EscrowDetail
detailOn={ detailOn }
setDetailOn={ setDetailOn }
tid={ detailTid }
serviceCode={ detailServiceCode }
></EscrowDetail>
{ !!emailBottomSheetOn &&
<EmailBottomSheet
bottomSheetOn={ emailBottomSheetOn }

View File

@@ -2,39 +2,30 @@ import { Route } from 'react-router-dom';
import { SentryRoutes } from '@/shared/configs/sentry';
import { ROUTE_NAMES } from '@/shared/constants/route-names';
import { AllTransactionListPage } from './all-transaction/list-page';
import { AllTransactionDetailPage } from './all-transaction/detail-page';
import { AllTransactionCancelPage } from './all-transaction/cancel-page';
import { CashReceiptListPage } from './cash-receipt/list-page';
import { CashReceiptDetailPage } from './cash-receipt/detail-page';
import { CashReceitHandWrittenIssuancePage } from './cash-receipt/hand-written-issuance-page';
import { EscrowListPage } from './escrow/list-page';
import { EscrowDetailPage } from './escrow/detail-page';
import { BillingListPage } from './billing/list-page';
import { BillingDetailPage } from './billing/detail-page';
import { BillingChargePage } from './billing/charge-page';
export const TransactionPages = () => {
return (
<>
<SentryRoutes>
<Route path={ROUTE_NAMES.transaction.allTransaction.base}>
<Route path={ROUTE_NAMES.transaction.allTransaction.list} element={<AllTransactionListPage />} />
<Route path={ROUTE_NAMES.transaction.allTransaction.detail} element={<AllTransactionDetailPage />} />
<Route path={ROUTE_NAMES.transaction.allTransaction.cancel} element={<AllTransactionCancelPage />} />
</Route>
<Route path={ROUTE_NAMES.transaction.cashReceipt.base}>
<Route path={ROUTE_NAMES.transaction.cashReceipt.list} element={<CashReceiptListPage />} />
<Route path={ROUTE_NAMES.transaction.cashReceipt.detail} element={<CashReceiptDetailPage />} />
<Route path={ROUTE_NAMES.transaction.cashReceipt.handWrittenIssuance} element={<CashReceitHandWrittenIssuancePage />} />
</Route>
<Route path={ROUTE_NAMES.transaction.escrow.base}>
<Route path={ROUTE_NAMES.transaction.escrow.list} element={<EscrowListPage />} />
<Route path={ROUTE_NAMES.transaction.escrow.detail} element={<EscrowDetailPage />} />
</Route>
<Route path={ROUTE_NAMES.transaction.billing.base}>
<Route path={ROUTE_NAMES.transaction.billing.list} element={<BillingListPage />} />
<Route path={ROUTE_NAMES.transaction.billing.detail} element={<BillingDetailPage />} />
<Route path={ROUTE_NAMES.transaction.billing.charge} element={<BillingChargePage />} />
</Route>
</SentryRoutes>

View File

@@ -20,10 +20,6 @@ export const PATHS: RouteNamesType = {
`${ROUTE_NAMES.transaction.base}${ROUTE_NAMES.transaction.allTransaction.base}`,
ROUTE_NAMES.transaction.allTransaction.list,
),
detail: generatePath(
`${ROUTE_NAMES.transaction.base}${ROUTE_NAMES.transaction.allTransaction.base}`,
ROUTE_NAMES.transaction.allTransaction.detail,
),
cancel: generatePath(
`${ROUTE_NAMES.transaction.base}${ROUTE_NAMES.transaction.allTransaction.base}`,
ROUTE_NAMES.transaction.allTransaction.cancel,
@@ -35,10 +31,6 @@ export const PATHS: RouteNamesType = {
`${ROUTE_NAMES.transaction.base}${ROUTE_NAMES.transaction.cashReceipt.base}`,
ROUTE_NAMES.transaction.cashReceipt.list,
),
detail: generatePath(
`${ROUTE_NAMES.transaction.base}${ROUTE_NAMES.transaction.cashReceipt.base}`,
ROUTE_NAMES.transaction.cashReceipt.detail,
),
handWrittenIssuance: generatePath(
`${ROUTE_NAMES.transaction.base}${ROUTE_NAMES.transaction.cashReceipt.base}`,
ROUTE_NAMES.transaction.cashReceipt.handWrittenIssuance,
@@ -50,10 +42,6 @@ export const PATHS: RouteNamesType = {
`${ROUTE_NAMES.transaction.base}${ROUTE_NAMES.transaction.escrow.base}`,
ROUTE_NAMES.transaction.escrow.list,
),
detail: generatePath(
`${ROUTE_NAMES.transaction.base}${ROUTE_NAMES.transaction.escrow.base}`,
ROUTE_NAMES.transaction.escrow.detail,
),
},
billing: {
base: generatePath(`${ROUTE_NAMES.transaction.base}${ROUTE_NAMES.transaction.billing.base}`),
@@ -61,10 +49,6 @@ export const PATHS: RouteNamesType = {
`${ROUTE_NAMES.transaction.base}${ROUTE_NAMES.transaction.billing.base}`,
ROUTE_NAMES.transaction.billing.list,
),
detail: generatePath(
`${ROUTE_NAMES.transaction.base}${ROUTE_NAMES.transaction.billing.base}`,
ROUTE_NAMES.transaction.billing.detail,
),
charge: generatePath(
`${ROUTE_NAMES.transaction.base}${ROUTE_NAMES.transaction.billing.base}`,
ROUTE_NAMES.transaction.billing.charge,

View File

@@ -5,24 +5,20 @@ export const ROUTE_NAMES = {
allTransaction: {
base: '/all-transaction/*',
list: 'list',
detail: 'detail',
cancel: 'cancel',
},
cashReceipt: {
base: '/cash-receipt/*',
list: 'list',
detail: 'detail',
handWrittenIssuance: 'hand-written-issuance',
},
escrow: {
base: '/escrow/*',
list: 'list',
detail: 'detail',
},
billing: {
base: '/billing/*',
list: 'list',
detail: 'detail',
charge: 'charge',
}
},