결제 관리 페이지 및 컴포넌트 다국어화 완료

- 결제 관리 페이지 다국어화 (결제 정보, 통보 데이터)
  * 헤더 타이틀 및 탭 버튼 다국어화
- 결제 엔티티 컴포넌트 전체 다국어화
  * payment-tab: 결제 정보/결제데이터 통보 탭
  * info-wrap: 서비스 이용, 수수료 및 정산주기 섹션
  * notification-data-wrap: 결제데이터 통보 조회 (신용카드, 계좌이체 등 5개 결제수단)
  * info-item: 수수료 및 정산주기 버튼
  * notify-row: 통보 상세 정보 (시작일자, 관리자 메일, URL/IP 등)
- 결제 바텀시트 컴포넌트 다국어화
  * card-commission-bottom-sheet: 카드 수수료 (일반/무이자/머니포인트 탭, 할부개월)
  * transfer-commission-bottom-sheet: 계좌이체 수수료 (통화 표기 포함)
  * credit-card-list-bottom-sheet: 카드사 목록
  * no-interest-info-bottom-sheet: 무이자 정보 (통화 표기 포함)
- 통화 표기 개선 (한국어: 원 suffix / 영어: ₩ prefix)
- 번역 키 추가: payment 네임스페이스 32개 키
- 계정 관리 페이지 헤더 타이틀 다국어화 적용

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Jay Sheen
2025-10-29 17:56:37 +09:00
parent 00b0290fa7
commit 8529f501c7
14 changed files with 204 additions and 100 deletions

View File

