부가 서비스 : 링크 결제 페이지
This commit is contained in:
136
src/entities/additional-service/ui/link-payment-step1.tsx
Normal file
136
src/entities/additional-service/ui/link-payment-step1.tsx
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import { PATHS } from '@/shared/constants/paths';
|
||||||
|
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
||||||
|
import { useSetOnBack } from '@/widgets/sub-layout/use-sub-layout';
|
||||||
|
import { IMAGE_ROOT } from '@/shared/constants/common';
|
||||||
|
|
||||||
|
export const LinkPaymentStep1 = () => {
|
||||||
|
const { navigate } = useNavigate();
|
||||||
|
|
||||||
|
useSetOnBack(() => {
|
||||||
|
navigate(PATHS.additionalService.intro);
|
||||||
|
});
|
||||||
|
const [selectedPaymentMethod, setSelectedPaymentMethod] = useState('SMS');
|
||||||
|
const [formData, setFormData] = useState({
|
||||||
|
merchant: 'nictest001m',
|
||||||
|
productName: '',
|
||||||
|
productPrice: '',
|
||||||
|
orderNumber: '',
|
||||||
|
validDate: '2025.06.30'
|
||||||
|
});
|
||||||
|
|
||||||
|
const handlePaymentMethodChange = (method: string) => {
|
||||||
|
setSelectedPaymentMethod(method);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInputChange = (field: string, value: string) => {
|
||||||
|
setFormData(prev => ({
|
||||||
|
...prev,
|
||||||
|
[field]: value
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="issue-form">
|
||||||
|
<div className="issue-row gap-10">
|
||||||
|
<div className="issue-label">가맹점</div>
|
||||||
|
<div className="issue-field">
|
||||||
|
<select
|
||||||
|
className="wid-100"
|
||||||
|
value={formData.merchant}
|
||||||
|
onChange={(e) => handleInputChange('merchant', e.target.value)}
|
||||||
|
>
|
||||||
|
<option>nictest001m</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="issue-row gap-10">
|
||||||
|
<div className="issue-label">발송 수단</div>
|
||||||
|
<div className="issue-field">
|
||||||
|
<div className="chip-row">
|
||||||
|
<span
|
||||||
|
className={`keyword-tag flex-1 ${selectedPaymentMethod === 'SMS' ? 'active' : ''}`}
|
||||||
|
onClick={() => handlePaymentMethodChange('SMS')}
|
||||||
|
>
|
||||||
|
SMS
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className={`keyword-tag flex-1 ${selectedPaymentMethod === '이메일' ? 'active' : ''}`}
|
||||||
|
onClick={() => handlePaymentMethodChange('이메일')}
|
||||||
|
>
|
||||||
|
이메일
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className={`keyword-tag flex-1 ${selectedPaymentMethod === '카카오' ? 'active' : ''}`}
|
||||||
|
onClick={() => handlePaymentMethodChange('카카오')}
|
||||||
|
>
|
||||||
|
카카오
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="issue-row gap-10">
|
||||||
|
<div className="issue-label">상품명</div>
|
||||||
|
<div className="issue-field">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder=""
|
||||||
|
value={formData.productName}
|
||||||
|
onChange={(e) => handleInputChange('productName', e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="issue-row gap-10">
|
||||||
|
<div className="issue-label">상품가격</div>
|
||||||
|
<div className="issue-field">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder=""
|
||||||
|
value={formData.productPrice}
|
||||||
|
onChange={(e) => handleInputChange('productPrice', e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="issue-row gap-10">
|
||||||
|
<div className="issue-label">상품 주문번호</div>
|
||||||
|
<div className="issue-field">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder=""
|
||||||
|
value={formData.orderNumber}
|
||||||
|
onChange={(e) => handleInputChange('orderNumber', e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="issue-row gap-10">
|
||||||
|
<div className="issue-label">결제 유효일</div>
|
||||||
|
<div className="issue-field">
|
||||||
|
<div className="link-apply-date">
|
||||||
|
<div className="input-wrapper date">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={formData.validDate}
|
||||||
|
className="date-input"
|
||||||
|
onChange={(e) => handleInputChange('validDate', e.target.value)}
|
||||||
|
/>
|
||||||
|
<button type="button" className="date-btn">
|
||||||
|
<img
|
||||||
|
src={IMAGE_ROOT + '/ico_date.svg'}
|
||||||
|
alt="날짜 선택"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<span>까지</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
164
src/entities/additional-service/ui/link-payment-step2.tsx
Normal file
164
src/entities/additional-service/ui/link-payment-step2.tsx
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
import {ProcessStep} from "@/entities/transaction/model/types";
|
||||||
|
import {useSetOnBack} from "@/widgets/sub-layout/use-sub-layout";
|
||||||
|
import {useState} from "react";
|
||||||
|
|
||||||
|
export interface LinkPaymentStep2Props {
|
||||||
|
setProcessStep: ((processStep: ProcessStep) => void);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LinkPaymentStep2 = ({
|
||||||
|
setProcessStep
|
||||||
|
}: LinkPaymentStep2Props) => {
|
||||||
|
useSetOnBack(() => {
|
||||||
|
setProcessStep(ProcessStep.One);
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleInputChange = (field: string, value: string) => {
|
||||||
|
setFormData(prev => ({
|
||||||
|
...prev,
|
||||||
|
[field]: value
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const [selectedPurchaserType, setSelectedPurchaserType] = useState('개인');
|
||||||
|
const [selectedLanguage, setSelectedLanguage] = useState('국문')
|
||||||
|
const [selectedLinkContent, setSelectedLinkContent] = useState('기본');
|
||||||
|
const [formData, setFormData] = useState({
|
||||||
|
purchaser: '',
|
||||||
|
purchaserEmail: '',
|
||||||
|
purchaserPhone: '',
|
||||||
|
purchaserBirth: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
const handlePurchaserTypeChange = (type: string) => {
|
||||||
|
setSelectedPurchaserType(type)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleLanguageType = (type: string) => {
|
||||||
|
setSelectedLanguage(type)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleLinkContent = (content: string) => {
|
||||||
|
setSelectedLinkContent(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="issue-form">
|
||||||
|
<div className="issue-row gap-10">
|
||||||
|
<div className="issue-label wid-105">구매자명</div>
|
||||||
|
<div className="issue-field">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder=""
|
||||||
|
value={formData.purchaser}
|
||||||
|
onChange={(e) => handleInputChange('purchaser', e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="issue-row gap-10">
|
||||||
|
<div className="issue-label wid-105">구매자 이메일</div>
|
||||||
|
<div className="issue-field">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="test@nicepay.co.kr"
|
||||||
|
value={formData.purchaserEmail}
|
||||||
|
onChange={(e) => handleInputChange('purchaserEmail', e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="issue-row gap-10">
|
||||||
|
<div className="issue-label wid-105">구매자<br/>휴대폰 번호</div>
|
||||||
|
<div className="issue-field">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="01012345678"
|
||||||
|
value={formData.purchaserPhone}
|
||||||
|
onChange={(e) => handleInputChange('purchaserPhone', e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="issue-row gap-10 beetween">
|
||||||
|
<div className="issue-label wid-105">구매자 정보 대조</div>
|
||||||
|
<label className="settings-switch">
|
||||||
|
<input type="checkbox"/>
|
||||||
|
<span className="slider"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div className="issue-row gap-10">
|
||||||
|
<div className="issue-label wid-105"></div>
|
||||||
|
<div className="issue-field">
|
||||||
|
<div className="chip-row">
|
||||||
|
<span
|
||||||
|
className={`keyword-tag flex-1 ${selectedPurchaserType === '개인' ? 'active' : ''}`}
|
||||||
|
onClick={() => handlePurchaserTypeChange('개인')}
|
||||||
|
>
|
||||||
|
개인
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className={`keyword-tag flex-1 ${selectedPurchaserType === '법인' ? 'active' : ''}`}
|
||||||
|
onClick={() => handlePurchaserTypeChange('법인')}
|
||||||
|
>
|
||||||
|
법인
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="issue-row gap-10">
|
||||||
|
<div className="issue-label wid-105"></div>
|
||||||
|
<div className='issue-field'>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="생년월일 6자리"
|
||||||
|
value={formData.purchaserBirth}
|
||||||
|
onChange={(e) => handleInputChange('purchaserPhone', e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="issue-row gap-10">
|
||||||
|
<div className="issue-label wid-105">언어</div>
|
||||||
|
<div className="issue-field">
|
||||||
|
<div className="chip-row">
|
||||||
|
<span
|
||||||
|
className={`keyword-tag flex-1 ${selectedLanguage === '국문' ? 'active' : ''}`}
|
||||||
|
onClick={() => handleLanguageType('국문')}
|
||||||
|
>
|
||||||
|
국문
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className={`keyword-tag flex-1 ${selectedLanguage === '영문' ? 'active' : ''}`}
|
||||||
|
onClick={() => handleLanguageType('영문')}
|
||||||
|
>
|
||||||
|
영문
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="issue-row gap-10">
|
||||||
|
<div className="issue-label wid-105">링크내용</div>
|
||||||
|
<div className="issue-field">
|
||||||
|
<div className="chip-row">
|
||||||
|
<span
|
||||||
|
className={`keyword-tag flex-1 ${selectedLinkContent === '기본' ? 'active' : ''}`}
|
||||||
|
onClick={() => handleLinkContent('기본')}
|
||||||
|
>
|
||||||
|
기본
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className={`keyword-tag flex-1 ${selectedLinkContent === '추가' ? 'active' : ''}`}
|
||||||
|
onClick={() => handleLinkContent('추가')}
|
||||||
|
>
|
||||||
|
추가
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,18 +1,85 @@
|
|||||||
import { HeaderType } from '@/entities/common/model/types';
|
import {useState} from 'react';
|
||||||
import {
|
import {LinkPaymentStep1} from '@/entities/additional-service/ui/link-payment-step1';
|
||||||
useSetHeaderTitle,
|
import {LinkPaymentStep2} from '@/entities/additional-service/ui/link-payment-step2';
|
||||||
useSetHeaderType,
|
import {HeaderType} from '@/entities/common/model/types';
|
||||||
useSetFooterMode
|
import {ProcessStep} from '@/entities/transaction/model/types';
|
||||||
} from '@/widgets/sub-layout/use-sub-layout';
|
import {useSetFooterMode, useSetHeaderTitle, useSetHeaderType} from '@/widgets/sub-layout/use-sub-layout';
|
||||||
|
import {useNavigate} from '@/shared/lib/hooks/use-navigate';
|
||||||
|
import {PATHS} from "@/shared/constants/paths";
|
||||||
|
|
||||||
export const LinkPaymentPage = () => {
|
export const LinkPaymentPage = () => {
|
||||||
useSetHeaderTitle('링크결제');
|
const { navigate } = useNavigate();
|
||||||
|
const [processStep, setProcessStep] = useState<ProcessStep>(ProcessStep.One);
|
||||||
|
|
||||||
|
useSetHeaderTitle('링크결제 신청');
|
||||||
useSetHeaderType(HeaderType.LeftArrow);
|
useSetHeaderType(HeaderType.LeftArrow);
|
||||||
useSetFooterMode(true);
|
useSetFooterMode(false);
|
||||||
|
|
||||||
|
const onClickToChangeTab = () => {
|
||||||
|
if(processStep === ProcessStep.One) {
|
||||||
|
setProcessStep(ProcessStep.Two);
|
||||||
|
}
|
||||||
|
else if(processStep === ProcessStep.Two) {
|
||||||
|
alert('완료')
|
||||||
|
navigate(PATHS.home)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<main>
|
||||||
|
<div className="tab-content">
|
||||||
|
<div className="tab-pane sub active">
|
||||||
|
<div className="option-list">
|
||||||
|
<div className="issue-progress">
|
||||||
|
<div className="bar">
|
||||||
|
{(processStep === ProcessStep.One) &&
|
||||||
|
<div
|
||||||
|
className="fill"
|
||||||
|
style={{ width: '50%' }}
|
||||||
|
></div>
|
||||||
|
}
|
||||||
|
{(processStep === ProcessStep.Two) &&
|
||||||
|
<div
|
||||||
|
className="fill"
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
></div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{(processStep === ProcessStep.One) &&
|
||||||
|
<LinkPaymentStep1 ></LinkPaymentStep1>
|
||||||
|
}
|
||||||
|
{ (processStep === ProcessStep.Two) &&
|
||||||
|
<LinkPaymentStep2
|
||||||
|
setProcessStep={ setProcessStep }
|
||||||
|
></LinkPaymentStep2>
|
||||||
|
}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{(processStep === ProcessStep.One) &&
|
||||||
|
<div className="apply-row">
|
||||||
|
<button
|
||||||
|
className="btn-50 btn-blue flex-1"
|
||||||
|
onClick={() => onClickToChangeTab() }
|
||||||
|
>다음</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
{(processStep === ProcessStep.Two) &&
|
||||||
|
<div className="apply-row two-button">
|
||||||
|
<button
|
||||||
|
className="btn-50 btn-darkgray flex-1">
|
||||||
|
이전</button>
|
||||||
|
<button
|
||||||
|
className="btn-50 btn-blue flex-3"
|
||||||
|
onClick={() => onClickToChangeTab() }
|
||||||
|
>결제 신청</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -1,15 +1,11 @@
|
|||||||
import { useState } from 'react';
|
import {useState} from 'react';
|
||||||
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 { CashReceitHandWrittenIssuanceStep1 } from '@/entities/transaction/ui/cash-receit-hand-written-issuance-step1';
|
import {CashReceitHandWrittenIssuanceStep1} from '@/entities/transaction/ui/cash-receit-hand-written-issuance-step1';
|
||||||
import { CashReceitHandWrittenIssuanceStep2 } from '@/entities/transaction/ui/cash-receit-hand-written-issuance-step2';
|
import {CashReceitHandWrittenIssuanceStep2} from '@/entities/transaction/ui/cash-receit-hand-written-issuance-step2';
|
||||||
import { ProcessStep } from '@/entities/transaction/model/types';
|
import {ProcessStep} from '@/entities/transaction/model/types';
|
||||||
import { HeaderType } from '@/entities/common/model/types';
|
import {HeaderType} from '@/entities/common/model/types';
|
||||||
import {
|
import {useSetFooterMode, useSetHeaderTitle, useSetHeaderType} from '@/widgets/sub-layout/use-sub-layout';
|
||||||
useSetHeaderTitle,
|
|
||||||
useSetHeaderType,
|
|
||||||
useSetFooterMode
|
|
||||||
} from '@/widgets/sub-layout/use-sub-layout';
|
|
||||||
|
|
||||||
export const CashReceitHandWrittenIssuancePage = () => {
|
export const CashReceitHandWrittenIssuancePage = () => {
|
||||||
const { navigate } = useNavigate();
|
const { navigate } = useNavigate();
|
||||||
@@ -40,10 +36,18 @@ export const CashReceitHandWrittenIssuancePage = () => {
|
|||||||
<div className="option-list">
|
<div className="option-list">
|
||||||
<div className="issue-progress">
|
<div className="issue-progress">
|
||||||
<div className="bar">
|
<div className="bar">
|
||||||
<div
|
{(processStep === ProcessStep.One) &&
|
||||||
className="fill"
|
<div
|
||||||
style={{ width: '50%' }}
|
className="fill"
|
||||||
></div>
|
style={{ width: '50%' }}
|
||||||
|
></div>
|
||||||
|
}
|
||||||
|
{(processStep === ProcessStep.Two) &&
|
||||||
|
<div
|
||||||
|
className="fill"
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
></div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
{ (processStep === ProcessStep.One) &&
|
{ (processStep === ProcessStep.One) &&
|
||||||
<CashReceitHandWrittenIssuanceStep1></CashReceitHandWrittenIssuanceStep1>
|
<CashReceitHandWrittenIssuanceStep1></CashReceitHandWrittenIssuanceStep1>
|
||||||
|
|||||||
Reference in New Issue
Block a user