링크결제 신청 단계 폼 다국어 지원 추가
- Step1, Step2 폼 레이블 현지화 - 발송 수단, 상품 정보, 구매자 정보 등 모든 필드 번역 - 구매자 정보 대조 옵션(개인/법인) 다국어 적용 - 언어 선택(국문/영문), 링크내용(기본/추가) 현지화 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -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 { useSetOnBack } from '@/widgets/sub-layout/use-sub-layout';
|
import { useSetOnBack } from '@/widgets/sub-layout/use-sub-layout';
|
||||||
@@ -13,6 +14,7 @@ interface LinkPaymentStep1Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const LinkPaymentStep1 = ({ formData, setFormData }: LinkPaymentStep1Props) => {
|
export const LinkPaymentStep1 = ({ formData, setFormData }: LinkPaymentStep1Props) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const { navigate } = useNavigate();
|
const { navigate } = useNavigate();
|
||||||
const midOptionsWithoutGids = useStore.getState().UserStore.selectOptionsMidsWithoutGids;
|
const midOptionsWithoutGids = useStore.getState().UserStore.selectOptionsMidsWithoutGids;
|
||||||
|
|
||||||
@@ -46,7 +48,7 @@ export const LinkPaymentStep1 = ({ formData, setFormData }: LinkPaymentStep1Prop
|
|||||||
<>
|
<>
|
||||||
<div className="issue-form">
|
<div className="issue-form">
|
||||||
<div className="issue-row gap-10">
|
<div className="issue-row gap-10">
|
||||||
<div className="issue-label">가맹점</div>
|
<div className="issue-label">{t('filter.merchant')}</div>
|
||||||
<div className="issue-field">
|
<div className="issue-field">
|
||||||
<select
|
<select
|
||||||
className="wid-100"
|
className="wid-100"
|
||||||
@@ -66,7 +68,7 @@ export const LinkPaymentStep1 = ({ formData, setFormData }: LinkPaymentStep1Prop
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="issue-row gap-10">
|
<div className="issue-row gap-10">
|
||||||
<div className="issue-label">발송 수단</div>
|
<div className="issue-label">{t('additionalService.linkPayment.sendMethod')}</div>
|
||||||
<div className="issue-field">
|
<div className="issue-field">
|
||||||
<div className="chip-row">
|
<div className="chip-row">
|
||||||
<span
|
<span
|
||||||
@@ -79,20 +81,20 @@ export const LinkPaymentStep1 = ({ formData, setFormData }: LinkPaymentStep1Prop
|
|||||||
className={`keyword-tag flex-1 ${formData.sendMethod === 'EMAIL' ? 'active' : ''}`}
|
className={`keyword-tag flex-1 ${formData.sendMethod === 'EMAIL' ? 'active' : ''}`}
|
||||||
onClick={() => handlePaymentMethodChange(LinkPaymentSendMethod.EMAIL)}
|
onClick={() => handlePaymentMethodChange(LinkPaymentSendMethod.EMAIL)}
|
||||||
>
|
>
|
||||||
이메일
|
{t('common.email')}
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
className={`keyword-tag flex-1 ${formData.sendMethod === 'KAKAO' ? 'active' : ''}`}
|
className={`keyword-tag flex-1 ${formData.sendMethod === 'KAKAO' ? 'active' : ''}`}
|
||||||
onClick={() => handlePaymentMethodChange(LinkPaymentSendMethod.KAKAO)}
|
onClick={() => handlePaymentMethodChange(LinkPaymentSendMethod.KAKAO)}
|
||||||
>
|
>
|
||||||
카카오
|
{t('common.kakao')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="issue-row gap-10">
|
<div className="issue-row gap-10">
|
||||||
<div className="issue-label">상품명</div>
|
<div className="issue-label">{t('transaction.fields.productName')}</div>
|
||||||
<div className="issue-field">
|
<div className="issue-field">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
@@ -104,7 +106,7 @@ export const LinkPaymentStep1 = ({ formData, setFormData }: LinkPaymentStep1Prop
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="issue-row gap-10">
|
<div className="issue-row gap-10">
|
||||||
<div className="issue-label">상품가격</div>
|
<div className="issue-label">{t('additionalService.linkPayment.productPrice')}</div>
|
||||||
<div className="issue-field">
|
<div className="issue-field">
|
||||||
<NumericFormat
|
<NumericFormat
|
||||||
value={formData.amount}
|
value={formData.amount}
|
||||||
@@ -120,7 +122,7 @@ export const LinkPaymentStep1 = ({ formData, setFormData }: LinkPaymentStep1Prop
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="issue-row gap-10">
|
<div className="issue-row gap-10">
|
||||||
<div className="issue-label">상품 주문번호</div>
|
<div className="issue-label">{t('additionalService.linkPayment.productOrderNumber')}</div>
|
||||||
<div className="issue-field">
|
<div className="issue-field">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
@@ -132,16 +134,16 @@ export const LinkPaymentStep1 = ({ formData, setFormData }: LinkPaymentStep1Prop
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="issue-row gap-10">
|
<div className="issue-row gap-10">
|
||||||
<div className="issue-label">결제 유효일</div>
|
<div className="issue-label">{t('additionalService.linkPayment.paymentValidDate')}</div>
|
||||||
<div className="issue-field">
|
<div className="issue-field">
|
||||||
<div className="link-apply-date">
|
<div className="link-apply-date">
|
||||||
<SingleDatePicker
|
<SingleDatePicker
|
||||||
date={formData.paymentLimitDate}
|
date={formData.paymentLimitDate}
|
||||||
setDate={handleDateChange}
|
setDate={handleDateChange}
|
||||||
placeholder="날짜 선택"
|
placeholder={t('additionalService.linkPayment.selectDate')}
|
||||||
minDate={new Date()}
|
minDate={new Date()}
|
||||||
/>
|
/>
|
||||||
<span>까지</span>
|
<span>{t('additionalService.linkPayment.until')}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { ProcessStep } from "@/entities/transaction/model/types";
|
import { ProcessStep } from "@/entities/transaction/model/types";
|
||||||
import { useSetOnBack } from "@/widgets/sub-layout/use-sub-layout";
|
import { useSetOnBack } from "@/widgets/sub-layout/use-sub-layout";
|
||||||
import { IdentityType, Language } from '@/entities/additional-service/model/types'
|
import { IdentityType, Language } from '@/entities/additional-service/model/types'
|
||||||
@@ -15,6 +16,8 @@ export const LinkPaymentStep2 = ({
|
|||||||
formData,
|
formData,
|
||||||
setFormData
|
setFormData
|
||||||
}: LinkPaymentStep2Props) => {
|
}: LinkPaymentStep2Props) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
useSetOnBack(() => {
|
useSetOnBack(() => {
|
||||||
setProcessStep(ProcessStep.One);
|
setProcessStep(ProcessStep.One);
|
||||||
});
|
});
|
||||||
@@ -49,7 +52,7 @@ export const LinkPaymentStep2 = ({
|
|||||||
<>
|
<>
|
||||||
<div className="issue-form">
|
<div className="issue-form">
|
||||||
<div className="issue-row gap-10">
|
<div className="issue-row gap-10">
|
||||||
<div className="issue-label wid-105">구매자명</div>
|
<div className="issue-label wid-105">{t('transaction.fields.buyerName')}</div>
|
||||||
<div className="issue-field">
|
<div className="issue-field">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
@@ -62,7 +65,7 @@ export const LinkPaymentStep2 = ({
|
|||||||
|
|
||||||
{formData.sendMethod === 'EMAIL' &&
|
{formData.sendMethod === 'EMAIL' &&
|
||||||
<div className="issue-row gap-10">
|
<div className="issue-row gap-10">
|
||||||
<div className="issue-label wid-105">구매자 이메일</div>
|
<div className="issue-label wid-105">{t('additionalService.linkPayment.buyerEmail')}</div>
|
||||||
<div className="issue-field">
|
<div className="issue-field">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
@@ -76,7 +79,7 @@ export const LinkPaymentStep2 = ({
|
|||||||
|
|
||||||
{(formData.sendMethod === 'SMS' || formData.sendMethod === 'KAKAO') &&
|
{(formData.sendMethod === 'SMS' || formData.sendMethod === 'KAKAO') &&
|
||||||
<div className="issue-row gap-10">
|
<div className="issue-row gap-10">
|
||||||
<div className="issue-label wid-105">구매자<br />휴대폰 번호</div>
|
<div className="issue-label wid-105" dangerouslySetInnerHTML={{ __html: t('additionalService.linkPayment.buyerPhoneNumber') }}></div>
|
||||||
<div className="issue-field">
|
<div className="issue-field">
|
||||||
<input
|
<input
|
||||||
type="tel"
|
type="tel"
|
||||||
@@ -97,7 +100,7 @@ export const LinkPaymentStep2 = ({
|
|||||||
|
|
||||||
|
|
||||||
<div className="issue-row gap-10 beetween">
|
<div className="issue-row gap-10 beetween">
|
||||||
<div className="issue-label wid-105">구매자 정보 대조</div>
|
<div className="issue-label wid-105">{t('additionalService.linkPayment.buyerInfoVerification')}</div>
|
||||||
<label className="settings-switch">
|
<label className="settings-switch">
|
||||||
<input type="checkbox" checked={formData.isIdentity} onChange={(e) => handleIdentityToggle(e.target.checked)} />
|
<input type="checkbox" checked={formData.isIdentity} onChange={(e) => handleIdentityToggle(e.target.checked)} />
|
||||||
<span className="slider"></span>
|
<span className="slider"></span>
|
||||||
@@ -112,14 +115,14 @@ export const LinkPaymentStep2 = ({
|
|||||||
onClick={() => formData.isIdentity && handleIdendityTypeChange(IdentityType.INDIVIDUAL)}
|
onClick={() => formData.isIdentity && handleIdendityTypeChange(IdentityType.INDIVIDUAL)}
|
||||||
style={!formData.isIdentity ? { opacity: 0.5, cursor: 'not-allowed' } : {}}
|
style={!formData.isIdentity ? { opacity: 0.5, cursor: 'not-allowed' } : {}}
|
||||||
>
|
>
|
||||||
개인
|
{t('additionalService.linkPayment.individual')}
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
className={`keyword-tag flex-1 ${formData.identityType === IdentityType.CORPORATE ? 'active' : ''} ${!formData.isIdentity ? 'disabled' : ''}`}
|
className={`keyword-tag flex-1 ${formData.identityType === IdentityType.CORPORATE ? 'active' : ''} ${!formData.isIdentity ? 'disabled' : ''}`}
|
||||||
onClick={() => formData.isIdentity && handleIdendityTypeChange(IdentityType.CORPORATE)}
|
onClick={() => formData.isIdentity && handleIdendityTypeChange(IdentityType.CORPORATE)}
|
||||||
style={!formData.isIdentity ? { opacity: 0.5, cursor: 'not-allowed' } : {}}
|
style={!formData.isIdentity ? { opacity: 0.5, cursor: 'not-allowed' } : {}}
|
||||||
>
|
>
|
||||||
법인
|
{t('additionalService.linkPayment.corporate')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -131,7 +134,7 @@ export const LinkPaymentStep2 = ({
|
|||||||
{formData.identityType === IdentityType.CORPORATE ? (
|
{formData.identityType === IdentityType.CORPORATE ? (
|
||||||
<PatternFormat
|
<PatternFormat
|
||||||
format="##########"
|
format="##########"
|
||||||
placeholder="사업자번호 10자리"
|
placeholder={t('additionalService.linkPayment.businessNumber10Digits')}
|
||||||
value={formData.identityValue}
|
value={formData.identityValue}
|
||||||
valueIsNumericString
|
valueIsNumericString
|
||||||
onValueChange={(values) => {
|
onValueChange={(values) => {
|
||||||
@@ -143,7 +146,7 @@ export const LinkPaymentStep2 = ({
|
|||||||
) : (
|
) : (
|
||||||
<PatternFormat
|
<PatternFormat
|
||||||
format="######"
|
format="######"
|
||||||
placeholder="생년월일 6자리"
|
placeholder={t('additionalService.linkPayment.birthDate6Digits')}
|
||||||
value={formData.identityValue}
|
value={formData.identityValue}
|
||||||
valueIsNumericString
|
valueIsNumericString
|
||||||
onValueChange={(values) => {
|
onValueChange={(values) => {
|
||||||
@@ -157,39 +160,39 @@ export const LinkPaymentStep2 = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="issue-row gap-10">
|
<div className="issue-row gap-10">
|
||||||
<div className="issue-label wid-105">언어</div>
|
<div className="issue-label wid-105">{t('additionalService.linkPayment.language')}</div>
|
||||||
<div className="issue-field">
|
<div className="issue-field">
|
||||||
<div className="chip-row">
|
<div className="chip-row">
|
||||||
<span
|
<span
|
||||||
className={`keyword-tag flex-1 ${formData.language === Language.KR ? 'active' : ''}`}
|
className={`keyword-tag flex-1 ${formData.language === Language.KR ? 'active' : ''}`}
|
||||||
onClick={() => handleLanguageType(Language.KR)}
|
onClick={() => handleLanguageType(Language.KR)}
|
||||||
>
|
>
|
||||||
국문
|
{t('additionalService.linkPayment.korean')}
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
className={`keyword-tag flex-1 ${formData.language === Language.EN ? 'active' : ''}`}
|
className={`keyword-tag flex-1 ${formData.language === Language.EN ? 'active' : ''}`}
|
||||||
onClick={() => handleLanguageType(Language.EN)}
|
onClick={() => handleLanguageType(Language.EN)}
|
||||||
>
|
>
|
||||||
영문
|
{t('additionalService.linkPayment.english')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="issue-row gap-10">
|
<div className="issue-row gap-10">
|
||||||
<div className="issue-label wid-105">링크내용</div>
|
<div className="issue-label wid-105">{t('additionalService.linkPayment.linkContent')}</div>
|
||||||
<div className="issue-field">
|
<div className="issue-field">
|
||||||
<div className="chip-row">
|
<div className="chip-row">
|
||||||
<span
|
<span
|
||||||
className={`keyword-tag flex-1 ${formData.linkContentType === LinkContentType.BASIC ? 'active' : ''}`}
|
className={`keyword-tag flex-1 ${formData.linkContentType === LinkContentType.BASIC ? 'active' : ''}`}
|
||||||
onClick={() => handleLinkContent(LinkContentType.BASIC)}
|
onClick={() => handleLinkContent(LinkContentType.BASIC)}
|
||||||
>
|
>
|
||||||
기본
|
{t('additionalService.linkPayment.basic')}
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
className={`keyword-tag flex-1 ${formData.linkContentType === LinkContentType.ADDITIONAL ? 'active' : ''}`}
|
className={`keyword-tag flex-1 ${formData.linkContentType === LinkContentType.ADDITIONAL ? 'active' : ''}`}
|
||||||
onClick={() => handleLinkContent(LinkContentType.ADDITIONAL)}
|
onClick={() => handleLinkContent(LinkContentType.ADDITIONAL)}
|
||||||
>
|
>
|
||||||
추가
|
{t('additionalService.linkPayment.additional')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1071,7 +1071,25 @@
|
|||||||
"linkBreakFailed": "Failed to break link. Please check individual status.",
|
"linkBreakFailed": "Failed to break link. Please check individual status.",
|
||||||
"linkBreakFailedGeneric": "Failed to break link.",
|
"linkBreakFailedGeneric": "Failed to break link.",
|
||||||
"pleaseRetry": "Please try again",
|
"pleaseRetry": "Please try again",
|
||||||
"resendSuccess": "Resend successful.",
|
"sendMethod": "Send Method",
|
||||||
|
"productPrice": "Product Price",
|
||||||
|
"productOrderNumber": "Product Order Number",
|
||||||
|
"paymentValidDate": "Payment Valid Date",
|
||||||
|
"until": "Until",
|
||||||
|
"selectDate": "Select Date",
|
||||||
|
"buyerEmail": "Buyer Email",
|
||||||
|
"buyerPhoneNumber": "Buyer\nPhone Number",
|
||||||
|
"buyerInfoVerification": "Buyer Info Verification",
|
||||||
|
"individual": "Individual",
|
||||||
|
"corporate": "Corporate",
|
||||||
|
"businessNumber10Digits": "Business Number (10 digits)",
|
||||||
|
"birthDate6Digits": "Birth Date (6 digits)",
|
||||||
|
"language": "Language",
|
||||||
|
"korean": "Korean",
|
||||||
|
"english": "English",
|
||||||
|
"linkContent": "Link Content",
|
||||||
|
"basic": "Basic",
|
||||||
|
"additional": "Additional",
|
||||||
"resendFailed": "Resend failed.",
|
"resendFailed": "Resend failed.",
|
||||||
"resendError": "An error occurred during resend.",
|
"resendError": "An error occurred during resend.",
|
||||||
"resendConfirm": "Do you want to resend?",
|
"resendConfirm": "Do you want to resend?",
|
||||||
|
|||||||
@@ -1071,7 +1071,25 @@
|
|||||||
"linkBreakFailed": "링크중단 요청에 실패했습니다. 개별 상태를 확인해주세요.",
|
"linkBreakFailed": "링크중단 요청에 실패했습니다. 개별 상태를 확인해주세요.",
|
||||||
"linkBreakFailedGeneric": "링크중단 요청에 실패했습니다.",
|
"linkBreakFailedGeneric": "링크중단 요청에 실패했습니다.",
|
||||||
"pleaseRetry": "다시 시도해 주세요",
|
"pleaseRetry": "다시 시도해 주세요",
|
||||||
"resendSuccess": "재발송을 성공하였습니다.",
|
"sendMethod": "발송 수단",
|
||||||
|
"productPrice": "상품가격",
|
||||||
|
"productOrderNumber": "상품 주문번호",
|
||||||
|
"paymentValidDate": "결제 유효일",
|
||||||
|
"until": "까지",
|
||||||
|
"selectDate": "날짜 선택",
|
||||||
|
"buyerEmail": "구매자 이메일",
|
||||||
|
"buyerPhoneNumber": "구매자\n휴대폰 번호",
|
||||||
|
"buyerInfoVerification": "구매자 정보 대조",
|
||||||
|
"individual": "개인",
|
||||||
|
"corporate": "법인",
|
||||||
|
"businessNumber10Digits": "사업자번호 10자리",
|
||||||
|
"birthDate6Digits": "생년월일 6자리",
|
||||||
|
"language": "언어",
|
||||||
|
"korean": "국문",
|
||||||
|
"english": "영문",
|
||||||
|
"linkContent": "링크내용",
|
||||||
|
"basic": "기본",
|
||||||
|
"additional": "추가",
|
||||||
"resendFailed": "재발송을 실패하였습니다.",
|
"resendFailed": "재발송을 실패하였습니다.",
|
||||||
"resendError": "재발송 중 오류가 발생했습니다.",
|
"resendError": "재발송 중 오류가 발생했습니다.",
|
||||||
"resendConfirm": "재발송 하시겠습니까?",
|
"resendConfirm": "재발송 하시겠습니까?",
|
||||||
|
|||||||
Reference in New Issue
Block a user