@@ -1,4 +1,5 @@
import { motion } from 'framer-motion';
import { useTranslation } from 'react-i18next';
import { IMAGE_ROOT } from '@/shared/constants/common';
import { BottomSheetMotionDuration, BottomSheetMotionVaiants } from '@/entities/common/model/constant';
import { BankFees, CategoryFees, FeeRanges, GeneralTabItems, InstallmentTabItems, MoneyPointTabItems, PaymentFees } from '../model/types';
@@ -34,6 +35,7 @@ export const CardCommissionBottomSheet = ({
categoryFees,
feeRate
}: CardCommissionBottomSheetProps) => {
const { t } = useTranslation();
const cardList = useStore.getState().CommonStore.creditCardList;
const [selectedCard, setSelectedCard] = useState<string>(cardList[0].desc1);
@@ -56,14 +58,14 @@ export const CardCommissionBottomSheet = ({
>
<div className="bottomsheet-header">
<div className="bottomsheet-title">
<h2> </h2>
<button
className="close-btn"
<h2>{t('payment.commissionAndSettlement')}</h2>
<button
className="close-btn"
type="button"
>
<img
<img
src={ IMAGE_ROOT + '/ico_close.svg' }
alt="닫기"
alt={t('common.close')}
onClick={ () => onClickToClose() }
/>
</button>
@@ -72,31 +74,31 @@ export const CardCommissionBottomSheet = ({
<div className="bottomsheet-content">
<div className="card-fee">
<div className="desc"> : { settlementPeriod }</div>
<div className="desc">{t('payment.settlementPeriod')} : { settlementPeriod }</div>
<div className="notice-tabs">
{ (payType === 2 || payType === 3) &&
<button
className="tab36 on"
{ (payType === 2 || payType === 3) &&
<button
className="tab36 on"
type="button"
></button>
>{t('payment.general')}</button>
}
{ (payType === 2 || payType === 3) &&
<button
className="tab36"
<button
className="tab36"
type="button"
></button>
>{t('payment.noInterest')}</button>
}
{ (payType === 3) &&
<button
className="tab36"
<button
className="tab36"
type="button"
>/</button>
>{t('payment.moneyPoint')}</button>
}
</div>
<div className="card-fee-box">
<span className="label"></span>
<span className="label">{t('payment.cardCompany')}</span>
<div className="field wid-100">
<select
value={ selectedCard }
@@ -113,43 +115,43 @@ export const CardCommissionBottomSheet = ({
<div className="card-fee-list">
<div className="card-fee-list-header">
<span className="th-left"></span>
<span className="th-right"></span>
<span className="th-left">{t('payment.installmentMonths')}</span>
<span className="th-right">{t('payment.commission')}</span>
</div>
<div className="card-fee-row">
<span>02 </span>
<span>{t('payment.months', { count: 2 })}</span>
<span>2.000%</span>
</div>
<div className="card-fee-row">
<span>03 </span>
<span>{t('payment.months', { count: 3 })}</span>
<span>3.100%</span>
</div>
<div className="card-fee-row">
<span>04 </span>
<span>{t('payment.months', { count: 4 })}</span>
<span>4.400%</span>
</div>
<div className="card-fee-row">
<span>05 </span>
<span>{t('payment.months', { count: 5 })}</span>
<span>5.200%</span>
</div>
<div className="card-fee-row">
<span>06 </span>
<span>{t('payment.months', { count: 6 })}</span>
<span>6.000%</span>
</div>
<div className="card-fee-row">
<span>07 </span>
<span>{t('payment.months', { count: 7 })}</span>
<span>6.600%</span>
</div>
<div className="card-fee-row">
<span>08 </span>
<span>{t('payment.months', { count: 8 })}</span>
<span>7.500%</span>
</div>
<div className="card-fee-row">
<span>09 </span>
<span>{t('payment.months', { count: 9 })}</span>
<span>8.000%</span>
</div>
<div className="card-fee-row">
<span>10 </span>
<span>{t('payment.months', { count: 10 })}</span>
<span>9.000%</span>
</div>
</div>

View File

@@ -1,4 +1,5 @@
import { motion } from 'framer-motion';
import { useTranslation } from 'react-i18next';
import { IMAGE_ROOT } from '@/shared/constants/common';
import { BottomSheetMotionDuration, BottomSheetMotionVaiants } from '@/entities/common/model/constant';
import { useStore } from '@/shared/model/store';
@@ -13,6 +14,7 @@ export const CreditCardListBottomSheet = ({
creditCardListBottomSheetOn,
setCreditCardListBottomSheetOn
}: CreditCardListBottomSheetProps) => {
const { t } = useTranslation();
const cardList = useStore.getState().CommonStore.creditCardList;
const [selectedCard, setSelectedCard] = useState<string>(cardList[0].desc1);
@@ -35,14 +37,14 @@ export const CreditCardListBottomSheet = ({
>
<div className="bottomsheet-header">
<div className="bottomsheet-title">
<h2></h2>
<button
className="close-btn"
<h2>{t('payment.cardCompany')}</h2>
<button
className="close-btn"
type="button"
>
<img
<img
src={ IMAGE_ROOT + '/ico_close.svg' }
alt="닫기"
alt={t('common.close')}
onClick={ () => onClickToClose() }
/>
</button>
@@ -62,10 +64,10 @@ export const CreditCardListBottomSheet = ({
</div>
<div className="bottomsheet-footer">
<button
className="btn-50 btn-blue flex-1"
<button
className="btn-50 btn-blue flex-1"
type="button"
></button>
>{t('common.confirm')}</button>
</div>
</motion.div>
</>

View File

@@ -1,5 +1,6 @@
import {
PaymentInfoItemType,
import { useTranslation } from 'react-i18next';
import {
PaymentInfoItemType,
} from '../model/types';
export interface InfoItemProps {
@@ -21,6 +22,7 @@ export const InfoItem = ({
setPayType,
setBottomSheetOn
}: InfoItemProps) => {
const { t } = useTranslation();
const onClickToOpenBottomSheet = () => {
if(setPayType && payType){
@@ -42,11 +44,11 @@ export const InfoItem = ({
</div>
<span className="ing-card-name">{ payName }</span>
</div>
<button
className="ing-card-link"
<button
className="ing-card-link"
type="button"
onClick={ () => onClickToOpenBottomSheet() }
> &gt;</button>
>{t('payment.commissionAndSettlement')} &gt;</button>
</li>
</>
)

View File

@@ -1,4 +1,5 @@
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { IMAGE_ROOT } from '@/shared/constants/common';
import { InfoItem } from './info-item';
import { CardCommissionBottomSheet } from './card-commission-bottom-sheet';
@@ -33,7 +34,8 @@ import { usePaymentNonCardMutation } from '../api/use-payment-non-card-mutation'
import { usePaymentInstallmentMutation } from '../api/use-payment-installment-mutation';
export const InfoWrap = () => {
const { t } = useTranslation();
const [mid, setMid] = useState<string>('nictest00g');
const [noInterestInfoBottomSheetOn, setNoInterestInfoBottomSheetOn] = useState<boolean>(false);
@@ -212,12 +214,12 @@ export const InfoWrap = () => {
return (
<>
<div className="ing-list">
<div className="ing-title"> , </div>
<div className="ing-title">{t('payment.serviceUsageCommissionAndSettlement')}</div>
<ul className="ing-card-list">
{ getList(PaymentInfoItemType.Comission) }
</ul>
<div className="ing-title"> </div>
<div className="ing-title">{t('payment.merchantNoInterestInfo')}</div>
<ul className="ing-card-list">
{ getList(PaymentInfoItemType.NoInterest) }
</ul>

View File

@@ -1,4 +1,5 @@
import { motion } from 'framer-motion';
import { useTranslation } from 'react-i18next';
import { IMAGE_ROOT } from '@/shared/constants/common';
import { BottomSheetMotionVaiants, BottomSheetMotionDuration } from '@/entities/common/model/constant';
import { InstallmentDetails, PaymentInstallmentDetailResponse } from '../model/types';
@@ -23,6 +24,7 @@ export const NoInterestInfoBottomSheet = ({
installmentDetails,
changeToCardCompany
}: NoInterestInfoBottomSheetProps) => {
const { t, i18n } = useTranslation();
const cardList = useStore.getState().CommonStore.creditCardList;
const [selectedCard, setSelectedCard] = useState<string>(cardList[0].desc1);
@@ -52,23 +54,23 @@ export const NoInterestInfoBottomSheet = ({
>
<div className="bottomsheet-header">
<div className="bottomsheet-title">
<h2> </h2>
<button
className="close-btn"
<h2>{t('payment.noInterestInfo')}</h2>
<button
className="close-btn"
type="button"
>
<img
<img
src={ IMAGE_ROOT + '/ico_close.svg' }
alt="닫기"
alt={t('common.close')}
onClick={ () => onClickToClose() }
/>
</button>
</div>
</div>
<div className="fee-cycle">
<div className="card-fee-box">
<span className="label"></span>
<span className="label">{t('payment.cardCompany')}</span>
<div className="field wid-100">
{ !!cardCompanyOptions &&
<select onChange={ onChangeToCardCompany }>
@@ -87,24 +89,26 @@ export const NoInterestInfoBottomSheet = ({
&& installmentDetails.length > 0
&& installmentDetails.map((value, index) => (
<>
{ (index > 0) &&
{ (index > 0) &&
<div className="divider"></div>
}
<div className="desc dot">
<span> : </span>
<span>{t('payment.installmentMonths')} : </span>
<span>{ value.installmentMonths }</span>
</div>
<div className="desc dot">
<span> : </span>
<span>{t('payment.applicationPeriod')} : </span>
<span>{ value.applicationPeriod }</span>
</div>
<div className="desc dot">
<span> : </span>
<span>{t('payment.applicationAmount')} : </span>
<span>
<NumericFormat
value={ value.applicationAmount }
value={ value.applicationAmount }
thousandSeparator
displayType="text"
prefix={i18n.language === 'en' ? t('home.currencySymbol') : ''}
suffix={i18n.language === 'en' ? '' : t('home.currencyWon')}
></NumericFormat>
</span>
</div>

View File

@@ -1,10 +1,12 @@
import { ChangeEvent, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { NotifyRowKeys } from '../model/types';
import { usePaymentNotificationDataMutation } from '../api/use-payment-notification-data-mutation';
import { useStore } from '@/shared/model/store';
import { NotifyRow } from './section/notify-row';
export const NotificationDataWrap = () => {
const { t } = useTranslation();
const midOptions = useStore.getState().UserStore.selectOptionsMids;
const userMid = useStore.getState().UserStore.mid;
@@ -60,12 +62,12 @@ export const NotificationDataWrap = () => {
</div>
<div className="notify-container">
<div className="notify-header">
<h3 className="notify-title"> </h3>
<h3 className="notify-title">{t('payment.notificationDataInquiry')}</h3>
</div>
<ul className="notify-list">
<li>
<NotifyRow
paymentMethodName='신용카드'
paymentMethodName={t('payment.paymentMethods.creditCard')}
type={ NotifyRowKeys.CreditCard }
startDate={ creditCard?.startDate }
adminEmail={ creditCard?.adminEmail }
@@ -81,7 +83,7 @@ export const NotificationDataWrap = () => {
<li className="notify-divider"></li>
<li>
<NotifyRow
paymentMethodName='계좌이체'
paymentMethodName={t('payment.paymentMethods.accountTransfer')}
type={ NotifyRowKeys.AccountTransfer }
startDate={ accountTransfer?.startDate }
adminEmail={ accountTransfer?.adminEmail }
@@ -97,7 +99,7 @@ export const NotificationDataWrap = () => {
<li className="notify-divider"></li>
<li>
<NotifyRow
paymentMethodName='가상계좌'
paymentMethodName={t('payment.paymentMethods.virtualAccount')}
type={ NotifyRowKeys.VirtualAccount }
startDate={ virtualAccount?.startDate }
adminEmail={ virtualAccount?.adminEmail }
@@ -113,7 +115,7 @@ export const NotificationDataWrap = () => {
<li className="notify-divider"></li>
<li>
<NotifyRow
paymentMethodName='휴대폰'
paymentMethodName={t('payment.paymentMethods.mobilePayment')}
type={ NotifyRowKeys.MobilePayment }
startDate={ mobilePayment?.startDate }
adminEmail={ mobilePayment?.adminEmail }
@@ -129,7 +131,7 @@ export const NotificationDataWrap = () => {
<li className="notify-divider"></li>
<li>
<NotifyRow
paymentMethodName='에스크로 결제'
paymentMethodName={t('payment.paymentMethods.escrowPayment')}
type={ NotifyRowKeys.EscrowPayment }
startDate={ escrowPayment?.startDate }
adminEmail={ escrowPayment?.adminEmail }
@@ -145,8 +147,8 @@ export const NotificationDataWrap = () => {
</ul>
</div>
<div className="notify-bar">
<span> PC에서 .</span>
<span> .</span>
<span>{t('payment.notificationDataSettingInfo')}</span>
<span>{t('payment.onlyConfiguredPaymentMethodsShown')}</span>
</div>
</div>
</>

View File

@@ -1,6 +1,7 @@
import { useTranslation } from 'react-i18next';
import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import {
import {
PaymentTabKeys,
PaymentTabProps
} from '../model/types';
@@ -8,6 +9,7 @@ import {
export const PaymentTab = ({
activeTab
}: PaymentTabProps) => {
const { t } = useTranslation();
const { navigate } = useNavigate();
const onClickToNavigation = (tab: PaymentTabKeys) => {
@@ -23,14 +25,14 @@ export const PaymentTab = ({
return(
<>
<div className="subTab">
<button
<button
className={`subtab-btn ${(activeTab === PaymentTabKeys.Info)? 'active': ''}` }
onClick={ () => onClickToNavigation(PaymentTabKeys.Info) }
> </button>
<button
onClick={ () => onClickToNavigation(PaymentTabKeys.Info) }
>{t('payment.info')}</button>
<button
className={`subtab-btn ${(activeTab === PaymentTabKeys.NotificationData)? 'active': ''}` }
onClick={ () => onClickToNavigation(PaymentTabKeys.NotificationData) }
> </button>
onClick={ () => onClickToNavigation(PaymentTabKeys.NotificationData) }
>{t('payment.notificationData')}</button>
</div>
</>
);

View File

@@ -1,5 +1,6 @@
import moment from 'moment';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { SlideDown } from 'react-slidedown';
import 'react-slidedown/lib/slidedown.css';
import { NotifyRowKeys } from '../../model/types';
@@ -31,6 +32,7 @@ export const NotifyRow = ({
openChild,
setOpenChild
}: NotifyRowProps) => {
const { t } = useTranslation();
const [isOpen, setIsOpen] = useState<boolean>(false);
const openNotifyRow = () => {
@@ -63,13 +65,13 @@ export const NotifyRow = ({
{ isOpen &&
<div className="notify-content">
<ul className="notify-detail-list">
<li className="notify-detail-item"> : { (!!startDate)? moment(startDate).format('YYYY-MM-DD'): '' }</li>
<li className="notify-detail-item"> : { adminEmail } </li>
<li className="notify-detail-item">URL/IP : { urlIp }</li>
<li className="notify-detail-item"> : { retransmissionInterval }</li>
<li className="notify-detail-item"> : { retransmissionCount }</li>
<li className="notify-detail-item">OK : { okCheck }</li>
<li className="notify-detail-item"> : { encryptionStatus }</li>
<li className="notify-detail-item">{t('payment.startDate')} : { (!!startDate)? moment(startDate).format('YYYY-MM-DD'): '' }</li>
<li className="notify-detail-item">{t('payment.adminEmail')} : { adminEmail } </li>
<li className="notify-detail-item">{t('payment.urlIp')} : { urlIp }</li>
<li className="notify-detail-item">{t('payment.retransmissionInterval')} : { retransmissionInterval }</li>
<li className="notify-detail-item">{t('payment.retransmissionCount')} : { retransmissionCount }</li>
<li className="notify-detail-item">{t('payment.okCheck')} : { okCheck }</li>
<li className="notify-detail-item">{t('payment.encryptionStatus')} : { encryptionStatus }</li>
</ul>
</div>
}

View File

@@ -1,6 +1,8 @@
import { useTranslation } from 'react-i18next';
import { IMAGE_ROOT } from '@/shared/constants/common';
export const TransferCommissionBottomSheet = () => {
const { t, i18n } = useTranslation();
return (
<>
@@ -8,43 +10,43 @@ export const TransferCommissionBottomSheet = () => {
<div className="bottomsheet">
<div className="bottomsheet-header">
<div className="bottomsheet-title">
<h2> </h2>
<button
className="close-btn"
<h2>{t('payment.commissionAndSettlement')}</h2>
<button
className="close-btn"
type="button"
>
<img
<img
src={ IMAGE_ROOT + '/ico_close.svg' }
alt="닫기"
alt={t('common.close')}
/>
</button>
</div>
</div>
<div className="fee-cycle">
<div className="desc dot">정산주기 : 일일(+3)</div>
<div className="desc dot"></div>
<div className="desc dot">{t('payment.settlementPeriod')} : {t('payment.dailyPlus3Days')}</div>
<div className="desc dot">{t('payment.commission')}</div>
<div className="divider"></div>
<ul className="kv-list">
<li className="kv-row pl-10">
<span className="k">()</span>
<span className="v">1</span>
<span className="k">{t('payment.paymentFeeMinimum')}</span>
<span className="v">1{i18n.language === 'en' ? '' : t('home.currencyWon')}</span>
</li>
<li className="kv-row pl-10">
<span className="k">(1~)</span>
<span className="v">1</span>
<span className="k">{t('payment.paymentFeeFrom1Won')}</span>
<span className="v">1{i18n.language === 'en' ? '' : t('home.currencyWon')}</span>
</li>
<li className="kv-row pl-10">
<span className="k"></span>
<span className="v">1</span>
<span className="k">{t('payment.cancellationFee')}</span>
<span className="v">1{i18n.language === 'en' ? '' : t('home.currencyWon')}</span>
</li>
</ul>
</div>
<div className="bottomsheet-footer">
<button
className="btn-50 btn-blue flex-1"
<button
className="btn-50 btn-blue flex-1"
type="button"
></button>
>{t('common.confirm')}</button>
</div>
</div>
</>