가맹점 관리 페이지 및 컴포넌트 다국어화 완료

- 가맹점 관리 페이지 다국어화 (가맹점 정보, 등록현황)
  * 헤더 타이틀 및 탭 버튼 다국어화
- 가맹점 엔티티 컴포넌트 전체 다국어화
  * merchant-tab: 가맹점 정보/등록현황 탭
  * info-wrap: 계약/기술/정산 담당자 섹션, 안내 메시지
  * registration-status-wrap: 신용카드 심사현황, 에스크로 가입현황
- 가맹점 섹션 컴포넌트 다국어화
  * account-section: 정산계좌 정보 (은행, 계좌번호, 예금주)
  * business-section: 기본정보 (상호, 사업자번호, 업종, 업태 등 11개 필드)
  * online-section: 온라인 등록현황 (상태, 계약완료, 심사 여부 등)
  * escrow-section: 에스크로 정보 (NICECROW 가입, 소재지, URL 등)
- 번역 키 추가: merchant 네임스페이스 35개 키
- 모든 가맹점 관리 필드 및 라벨 일관된 다국어 지원

🤖 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 18:04:08 +09:00
parent 8d67d59d78
commit 9b193ee6f9
11 changed files with 145 additions and 55 deletions

View File

@@ -1,4 +1,5 @@
import { ChangeEvent, useEffect, useState } from 'react'; import { ChangeEvent, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useMerchantMidMutation } from '../api/use-merchant-mid-mutation'; import { useMerchantMidMutation } from '../api/use-merchant-mid-mutation';
import { BusinessSection } from './section/business-section'; import { BusinessSection } from './section/business-section';
import { ManagerSection } from './section/manager-section'; import { ManagerSection } from './section/manager-section';
@@ -11,6 +12,7 @@ import {
import { useStore } from '@/shared/model/store'; import { useStore } from '@/shared/model/store';
export const InfoWrap = () => { export const InfoWrap = () => {
const { t } = useTranslation();
const midOptions = useStore.getState().UserStore.selectOptionsMids; const midOptions = useStore.getState().UserStore.selectOptionsMids;
const userMid = useStore.getState().UserStore.mid; const userMid = useStore.getState().UserStore.mid;
@@ -61,7 +63,7 @@ export const InfoWrap = () => {
<div className="info-divider mb-16"></div> <div className="info-divider mb-16"></div>
<ManagerSection <ManagerSection
type={ SectionKeys.Merchant } type={ SectionKeys.Merchant }
title='계약 담당자' title={t('merchant.contractManager')}
manager={ data?.merchantManager } manager={ data?.merchantManager }
managerTelephone={ data?.merchantManagerTelephone } managerTelephone={ data?.merchantManagerTelephone }
managetEmail={ data?.merchantManagerEmail } managetEmail={ data?.merchantManagerEmail }
@@ -71,7 +73,7 @@ export const InfoWrap = () => {
<div className="info-divider mb-16"></div> <div className="info-divider mb-16"></div>
<ManagerSection <ManagerSection
type={ SectionKeys.Technical } type={ SectionKeys.Technical }
title='기술 담당자' title={t('merchant.technicalManager')}
manager={ data?.technicalManager } manager={ data?.technicalManager }
managerTelephone={ data?.technicalManagerTelephone } managerTelephone={ data?.technicalManagerTelephone }
managetEmail={ data?.technicalManagerEmail } managetEmail={ data?.technicalManagerEmail }
@@ -81,7 +83,7 @@ export const InfoWrap = () => {
<div className="info-divider mb-16"></div> <div className="info-divider mb-16"></div>
<ManagerSection <ManagerSection
type={ SectionKeys.Settlement } type={ SectionKeys.Settlement }
title='정산 담당자' title={t('merchant.settlementManager')}
manager={ data?.settlementManager } manager={ data?.settlementManager }
managerTelephone={ data?.settlementManagerTelephone } managerTelephone={ data?.settlementManagerTelephone }
managetEmail={ data?.settlementManagerEmail } managetEmail={ data?.settlementManagerEmail }
@@ -93,7 +95,7 @@ export const InfoWrap = () => {
data={ data } data={ data }
></AccountSection> ></AccountSection>
<div className="notice-bottom left-align"> <div className="notice-bottom left-align">
<p className="notice-tip"> .<br/>PC .</p> <p className="notice-tip">{t('merchant.infoNotice')}</p>
</div> </div>
</div> </div>
</> </>

View File

@@ -1,3 +1,4 @@
import { useTranslation } from 'react-i18next';
import { PATHS } from '@/shared/constants/paths'; import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate'; import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { import {
@@ -8,6 +9,7 @@ import {
export const MerchantTab = ({ export const MerchantTab = ({
activeTab activeTab
}: MerchantTabProps) => { }: MerchantTabProps) => {
const { t } = useTranslation();
const { navigate } = useNavigate(); const { navigate } = useNavigate();
const onClickToNavigation = (tab: MerchantTabKeys) => { const onClickToNavigation = (tab: MerchantTabKeys) => {
@@ -26,11 +28,11 @@ export const MerchantTab = ({
<button <button
className={`subtab-btn ${(activeTab === MerchantTabKeys.Info)? 'active': ''}` } className={`subtab-btn ${(activeTab === MerchantTabKeys.Info)? 'active': ''}` }
onClick={ () => onClickToNavigation(MerchantTabKeys.Info) } onClick={ () => onClickToNavigation(MerchantTabKeys.Info) }
> </button> >{t('merchant.info')}</button>
<button <button
className={`subtab-btn ${(activeTab === MerchantTabKeys.RegistrationStatus)? 'active': ''}` } className={`subtab-btn ${(activeTab === MerchantTabKeys.RegistrationStatus)? 'active': ''}` }
onClick={ () => onClickToNavigation(MerchantTabKeys.RegistrationStatus) } onClick={ () => onClickToNavigation(MerchantTabKeys.RegistrationStatus) }
></button> >{t('merchant.registrationStatus')}</button>
</div> </div>
</> </>
); );

View File

@@ -1,4 +1,5 @@
import { ChangeEvent, useEffect, useState } from 'react'; import { ChangeEvent, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useMerchantMidStatusMutation } from '../api/use-merchant-mid-status-mutation'; import { useMerchantMidStatusMutation } from '../api/use-merchant-mid-status-mutation';
import { import {
CardApplications, CardApplications,
@@ -15,6 +16,7 @@ import { EscrowSection } from './section/escrow-section';
import { useStore } from '@/shared/model/store'; import { useStore } from '@/shared/model/store';
export const RegistrationStatusWrap = () => { export const RegistrationStatusWrap = () => {
const { t } = useTranslation();
const midOptions = useStore.getState().UserStore.selectOptionsMids; const midOptions = useStore.getState().UserStore.selectOptionsMids;
const userMid = useStore.getState().UserStore.mid; const userMid = useStore.getState().UserStore.mid;
@@ -69,7 +71,7 @@ export const RegistrationStatusWrap = () => {
<div className="info-divider mb-16"></div> <div className="info-divider mb-16"></div>
<CardSection <CardSection
type={ SectionKeys.Card } type={ SectionKeys.Card }
title='신용카드 심사현황' title={t('merchant.cardReviewStatus')}
cardApplications={ cardApplications } cardApplications={ cardApplications }
openChild={ openChild } openChild={ openChild }
setOpenChild={ setOpenChild } setOpenChild={ setOpenChild }
@@ -77,7 +79,7 @@ export const RegistrationStatusWrap = () => {
<div className="info-divider mb-16"></div> <div className="info-divider mb-16"></div>
<EscrowSection <EscrowSection
type={ SectionKeys.Escrow } type={ SectionKeys.Escrow }
title='에스크로 가입현황' title={t('merchant.escrowRegistrationStatus')}
companyName={ escrow?.companyName } companyName={ escrow?.companyName }
businessRegistrationNumber={ escrow?.businessRegistrationNumber } businessRegistrationNumber={ escrow?.businessRegistrationNumber }
escrowStatus={ escrow?.escrowStatus } escrowStatus={ escrow?.escrowStatus }

View File

@@ -1,3 +1,4 @@
import { useTranslation } from 'react-i18next';
import { MerchantMidResponse } from '../../model/types'; import { MerchantMidResponse } from '../../model/types';
export interface AccountSectionProps { export interface AccountSectionProps {
@@ -7,22 +8,23 @@ export interface AccountSectionProps {
export const AccountSection = ({ export const AccountSection = ({
data data
}: AccountSectionProps) => { }: AccountSectionProps) => {
const { t } = useTranslation();
return ( return (
<> <>
<div className="section"> <div className="section">
<div className="section-title"></div> <div className="section-title">{t('merchant.settlementAccount')}</div>
<ul className="kv-list"> <ul className="kv-list">
<li className="kv-row"> <li className="kv-row">
<span className="k"></span> <span className="k">{t('merchant.bank')}</span>
<span className="v">{ data?.bankName }</span> <span className="v">{ data?.bankName }</span>
</li> </li>
<li className="kv-row"> <li className="kv-row">
<span className="k"></span> <span className="k">{t('merchant.accountNumber')}</span>
<span className="v">{ data?.accountNumber }</span> <span className="v">{ data?.accountNumber }</span>
</li> </li>
<li className="kv-row"> <li className="kv-row">
<span className="k"></span> <span className="k">{t('merchant.accountHolder')}</span>
<span className="v">{ data?.accountHolderName }</span> <span className="v">{ data?.accountHolderName }</span>
</li> </li>
</ul> </ul>

View File

@@ -1,3 +1,4 @@
import { useTranslation } from 'react-i18next';
import { MerchantMidResponse } from '../../model/types'; import { MerchantMidResponse } from '../../model/types';
export interface BusinessSectionProps { export interface BusinessSectionProps {
@@ -7,30 +8,31 @@ export interface BusinessSectionProps {
export const BusinessSection = ({ export const BusinessSection = ({
data data
}: BusinessSectionProps) => { }: BusinessSectionProps) => {
const { t } = useTranslation();
return ( return (
<> <>
<div className="section"> <div className="section">
<div className="section-title"></div> <div className="section-title">{t('merchant.basicInfo')}</div>
<ul className="kv-list"> <ul className="kv-list">
<li className="kv-row"> <li className="kv-row">
<span className="k"></span> <span className="k">{t('merchant.companyName')}</span>
<span className="v">{ data?.businessCompanyName }</span> <span className="v">{ data?.businessCompanyName }</span>
</li> </li>
<li className="kv-row"> <li className="kv-row">
<span className="k"></span> <span className="k">{t('merchant.businessRegistrationNumber')}</span>
<span className="v">{ data?.businessRegistrationNumber }</span> <span className="v">{ data?.businessRegistrationNumber }</span>
</li> </li>
<li className="kv-row"> <li className="kv-row">
<span className="k"></span> <span className="k">{t('merchant.businessAttribute')}</span>
<span className="v">{ data?.businessScaleTypeName }</span> <span className="v">{ data?.businessScaleTypeName }</span>
</li> </li>
<li className="kv-row"> <li className="kv-row">
<span className="k"></span> <span className="k">{t('merchant.businessType')}</span>
<span className="v">{ data?.businessType }</span> <span className="v">{ data?.businessType }</span>
</li> </li>
<li className="kv-row"> <li className="kv-row">
<span className="k"></span> <span className="k">{t('merchant.businessCategory')}</span>
<span className="v">{ data?.businessCategory }</span> <span className="v">{ data?.businessCategory }</span>
</li> </li>
</ul> </ul>
@@ -39,15 +41,15 @@ export const BusinessSection = ({
<div className="section"> <div className="section">
<ul className="kv-list"> <ul className="kv-list">
<li className="kv-row"> <li className="kv-row">
<span className="k"></span> <span className="k">{t('merchant.representativeName')}</span>
<span className="v">{ data?.representativeName }</span> <span className="v">{ data?.representativeName }</span>
</li> </li>
<li className="kv-row"> <li className="kv-row">
<span className="k"> </span> <span className="k">{t('merchant.representativePhone')}</span>
<span className="v">{ data?.telephoneNumber }</span> <span className="v">{ data?.telephoneNumber }</span>
</li> </li>
<li className="kv-row"> <li className="kv-row">
<span className="k"> </span> <span className="k">{t('merchant.representativeEmail')}</span>
<span className="v">{ data?.email }</span> <span className="v">{ data?.email }</span>
</li> </li>
</ul> </ul>
@@ -56,11 +58,11 @@ export const BusinessSection = ({
<div className="section"> <div className="section">
<ul className="kv-list"> <ul className="kv-list">
<li className="kv-row"> <li className="kv-row">
<span className="k"></span> <span className="k">{t('merchant.businessAddress')}</span>
<span className="v">{ data?.businessAddress }</span> <span className="v">{ data?.businessAddress }</span>
</li> </li>
<li className="kv-row"> <li className="kv-row">
<span className="k"> </span> <span className="k">{t('merchant.websiteUrl')}</span>
<span className="v">{ data?.url }</span> <span className="v">{ data?.url }</span>
</li> </li>
</ul> </ul>

View File

@@ -1,3 +1,4 @@
import { useTranslation } from 'react-i18next';
import { SectionTitleArrow } from '@/entities/common/ui/section-title-arrow'; import { SectionTitleArrow } from '@/entities/common/ui/section-title-arrow';
import { Escrow, SectionKeys } from '../../model/types'; import { Escrow, SectionKeys } from '../../model/types';
import SlideDown from 'react-slidedown'; import SlideDown from 'react-slidedown';
@@ -23,6 +24,7 @@ export const EscrowSection = ({
openChild, openChild,
setOpenChild setOpenChild
}: EscrowSectionProps) => { }: EscrowSectionProps) => {
const { t } = useTranslation();
const [isOpen, setIsOpen] = useState<boolean>(false); const [isOpen, setIsOpen] = useState<boolean>(false);
@@ -55,27 +57,27 @@ export const EscrowSection = ({
{ isOpen && { isOpen &&
<ul className="kv-list"> <ul className="kv-list">
<li className="kv-row"> <li className="kv-row">
<span className="k"></span> <span className="k">{t('merchant.companyName')}</span>
<span className="v">{ companyName }</span> <span className="v">{ companyName }</span>
</li> </li>
<li className="kv-row"> <li className="kv-row">
<span className="k"></span> <span className="k">{t('merchant.businessRegistrationNumber')}</span>
<span className="v">{ businessRegistrationNumber }</span> <span className="v">{ businessRegistrationNumber }</span>
</li> </li>
<li className="kv-row"> <li className="kv-row">
<span className="k">NICECROW </span> <span className="k">{t('merchant.nicecrowJoin')}</span>
<span className="v">{ escrowStatus }</span> <span className="v">{ escrowStatus }</span>
</li> </li>
<li className="kv-row"> <li className="kv-row">
<span className="k"></span> <span className="k">{t('merchant.location')}</span>
<span className="v">{ address }</span> <span className="v">{ address }</span>
</li> </li>
<li className="kv-row"> <li className="kv-row">
<span className="k">URL</span> <span className="k">{t('merchant.url')}</span>
<span className="v">{ merchantUrl }</span> <span className="v">{ merchantUrl }</span>
</li> </li>
<li className="kv-row"> <li className="kv-row">
<span className="k"> </span> <span className="k">{t('merchant.serviceRegistrationNumber')}</span>
<span className="v">{ serviceRegistrationNumber }</span> <span className="v">{ serviceRegistrationNumber }</span>
</li> </li>
</ul> </ul>

View File

@@ -1,4 +1,5 @@
import moment from 'moment'; import moment from 'moment';
import { useTranslation } from 'react-i18next';
import { OnlineInfomation } from '../../model/types'; import { OnlineInfomation } from '../../model/types';
export interface OnlineSectionProps { export interface OnlineSectionProps {
@@ -8,38 +9,39 @@ export interface OnlineSectionProps {
export const OnlineSection = ({ export const OnlineSection = ({
data data
}: OnlineSectionProps) => { }: OnlineSectionProps) => {
const { t } = useTranslation();
return ( return (
<> <>
<div className="section"> <div className="section">
<div className="section-title"> </div> <div className="section-title">{t('merchant.onlineRegistrationStatus')}</div>
<ul className="kv-list"> <ul className="kv-list">
<li className="kv-row"> <li className="kv-row">
<span className="k"></span> <span className="k">{t('merchant.status')}</span>
<span className="v">{ data?.usageStatus }</span> <span className="v">{ data?.usageStatus }</span>
</li> </li>
<li className="kv-row"> <li className="kv-row">
<span className="k"></span> <span className="k">{t('merchant.companyName')}</span>
<span className="v">{ data?.companyName }</span> <span className="v">{ data?.companyName }</span>
</li> </li>
<li className="kv-row"> <li className="kv-row">
<span className="k"> </span> <span className="k">{t('merchant.businessRegistrationNumber')}</span>
<span className="v">{ data?.businessRegistrationNumber }</span> <span className="v">{ data?.businessRegistrationNumber }</span>
</li> </li>
<li className="kv-row"> <li className="kv-row">
<span className="k"></span> <span className="k">{t('merchant.issueDate')}</span>
<span className="v">{ data?.registrationDate }</span> <span className="v">{ data?.registrationDate }</span>
</li> </li>
<li className="kv-row"> <li className="kv-row">
<span className="k"> </span> <span className="k">{t('merchant.contractStatus')}</span>
<span className="v">{ data?.contractStatus }</span> <span className="v">{ data?.contractStatus }</span>
</li> </li>
<li className="kv-row"> <li className="kv-row">
<span className="k"> </span> <span className="k">{t('merchant.websiteReviewStatus')}</span>
<span className="v">{ data?.cardAuditStatus }</span> <span className="v">{ data?.cardAuditStatus }</span>
</li> </li>
<li className="kv-row"> <li className="kv-row">
<span className="k"></span> <span className="k">{t('merchant.guaranteeInsurance')}</span>
<span className="v">{ data?.insuranceAmount }</span> <span className="v">{ data?.insuranceAmount }</span>
</li> </li>
<li className="kv-row"> <li className="kv-row">

View File

@@ -333,5 +333,41 @@
"mobilePayment": "Mobile Payment", "mobilePayment": "Mobile Payment",
"escrowPayment": "Escrow Payment" "escrowPayment": "Escrow Payment"
} }
},
"merchant": {
"title": "Merchant Management",
"info": "Merchant Info",
"registrationStatus": "Registration Status",
"contractManager": "Contract Manager",
"technicalManager": "Technical Manager",
"settlementManager": "Settlement Manager",
"infoNotice": "※ Merchant information cannot be modified in the app.\nPlease configure it in the PC merchant admin.",
"cardReviewStatus": "Credit Card Review Status",
"escrowRegistrationStatus": "Escrow Registration Status",
"settlementAccount": "Settlement Account",
"bank": "Bank",
"accountNumber": "Account Number",
"accountHolder": "Account Holder",
"basicInfo": "Basic Information",
"companyName": "Company Name",
"businessRegistrationNumber": "Business Registration Number",
"businessAttribute": "Business Attribute",
"businessType": "Business Type",
"businessCategory": "Business Category",
"representativeName": "Representative Name",
"representativePhone": "Representative Phone",
"representativeEmail": "Representative Email",
"businessAddress": "Business Address",
"websiteUrl": "Website URL",
"onlineRegistrationStatus": "Online Registration Status",
"status": "Status",
"issueDate": "Issue Date",
"contractStatus": "Contract Status",
"websiteReviewStatus": "Website Review Status",
"guaranteeInsurance": "Guarantee Insurance",
"nicecrowJoin": "NICECROW Join",
"location": "Location",
"url": "URL",
"serviceRegistrationNumber": "Service Registration Number"
} }
} }

View File

@@ -337,5 +337,41 @@
"mobilePayment": "휴대폰", "mobilePayment": "휴대폰",
"escrowPayment": "에스크로 결제" "escrowPayment": "에스크로 결제"
} }
},
"merchant": {
"title": "가맹점 관리",
"info": "가맹점 정보",
"registrationStatus": "등록현황",
"contractManager": "계약 담당자",
"technicalManager": "기술 담당자",
"settlementManager": "정산 담당자",
"infoNotice": "※ 가맹점 정보는 앱에서 수정할 수 없습니다.\nPC 가맹점 관리자에서 설정해 주세요.",
"cardReviewStatus": "신용카드 심사현황",
"escrowRegistrationStatus": "에스크로 가입현황",
"settlementAccount": "정산계좌",
"bank": "은행",
"accountNumber": "계좌번호",
"accountHolder": "예금주",
"basicInfo": "기본정보",
"companyName": "상호",
"businessRegistrationNumber": "사업자번호",
"businessAttribute": "사업자속성",
"businessType": "업종",
"businessCategory": "업태",
"representativeName": "대표자명",
"representativePhone": "대표 연락처",
"representativeEmail": "대표 이메일",
"businessAddress": "사업장주소",
"websiteUrl": "홈페이지 주소",
"onlineRegistrationStatus": "온라인 등록현황",
"status": "상태",
"issueDate": "발급일자",
"contractStatus": "계약완료 여부",
"websiteReviewStatus": "홈페이지 심사 여부",
"guaranteeInsurance": "보증보험",
"nicecrowJoin": "NICECROW 가입",
"location": "소재지",
"url": "URL",
"serviceRegistrationNumber": "서비스 등록번호"
} }
} }

View File

@@ -1,4 +1,5 @@
import { useState } from 'react'; import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { PATHS } from '@/shared/constants/paths'; import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate'; import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { MerchantTab } from '@/entities/merchant/ui/merchant-tab'; import { MerchantTab } from '@/entities/merchant/ui/merchant-tab';
@@ -13,11 +14,12 @@ import {
} from '@/widgets/sub-layout/use-sub-layout'; } from '@/widgets/sub-layout/use-sub-layout';
export const InfoPage = () => { export const InfoPage = () => {
const { t } = useTranslation();
const { navigate } = useNavigate(); const { navigate } = useNavigate();
const [activeTab, setActiveTab] = useState<MerchantTabKeys>(MerchantTabKeys.Info); const [activeTab, setActiveTab] = useState<MerchantTabKeys>(MerchantTabKeys.Info);
useSetHeaderTitle('가맹점 관리'); useSetHeaderTitle(t('merchant.title'));
useSetHeaderType(HeaderType.LeftArrow); useSetHeaderType(HeaderType.LeftArrow);
useSetFooterMode(false); useSetFooterMode(false);
useSetOnBack(() => { useSetOnBack(() => {

View File

@@ -1,4 +1,5 @@
import { useState } from 'react'; import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { PATHS } from '@/shared/constants/paths'; import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate'; import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { MerchantTab } from '@/entities/merchant/ui/merchant-tab'; import { MerchantTab } from '@/entities/merchant/ui/merchant-tab';
@@ -13,11 +14,12 @@ import {
} from '@/widgets/sub-layout/use-sub-layout'; } from '@/widgets/sub-layout/use-sub-layout';
export const RegistrationStatusPage = () => { export const RegistrationStatusPage = () => {
const { t } = useTranslation();
const { navigate } = useNavigate(); const { navigate } = useNavigate();
const [activeTab, setActiveTab] = useState<MerchantTabKeys>(MerchantTabKeys.RegistrationStatus); const [activeTab, setActiveTab] = useState<MerchantTabKeys>(MerchantTabKeys.RegistrationStatus);
useSetHeaderTitle('가맹점 관리'); useSetHeaderTitle(t('merchant.title'));
useSetHeaderType(HeaderType.LeftArrow); useSetHeaderType(HeaderType.LeftArrow);
useSetFooterMode(false); useSetFooterMode(false);
useSetOnBack(() => { useSetOnBack(() => {