메뉴 권한 및 ui 수정

This commit is contained in:
focp212@naver.com
2025-11-05 14:03:50 +09:00
parent 7d158c8a6e
commit a4807c4013
13 changed files with 53 additions and 489 deletions

View File

@@ -5,6 +5,7 @@ import { RefObject, useEffect, useState } from 'react';
import { MenuItem } from '../model/types';
import { useTranslation } from 'react-i18next';
import { MenuItems } from '@/entities/common/model/constant';
import { showAlert } from '@/widgets/show-alert';
export interface MenuCategoryProps {
menuId?: number;
@@ -33,15 +34,30 @@ export const MenuCategory = ({
}: MenuCategoryProps) => {
const { navigate } = useNavigate();
const { i18n } = useTranslation();
const menuGrantsByKey = useStore.getState().UserStore.menuGrantsByKey;
const [favoriteItems, setFavoriteItems] = useState<Array<UserFavorite>>([]);
const [menuIds, setMenuIds] = useState<Array<number | undefined>>([]);
const onClickToNavigate = (path?: string, menuId?: number) => {
const checkGrant = (menuId?: number) => {
const myGrants = menuGrantsByKey['' + menuId];
if(myGrants?.includes('R')){
return true
}
return false;
};
const onClickToNavigate = (menuId?: number, path?: string) => {
if(menuId && checkGrant(menuId)){
if(!!path && !!setMenuOn && !editMode){
setMenuOn(false);
navigate(path);
}
}
else{
showAlert('권한이 없습니다.');
}
};
const favoriteSetting = (
@@ -121,7 +137,7 @@ export const MenuCategory = ({
rs.push(
<li
key={ `menu-item-key-${menuId}-${i}` }
onClick={ () => onClickToNavigate(subMenu[i]?.programPath) }
onClick={ () => onClickToNavigate(subMenu[i]?.menuId, subMenu[i]?.programPath) }
>
<span>{ displayName }</span>
<div className="check_box_scrap">
@@ -151,7 +167,7 @@ export const MenuCategory = ({
rs.push(
<li
key={ `menu-item-key-${i}` }
onClick={ () => onClickToNavigate(subMenu[i]?.programPath) }
onClick={ () => onClickToNavigate(subMenu[i]?.menuId, subMenu[i]?.programPath) }
>{ displayName }</li>
);
}

View File

@@ -59,7 +59,10 @@ export const FaqDetail = ({
<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
className="faq-detail__body"
dangerouslySetInnerHTML={{ __html: contents || '' }}
></div>
</div>
</div>
}

View File

@@ -67,7 +67,10 @@ export const NoticeDetail = ({
<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
className="notice-detail__body"
dangerouslySetInnerHTML={{ __html: result.contents || '' }}
></div>
</div>
</div>
</div>

View File

@@ -85,11 +85,17 @@ export const QnaDetail = ({
<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: result?.answer || '' }}></div>
<div
className="inq-detail__body"
dangerouslySetInnerHTML={{ __html: result?.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: result?.contents || '' }}></div>
<div
className="inq-detail__body"
dangerouslySetInnerHTML={{ __html: result?.contents || '' }}
></div>
</div>
</div>
</div>

View File

@@ -1,5 +1,3 @@
import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { FaqItemProps } from '../model/types';
import { useTranslation } from 'react-i18next';

View File

@@ -1,6 +1,4 @@
import moment from 'moment';
import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { NoticeItemProps } from '../model/types';
import { useTranslation } from 'react-i18next';
@@ -8,7 +6,6 @@ export const SupportNoticeItem = ({
noticeItem,
setDetailData,
}: NoticeItemProps) => {
const { navigate } = useNavigate();
const { t } = useTranslation();
const onClickToDetail = () => {

View File

@@ -19,7 +19,6 @@ import {
useSetFooterMode
} from '@/widgets/sub-layout/use-sub-layout';
import { useAllTransactioCancleInfoMutation } from '@/entities/transaction/api/use-all-transaction-cancel-info-mutation';
import { NumericFormat } from 'react-number-format';
import { useStore } from '@/shared/model/store';
import { AllTransactionCancelPreventBond } from '@/entities/transaction/ui/all-transaction-cancel-prevent-bond';
import { snackBar } from '@/shared/lib';

View File

@@ -32,13 +32,13 @@ 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';
import { showAlert } from '@/widgets/show-alert';
import { snackBar } from '@/shared/lib';
/* 거래내역조회 31 */
export const AllTransactionListPage = () => {
const menuGrantsByKey = useStore.getState().UserStore.menuGrantsByKey;
const myGrants = menuGrantsByKey['31'];
const { navigate } = useNavigate();
const { t, i18n } = useTranslation();
const userMid = useStore.getState().UserStore.mid;

View File

@@ -1,97 +0,0 @@
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useLocation } from 'react-router';
import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { useBillingDetailMutation } from '@/entities/transaction/api/use-billing-detail-mutation';
import { BillingInfoSection } from '@/entities/transaction/ui/section/billing-info-section';
import { HeaderType } from '@/entities/common/model/types';
import {
TransactionCategory,
BillingDetailParams,
BillingDetailResponse,
BillingInfo,
AmountInfo
} from '@/entities/transaction/model/types';
import {
useSetOnBack,
useSetHeaderTitle,
useSetHeaderType,
useSetFooterMode
} from '@/widgets/sub-layout/use-sub-layout';
import { NumericFormat } from 'react-number-format';
import { C } from 'node_modules/react-router/dist/development/index-react-server-client-DRhjXpk2.mjs';
import { AmountInfoSection } from '@/entities/transaction/ui/section/amount-info-section';
export const BillingDetailPage = () => {
const { navigate } = useNavigate();
const { t, i18n } = useTranslation();
const location = useLocation();
const tid = location?.state.tid;
const serviceCode = location?.state.serviceCode;
const [billingInfo, setBillingInfo] = useState<BillingInfo>();
const [amountInfo, setAmountInfo] = useState<AmountInfo>();
useSetHeaderTitle(t('billing.detailTitle'));
useSetHeaderType(HeaderType.RightClose);
useSetOnBack(() => {
navigate(PATHS.transaction.billing.list);
});
useSetFooterMode(false);
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
})
});
};
useEffect(() => {
callDetail();
}, []);
return (
<>
<main>
<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">
{ 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>
</main>
</>
);
};

View File

@@ -1,161 +0,0 @@
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useLocation } from 'react-router';
import { PATHS } from '@/shared/constants/paths';
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 { HeaderType } from '@/entities/common/model/types';
import {
TransactionCategory,
CashReceiptDetailParams,
DetailResponse,
IssueInfo,
DetailInfo,
InfoSectionKeys,
CashReceiptPurposeType,
AmountInfo,
CashReceiptPurposeUpdateParams,
CashReceiptTransactionType
} from '@/entities/transaction/model/types';
import {
useSetOnBack,
useSetHeaderTitle,
useSetHeaderType,
useSetFooterMode
} from '@/widgets/sub-layout/use-sub-layout';
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';
export const CashReceiptDetailPage = () => {
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);
useSetHeaderTitle(t('cashReceipt.detailTitle'));
useSetHeaderType(HeaderType.RightClose);
useSetOnBack(() => {
navigate(PATHS.transaction.cashReceipt.list);
});
useSetFooterMode(false);
const tid = location?.state.tid
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(() => {
callDetail();
}, []);
const onClickToOpenInfo = (infoSectionKey: InfoSectionKeys) => {
if(infoSectionKey === InfoSectionKeys.Amount){
setShowAmountInfo(!showAmountInfo);
}
else if(infoSectionKey === InfoSectionKeys.Detail){
setShowDetailInfo(!showDetailInfo);
}
};
const onClickToPurposeUpdate = () => {
setBottomSheetOn(true);
};
return (
<>
<main>
<div className="tab-content">
<div className="tab-pane sub active">
<div className="option-list">
<div className={ `txn-detail ${(detailInfo?.canDownloadReceipt)? 'pb-86': ''}` }>
<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>
</main>
<CashReceitPurposeUpdateBottomSheet
setBottomSheetOn={ setBottomSheetOn }
bottomSheetOn={ bottomSheetOn }
callPurposeUpdate={ callPurposeUpdate }
></CashReceitPurposeUpdateBottomSheet>
</>
);
};

View File

@@ -1,209 +0,0 @@
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useLocation } from 'react-router';
import { PATHS } from '@/shared/constants/paths';
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 { HeaderType } from '@/entities/common/model/types';
import {
TransactionCategory,
EscrowDetailParams,
DetailResponse,
ImportantInfo,
EscrowInfo,
PaymentInfo,
TransactionInfo,
SettlementInfo,
InfoSectionKeys,
MerchantInfo,
AmountInfo
} from '@/entities/transaction/model/types';
import {
useSetOnBack,
useSetHeaderTitle,
useSetHeaderType,
useSetFooterMode
} from '@/widgets/sub-layout/use-sub-layout';
import { EscrowMailResendBottomSheet } from '@/entities/transaction/ui/escrow-mail-resend-bottom-sheet';
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';
export const EscrowDetailPage = () => {
const { navigate } = useNavigate();
const { t } = useTranslation();
const location = useLocation();
const paramTid = location?.state.tid;
const serviceCode = location?.state.serviceCode;
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 [tid, setTid] = useState<string | undefined>(paramTid);
useSetHeaderTitle(t('escrow.detailTitle'));
useSetHeaderType(HeaderType.RightClose);
useSetOnBack(() => {
navigate(PATHS.transaction.escrow.list);
});
useSetFooterMode(false);
const { mutateAsync: escrowDetail } = useEscrowDetailMutation();
const { mutateAsync: escrowMailResend } = useEscrowMailResendMutation()
const callDetail = () => {
let escroDetailParams: EscrowDetailParams = {
tid: tid || paramTid,
};
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);
setTid(rs.importantInfo?.tid);
});
};
useEffect(() => {
callDetail();
}, []);
const onClickToShowMailResend = () => {
setBottomSheetOn(true);
};
const callMailResend = () => {
let params = {
orderNumber: orderNumber,
tid: tid,
};
escrowMailResend(params).then((rs: any) => {
console.log(rs);
});
};
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 (
<>
<main>
<div className="tab-content pb-86">
<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 className="apply-row">
<button
className="btn-50 btn-blue flex-1"
onClick={ () => onClickToShowMailResend() }
> </button>
</div>
</div>
</div>
</main>
<EmailBottomSheet
setBottomSheetOn={ setBottomSheetOn }
bottomSheetOn={ bottomSheetOn }
imageSave={ false }
sendEmail={ true }
sendRequest={ callMailResend }
></EmailBottomSheet>
</>
);
};

View File

@@ -11,7 +11,7 @@ main {
width: 100%;
height: 100%;
background: #fff;
z-index: 9999;
z-index: 999;
display: unset;
/* overflow-y: auto; */
overflow-y: scroll;

View File

@@ -1,7 +1,15 @@
import { Dialog } from '@/shared/ui/dialogs/dialog';
import { overlay } from 'overlay-kit';
export const showAlert = (msg: string) => {
export const showAlert = (msg: string, callback?: () => void) => {
const onConfirmClick = () => {
if(!!callback && typeof(callback) === 'function'){
setTimeout(() => {
callback();
}, 10);
}
};
overlay.open(({
isOpen,
close,
@@ -14,6 +22,7 @@ export const showAlert = (msg: string) => {
onClose={ close }
message={ msg }
buttonLabel={ ['확인'] }
onConfirmClick={ onConfirmClick }
/>
);
});