Skip to content

Commit

Permalink
Merge pull request #49 from Spaces-Place/dusqo
Browse files Browse the repository at this point in the history
카카오결제 팝업 > 페이지로 변경
  • Loading branch information
KangYeonbae authored Dec 4, 2024
2 parents 03a1bc4 + d5e0388 commit 8a707eb
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 189 deletions.
31 changes: 4 additions & 27 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import SearchResults from './pages/searchResults';
import NotFound from './pages/notFound';
import Contact from './pages/contact';
import Settings from './pages/Settings';
import PaymentApproval from './pages/PaymentApproval';
import PaymentResult from './pages/PaymentResult';

// 컨텍스트 및 상수
import { AuthContext } from './utils/AuthContext';
Expand All @@ -35,7 +35,6 @@ import ScrollToTop from './components/ScrollToTop';
import LoadingSpinner from './components/LoadingSpinner';
import SearchBar from './components/SearchBar';
import ThemeToggle from './components/ThemeToggle';
import PaymentResult from './pages/PaymentResult';

// 보호된 라우트 컴포넌트
const PrivateRoute = ({ children, requiredRole }) => {
Expand Down Expand Up @@ -195,7 +194,8 @@ function App() {
<Route path="/contact" element={<Contact />} />
<Route path="/mappage" element={<MyMapPage />} />
<Route path="/search" element={<SearchResults query={searchQuery} />} />
<Route path="/payments/kakao/approval" element={<PaymentApproval />} />
<Route path="/booking" element={<Booking />} />
<Route path="booking/success" element={<PaymentResult />} />

{/* 공간 관련 라우트 */}
{ItemType.map(({type}) => (
Expand All @@ -216,32 +216,9 @@ function App() {
<OwnerMypage />
</PrivateRoute>
} />
<Route path="/booking" element={
<PrivateRoute>
<Booking />
</PrivateRoute>
} />

<Route path="/settings" element={
<PrivateRoute>
<Settings />
</PrivateRoute>
} />

{/* 결제 결과 처리 라우트 */}
<Route path="/payment/success" element={
<PrivateRoute>
<PaymentResult type="success" />
</PrivateRoute>
} />
<Route path="/payment/cancel" element={
<PrivateRoute>
<PaymentResult type="cancel" />
</PrivateRoute>
} />
<Route path="/payment/fail" element={
<PrivateRoute>
<PaymentResult type="fail" />
</PrivateRoute>
} />

{/* 404 페이지 */}
Expand Down
35 changes: 0 additions & 35 deletions src/pages/PaymentApproval.js

This file was deleted.

73 changes: 36 additions & 37 deletions src/pages/PaymentResult.js
Original file line number Diff line number Diff line change
@@ -1,46 +1,45 @@
// PaymentResult.js
import { useEffect, useState } from 'react';
import { useSearchParams, useNavigate } from 'react-router-dom';
import { handlePaymentResult } from '../utils/paymentService';
import "../styles/booking.css"

// PaymentResult.js
export default function PaymentResult() {
const [searchParams] = useSearchParams();
const navigate = useNavigate();
const [status, setStatus] = useState('결제 처리중...');
const [searchParams] = useSearchParams();
const navigate = useNavigate();
const [status, setStatus] = useState('결제 처리중...');

useEffect(() => {
const processPaymentResult = async () => {
try {
const result = await handlePaymentResult(searchParams);
setStatus('결제가 완료되었습니다.');

// 결제 성공 시 4단계로 이동
setTimeout(() => {
navigate('/booking', {
state: {
paymentSuccess: true,
orderNumber: searchParams.get('order_number')
}
});
}, 3000);
} catch (error) {
setStatus('결제 처리 중 오류가 발생했습니다.');
setTimeout(() => {
navigate('/booking');
}, 3000);
}
};
useEffect(() => {
const processPayment = async () => {
const orderNumber = searchParams.get('order_number');
const pgToken = searchParams.get('pg_token');

processPaymentResult();
}, [searchParams, navigate]);
if (orderNumber && pgToken) {
try {
const result = await handlePaymentResult(searchParams);
if (result) {
setStatus('결제가 완료되었습니다.');
setTimeout(() => {
navigate('/booking', {
state: { paymentSuccess: true }
});
}, 1500);
}
} catch (error) {
setStatus('결제 처리 중 오류가 발생했습니다.');
setTimeout(() => navigate('/booking'), 2000);
}
}
};

return (
<div className="booking_payment-result">
<h2 className="booking_payment-title">결제 처리 결과</h2>
<p className="booking_payment-status">{status}</p>
<p className="booking_payment-redirect">
잠시 후 자동으로 이동합니다...
</p>
</div>
);
}
processPayment();
}, [searchParams, navigate]);

return (
<div className="booking_payment-result">
<h2 className="booking_payment-title">결제 처리 결과</h2>
<p className="booking_payment-status">{status}</p>
</div>
);
}
134 changes: 44 additions & 90 deletions src/pages/booking.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,104 +40,58 @@ export default function BookingForm() {
}
};

// BookingForm.js
const handleSubmit = async (e) => {
e.preventDefault();

if (step < 3) {
setStep(prev => prev + 1);
}
else if (step === 3) {
if (!bookingData.agreement) {
alert('예약 정책에 동의해주세요.');
return;
}

try {
setPaymentProcessing(true);
if (bookingData.paymentMethod === 'kakao') {
const paymentData = usageUnit === 'DAY'
? {
date: bookingData.date,
user_name: bookingData.name,
phone: bookingData.phone,
email: bookingData.email
}
: {
start_time: bookingData.start_time,
end_time: bookingData.end_time,
user_name: bookingData.name,
phone: bookingData.phone,
email: bookingData.email
};

const response = await initiateKakaoPayment(
paymentData,
totalPrice,
bookingInfo.spaceId
);

if (response.next_redirect_pc_url) {
// 카카오페이 결제창 팝업으로 열기
const width = 450;
const height = 650;
const left = window.screen.width / 2 - width / 2;
const top = window.screen.height / 2 - height / 2;

// 결제 완료 후 처리를 위한 메시지 리스너
const handleMessage = async (e) => {
if (e.data.type === 'KAKAO_PAYMENT_SUCCESS') {
const approvalUrl = e.data.url;
const urlParams = new URLSearchParams(new URL(approvalUrl).search);
const orderNumber = urlParams.get('order_number');
const pgToken = urlParams.get('pg_token');

const result = await handlePaymentApproval(orderNumber, pgToken);
if (result.success) {
setStep(4); // 결제 성공 시 step 4로 이동

const handleSubmit = async (e) => {
e.preventDefault();

if (step < 3) {
setStep(prev => prev + 1);
}
else if (step === 3) {
if (!bookingData.agreement) {
alert('예약 정책에 동의해주세요.');
return;
}

try {
setPaymentProcessing(true);
if (bookingData.paymentMethod === 'kakao') {
const paymentData = usageUnit === 'DAY'
? {
date: bookingData.date,
user_name: bookingData.name,
phone: bookingData.phone,
email: bookingData.email
}
}
};

window.addEventListener('message', handleMessage);

const popup = window.open(
response.next_redirect_pc_url,
'KakaoPay',
`width=${width},height=${height},left=${left},top=${top}`
: {
start_time: bookingData.start_time,
end_time: bookingData.end_time,
user_name: bookingData.name,
phone: bookingData.phone,
email: bookingData.email
};

const response = await initiateKakaoPayment(
paymentData,
totalPrice,
bookingInfo.spaceId
);

// 팝업 닫힘 감지
const checkPopupClosed = setInterval(() => {
if (popup.closed) {
clearInterval(checkPopupClosed);
window.removeEventListener('message', handleMessage);
setPaymentProcessing(false);
}
}, 500);

if (response.next_redirect_pc_url) {
// 팝업 대신 현재 창에서 리다이렉트
window.location.href = response.next_redirect_pc_url;
}
}
} catch (error) {
alert('결제 처리 중 오류가 발생했습니다.');
console.error('Payment error:', error);
setPaymentProcessing(false);
}
} catch (error) {
alert('결제 처리 중 오류가 발생했습니다.');
console.error('Payment error:', error);
setPaymentProcessing(false);
}
}
};



// 결제 상태 확인 함수
const checkPaymentStatus = async (tid) => {
try {
const response = await fetch(`/api/payments/status/${tid}`);
const data = await response.json();
return data;
} catch (error) {
throw new Error('Payment status check failed');
}
};


useEffect(() => {
const paymentSuccess = location.state?.paymentSuccess;
if (paymentSuccess) {
Expand Down

0 comments on commit 8a707eb

Please sign in to comment.