불필요 파일 제거
This commit is contained in:
@@ -1,527 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import { appBridge } from '../utils/appBridge';
|
||||
import { LanguageSwitcher } from '../components';
|
||||
import { SearchFilter } from '../types/filter';
|
||||
|
||||
interface TestResult {
|
||||
method: string;
|
||||
success: boolean;
|
||||
result?: any;
|
||||
error?: string;
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
const Test: React.FC = () => {
|
||||
const [results, setResults] = useState<TestResult[]>([]);
|
||||
const [isLoading, setIsLoading] = useState<string | null>(null);
|
||||
const [messageCount, setMessageCount] = useState<number>(0);
|
||||
const [searchData, setSearchData] = useState<Array<{
|
||||
id: string;
|
||||
type: string;
|
||||
amount: number;
|
||||
date: Date;
|
||||
status: string;
|
||||
description: string;
|
||||
}>>([]);
|
||||
|
||||
const addResult = (method: string, success: boolean, result?: any, error?: string) => {
|
||||
const newResult: TestResult = {
|
||||
method,
|
||||
success,
|
||||
result,
|
||||
error,
|
||||
timestamp: new Date().toLocaleTimeString()
|
||||
};
|
||||
setResults(prev => [newResult, ...prev]);
|
||||
};
|
||||
|
||||
const executeTest = async (method: string, testFn: () => Promise<any>) => {
|
||||
setIsLoading(method);
|
||||
try {
|
||||
const result = await testFn();
|
||||
addResult(method, true, result);
|
||||
} catch (error) {
|
||||
addResult(method, false, undefined, error instanceof Error ? error.message : String(error));
|
||||
} finally {
|
||||
setIsLoading(null);
|
||||
}
|
||||
};
|
||||
|
||||
const clearResults = () => {
|
||||
setResults([]);
|
||||
};
|
||||
|
||||
// 앱 정보 테스트
|
||||
const testGetAppInfo = () => executeTest('getAppInfo', () => appBridge.getAppInfo());
|
||||
const testGetDeviceInfo = () => executeTest('getDeviceInfo', () => appBridge.getDeviceInfo());
|
||||
|
||||
// 네비게이션 테스트
|
||||
const testNavigateBack = () => executeTest('navigateBack', () => appBridge.navigateBack());
|
||||
const testNavigateTo = () => executeTest('navigateTo', () => appBridge.navigateTo('/home'));
|
||||
const testCloseWebView = () => executeTest('closeWebView', () => appBridge.closeWebView());
|
||||
const testNavigateToLogin = () => executeTest('navigateToLogin', () => appBridge.navigateToLogin());
|
||||
|
||||
// 알림 테스트
|
||||
const testShowToast = () => executeTest('showToast', () => appBridge.showToast('테스트 토스트 메시지', 3000));
|
||||
const testShowAlert = () => executeTest('showAlert', () => appBridge.showAlert('테스트 알림', '이것은 테스트 알림입니다.'));
|
||||
const testShowConfirm = () => executeTest('showConfirm', () => appBridge.showConfirm('확인', '계속하시겠습니까?'));
|
||||
|
||||
// 저장소 테스트
|
||||
const testSetStorage = () => executeTest('setStorage', () => appBridge.setStorage('test_key', { message: '테스트 데이터', timestamp: new Date().toISOString() }));
|
||||
const testGetStorage = () => executeTest('getStorage', () => appBridge.getStorage('test_key'));
|
||||
const testRemoveStorage = () => executeTest('removeStorage', () => appBridge.removeStorage('test_key'));
|
||||
|
||||
// 공유 테스트
|
||||
const testShareContent = () => executeTest('shareContent', () => appBridge.shareContent({
|
||||
title: '테스트 공유',
|
||||
text: '이것은 테스트 공유 내용입니다.',
|
||||
url: 'https://nicepayments.com'
|
||||
}));
|
||||
|
||||
// 인증 테스트
|
||||
const testLogin = () => executeTest('login', () => appBridge.login({ email: 'test@example.com', password: 'test123' }));
|
||||
const testLogout = () => executeTest('logout', () => appBridge.logout());
|
||||
|
||||
// 안전한 호출 테스트
|
||||
const testSafeCall = () => executeTest('safeCall', () => appBridge.safeCall(
|
||||
() => appBridge.getAppInfo(),
|
||||
{ version: 'fallback', buildNumber: 'fallback' },
|
||||
(error) => console.error('Safe call error:', error)
|
||||
));
|
||||
|
||||
// 타임아웃 테스트
|
||||
const testCallWithTimeout = () => executeTest('callWithTimeout', () => appBridge.callWithTimeout(
|
||||
() => appBridge.getDeviceInfo(),
|
||||
2000
|
||||
));
|
||||
|
||||
// 메시지 카운트 업데이트 테스트
|
||||
const testUpdateMessageCount = () => executeTest('updateMessageCount', () => appBridge.updateMessageCount(messageCount));
|
||||
|
||||
// 조회조건 변경 핸들러
|
||||
const handleFilterChange = (filter: SearchFilter) => {
|
||||
addResult('filterChange', true, filter);
|
||||
|
||||
// 가상 데이터로 검색 결과 시뮬레이션
|
||||
const mockData: any = generateMockData(filter);
|
||||
setSearchData(mockData);
|
||||
};
|
||||
|
||||
// 가상 거래 데이터 생성
|
||||
const generateMockData = (filter: SearchFilter) => {
|
||||
const transactionTypes = ['deposit', 'withdrawal'];
|
||||
const data = [];
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const type = filter.transactionType === 'all'
|
||||
? transactionTypes[Math.floor(Math.random() * transactionTypes.length)]
|
||||
: filter.transactionType;
|
||||
|
||||
const amount = Math.floor(Math.random() * 1000000) + 10000;
|
||||
const date = new Date();
|
||||
date.setDate(date.getDate() - Math.floor(Math.random() * 180));
|
||||
|
||||
data.push({
|
||||
id: `TXN${String(i + 1).padStart(3, '0')}`,
|
||||
type: type,
|
||||
amount: amount,
|
||||
date: date,
|
||||
status: Math.random() > 0.1 ? 'completed' : 'failed',
|
||||
description: type === 'deposit' ? '입금' : '출금'
|
||||
});
|
||||
}
|
||||
|
||||
// 정렬 적용
|
||||
data.sort((a, b) => {
|
||||
if (filter.sortOrder === 'latest') {
|
||||
return b.date.getTime() - a.date.getTime();
|
||||
} else {
|
||||
return a.date.getTime() - b.date.getTime();
|
||||
}
|
||||
});
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 py-8">
|
||||
<div className="max-w-6xl mx-auto px-4">
|
||||
<div className="bg-white rounded-lg shadow-lg p-6 mb-6">
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<h1 className="text-3xl font-bold text-gray-900">AppBridge 테스트</h1>
|
||||
<div className="flex space-x-4">
|
||||
<LanguageSwitcher />
|
||||
<span className={`px-3 py-1 rounded-full text-sm font-medium ${
|
||||
appBridge.isNativeEnvironment()
|
||||
? 'bg-green-100 text-green-800'
|
||||
: 'bg-red-100 text-red-800'
|
||||
}`}>
|
||||
{appBridge.isNativeEnvironment() ? '네이티브 환경' : '웹 환경'}
|
||||
</span>
|
||||
{appBridge.isNativeEnvironment() && (
|
||||
<span className={`px-3 py-1 rounded-full text-sm font-medium ${
|
||||
appBridge.isAndroid()
|
||||
? 'bg-blue-100 text-blue-800'
|
||||
: 'bg-gray-100 text-gray-800'
|
||||
}`}>
|
||||
{appBridge.isAndroid() ? 'Android' : appBridge.isIOS() ? 'iOS' : 'Unknown'}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!appBridge.isNativeEnvironment() && (
|
||||
<div className="bg-yellow-50 border border-yellow-200 rounded-md p-4 mb-6">
|
||||
<div className="flex">
|
||||
<div className="flex-shrink-0">
|
||||
<svg className="h-5 w-5 text-yellow-400" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fillRule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clipRule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
<div className="ml-3">
|
||||
<h3 className="text-sm font-medium text-yellow-800">
|
||||
웹 환경에서 실행 중
|
||||
</h3>
|
||||
<div className="mt-2 text-sm text-yellow-700">
|
||||
<p>대부분의 AppBridge 기능은 네이티브 환경에서만 작동합니다. 실제 테스트를 위해서는 모바일 앱에서 실행해주세요.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
{/* 검색 결과 표시 */}
|
||||
{searchData.length > 0 && (
|
||||
<div className="bg-white rounded-lg shadow-lg p-6 mb-6">
|
||||
<h2 className="text-xl font-semibold text-gray-900 mb-4">
|
||||
검색 결과 ({searchData.length}건)
|
||||
</h2>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="min-w-full divide-y divide-gray-200">
|
||||
<thead className="bg-gray-50">
|
||||
<tr>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
거래ID
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
구분
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
금액
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
날짜
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
상태
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="bg-white divide-y divide-gray-200">
|
||||
{searchData.map((item, index) => (
|
||||
<tr key={index} className="hover:bg-gray-50">
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
|
||||
{item.id}
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
||||
<span className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${
|
||||
item.type === 'deposit'
|
||||
? 'bg-green-100 text-green-800'
|
||||
: 'bg-red-100 text-red-800'
|
||||
}`}>
|
||||
{item.description}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
||||
{item.amount.toLocaleString()}원
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
||||
{item.date.toLocaleDateString('ko-KR')}
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
||||
<span className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${
|
||||
item.status === 'completed'
|
||||
? 'bg-blue-100 text-blue-800'
|
||||
: 'bg-gray-100 text-gray-800'
|
||||
}`}>
|
||||
{item.status === 'completed' ? '완료' : '실패'}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
{/* 테스트 버튼들 */}
|
||||
<div className="bg-white rounded-lg shadow-lg p-6">
|
||||
<h2 className="text-xl font-semibold text-gray-900 mb-4">테스트 기능</h2>
|
||||
|
||||
{/* 앱 정보 */}
|
||||
<div className="mb-6">
|
||||
<h3 className="text-lg font-medium text-gray-800 mb-2">앱 정보</h3>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<button
|
||||
onClick={testGetAppInfo}
|
||||
disabled={isLoading === 'getAppInfo'}
|
||||
className="bg-blue-500 hover:bg-blue-600 disabled:bg-blue-300 text-white px-4 py-2 rounded text-sm"
|
||||
>
|
||||
{isLoading === 'getAppInfo' ? '실행 중...' : '앱 정보'}
|
||||
</button>
|
||||
<button
|
||||
onClick={testGetDeviceInfo}
|
||||
disabled={isLoading === 'getDeviceInfo'}
|
||||
className="bg-blue-500 hover:bg-blue-600 disabled:bg-blue-300 text-white px-4 py-2 rounded text-sm"
|
||||
>
|
||||
{isLoading === 'getDeviceInfo' ? '실행 중...' : '디바이스 정보'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 네비게이션 */}
|
||||
<div className="mb-6">
|
||||
<h3 className="text-lg font-medium text-gray-800 mb-2">네비게이션</h3>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<button
|
||||
onClick={testNavigateBack}
|
||||
disabled={isLoading === 'navigateBack'}
|
||||
className="bg-green-500 hover:bg-green-600 disabled:bg-green-300 text-white px-4 py-2 rounded text-sm"
|
||||
>
|
||||
{isLoading === 'navigateBack' ? '실행 중...' : '뒤로 가기'}
|
||||
</button>
|
||||
<button
|
||||
onClick={testNavigateTo}
|
||||
disabled={isLoading === 'navigateTo'}
|
||||
className="bg-green-500 hover:bg-green-600 disabled:bg-green-300 text-white px-4 py-2 rounded text-sm"
|
||||
>
|
||||
{isLoading === 'navigateTo' ? '실행 중...' : '페이지 이동'}
|
||||
</button>
|
||||
<button
|
||||
onClick={testNavigateToLogin}
|
||||
disabled={isLoading === 'navigateToLogin'}
|
||||
className="bg-green-500 hover:bg-green-600 disabled:bg-green-300 text-white px-4 py-2 rounded text-sm"
|
||||
>
|
||||
{isLoading === 'navigateTo' ? '실행 중...' : '로그인 화면'}
|
||||
</button>
|
||||
<button
|
||||
onClick={testCloseWebView}
|
||||
disabled={isLoading === 'closeWebView'}
|
||||
className="bg-red-500 hover:bg-red-600 disabled:bg-red-300 text-white px-4 py-2 rounded text-sm col-span-2"
|
||||
>
|
||||
{isLoading === 'closeWebView' ? '실행 중...' : '웹뷰 닫기'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 알림 */}
|
||||
<div className="mb-6">
|
||||
<h3 className="text-lg font-medium text-gray-800 mb-2">알림</h3>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<button
|
||||
onClick={testShowToast}
|
||||
disabled={isLoading === 'showToast'}
|
||||
className="bg-yellow-500 hover:bg-yellow-600 disabled:bg-yellow-300 text-white px-4 py-2 rounded text-sm"
|
||||
>
|
||||
{isLoading === 'showToast' ? '실행 중...' : '토스트'}
|
||||
</button>
|
||||
<button
|
||||
onClick={testShowAlert}
|
||||
disabled={isLoading === 'showAlert'}
|
||||
className="bg-yellow-500 hover:bg-yellow-600 disabled:bg-yellow-300 text-white px-4 py-2 rounded text-sm"
|
||||
>
|
||||
{isLoading === 'showAlert' ? '실행 중...' : '알림'}
|
||||
</button>
|
||||
<button
|
||||
onClick={testShowConfirm}
|
||||
disabled={isLoading === 'showConfirm'}
|
||||
className="bg-yellow-500 hover:bg-yellow-600 disabled:bg-yellow-300 text-white px-4 py-2 rounded text-sm col-span-2"
|
||||
>
|
||||
{isLoading === 'showConfirm' ? '실행 중...' : '확인 대화상자'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 저장소 */}
|
||||
<div className="mb-6">
|
||||
<h3 className="text-lg font-medium text-gray-800 mb-2">저장소</h3>
|
||||
<div className="grid grid-cols-3 gap-2">
|
||||
<button
|
||||
onClick={testSetStorage}
|
||||
disabled={isLoading === 'setStorage'}
|
||||
className="bg-purple-500 hover:bg-purple-600 disabled:bg-purple-300 text-white px-4 py-2 rounded text-sm"
|
||||
>
|
||||
{isLoading === 'setStorage' ? '실행 중...' : '저장'}
|
||||
</button>
|
||||
<button
|
||||
onClick={testGetStorage}
|
||||
disabled={isLoading === 'getStorage'}
|
||||
className="bg-purple-500 hover:bg-purple-600 disabled:bg-purple-300 text-white px-4 py-2 rounded text-sm"
|
||||
>
|
||||
{isLoading === 'getStorage' ? '실행 중...' : '읽기'}
|
||||
</button>
|
||||
<button
|
||||
onClick={testRemoveStorage}
|
||||
disabled={isLoading === 'removeStorage'}
|
||||
className="bg-purple-500 hover:bg-purple-600 disabled:bg-purple-300 text-white px-4 py-2 rounded text-sm"
|
||||
>
|
||||
{isLoading === 'removeStorage' ? '실행 중...' : '삭제'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{/* 결제 및 인증 */}
|
||||
<div className="mb-6">
|
||||
<h3 className="text-lg font-medium text-gray-800 mb-2">결제 & 인증</h3>
|
||||
<div className="space-y-2">
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<button
|
||||
onClick={testLogin}
|
||||
disabled={isLoading === 'login'}
|
||||
className="bg-green-600 hover:bg-green-700 disabled:bg-green-300 text-white px-4 py-2 rounded text-sm"
|
||||
>
|
||||
{isLoading === 'login' ? '실행 중...' : '로그인'}
|
||||
</button>
|
||||
<button
|
||||
onClick={testLogout}
|
||||
disabled={isLoading === 'logout'}
|
||||
className="bg-red-600 hover:bg-red-700 disabled:bg-red-300 text-white px-4 py-2 rounded text-sm"
|
||||
>
|
||||
{isLoading === 'logout' ? '실행 중...' : '로그아웃'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 공유 */}
|
||||
<div className="mb-6">
|
||||
<h3 className="text-lg font-medium text-gray-800 mb-2">공유</h3>
|
||||
<div className="space-y-2">
|
||||
<button
|
||||
onClick={testShareContent}
|
||||
disabled={isLoading === 'shareContent'}
|
||||
className="bg-cyan-500 hover:bg-cyan-600 disabled:bg-cyan-300 text-white px-4 py-2 rounded text-sm w-full"
|
||||
>
|
||||
{isLoading === 'shareContent' ? '실행 중...' : '공유'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 메시지 카운트 */}
|
||||
<div className="mb-6">
|
||||
<h3 className="text-lg font-medium text-gray-800 mb-2">메시지 카운트</h3>
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center space-x-2">
|
||||
<input
|
||||
type="number"
|
||||
value={messageCount}
|
||||
onChange={(e) => setMessageCount(parseInt(e.target.value) || 0)}
|
||||
min="0"
|
||||
className="border border-gray-300 rounded px-3 py-1 text-sm w-20"
|
||||
placeholder="0"
|
||||
/>
|
||||
<button
|
||||
onClick={testUpdateMessageCount}
|
||||
disabled={isLoading === 'updateMessageCount'}
|
||||
className="bg-orange-500 hover:bg-orange-600 disabled:bg-orange-300 text-white px-4 py-2 rounded text-sm"
|
||||
>
|
||||
{isLoading === 'updateMessageCount' ? '실행 중...' : '배지 업데이트'}
|
||||
</button>
|
||||
</div>
|
||||
<p className="text-xs text-gray-600">
|
||||
iOS: 앱 아이콘 배지 / Android: 로그 출력
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 고급 테스트 */}
|
||||
<div className="mb-6">
|
||||
<h3 className="text-lg font-medium text-gray-800 mb-2">고급 테스트</h3>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<button
|
||||
onClick={testSafeCall}
|
||||
disabled={isLoading === 'safeCall'}
|
||||
className="bg-gray-500 hover:bg-gray-600 disabled:bg-gray-300 text-white px-4 py-2 rounded text-sm"
|
||||
>
|
||||
{isLoading === 'safeCall' ? '실행 중...' : '안전한 호출'}
|
||||
</button>
|
||||
<button
|
||||
onClick={testCallWithTimeout}
|
||||
disabled={isLoading === 'callWithTimeout'}
|
||||
className="bg-gray-500 hover:bg-gray-600 disabled:bg-gray-300 text-white px-4 py-2 rounded text-sm"
|
||||
>
|
||||
{isLoading === 'callWithTimeout' ? '실행 중...' : '타임아웃 호출'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 테스트 결과 */}
|
||||
<div className="bg-white rounded-lg shadow-lg p-6">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h2 className="text-xl font-semibold text-gray-900">테스트 결과</h2>
|
||||
<button
|
||||
onClick={clearResults}
|
||||
className="bg-gray-500 hover:bg-gray-600 text-white px-4 py-2 rounded text-sm"
|
||||
>
|
||||
결과 지우기
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3 max-h-96 overflow-y-auto">
|
||||
{results.length === 0 ? (
|
||||
<p className="text-gray-500 text-center py-8">
|
||||
테스트 버튼을 클릭하여 결과를 확인하세요.
|
||||
</p>
|
||||
) : (
|
||||
results.map((result, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`p-3 rounded-lg border ${
|
||||
result.success
|
||||
? 'bg-green-50 border-green-200'
|
||||
: 'bg-red-50 border-red-200'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="font-medium text-gray-900">
|
||||
{result.method}
|
||||
</span>
|
||||
<span className="text-sm text-gray-500">
|
||||
{result.timestamp}
|
||||
</span>
|
||||
</div>
|
||||
{result.success ? (
|
||||
<div className="mt-2">
|
||||
<span className="text-green-800 text-sm">✅ 성공</span>
|
||||
{result.result && (
|
||||
<pre className="mt-1 text-xs bg-green-100 p-2 rounded overflow-x-auto">
|
||||
{JSON.stringify(result.result, null, 2)}
|
||||
</pre>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="mt-2">
|
||||
<span className="text-red-800 text-sm">❌ 실패</span>
|
||||
<p className="mt-1 text-xs text-red-700 bg-red-100 p-2 rounded">
|
||||
{result.error}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Test;
|
||||
@@ -1,3 +1,2 @@
|
||||
export { default as Home } from './Home';
|
||||
export { default as Contact } from './Contact';
|
||||
export { default as Test } from './Test';
|
||||
export { default as Contact } from './Contact';
|
||||
Reference in New Issue
Block a user