109 lines
4.3 KiB
TypeScript
109 lines
4.3 KiB
TypeScript
|
|
import React, { useState, useEffect, useCallback } from 'react';
|
|
import { supabase, runDatabaseSelfTest, testStorageConnection } from '../services/supabaseClient';
|
|
import { ServerIcon } from './icons/ServerIcon';
|
|
import { LoadingSpinner } from './LoadingSpinner';
|
|
|
|
type TestStatus = 'idle' | 'testing' | 'success' | 'error';
|
|
|
|
interface DatabaseControlsProps {
|
|
onReady: () => void;
|
|
}
|
|
|
|
export const DatabaseControls: React.FC<DatabaseControlsProps> = ({ onReady }) => {
|
|
const [status, setStatus] = useState<TestStatus>('idle');
|
|
const [message, setMessage] = useState('');
|
|
const [hasRunAutoTest, setHasRunAutoTest] = useState(false);
|
|
|
|
const handleTestConnection = useCallback(async () => {
|
|
setStatus('testing');
|
|
setMessage('');
|
|
|
|
try {
|
|
// Test 1: Full Database CRUD Self-Test
|
|
const dbResult = await runDatabaseSelfTest();
|
|
if (!dbResult.success) {
|
|
setStatus('error');
|
|
setMessage(dbResult.error || 'An unknown database error occurred.');
|
|
return;
|
|
}
|
|
|
|
// Test 2: Storage Write/Delete
|
|
const storageResult = await testStorageConnection();
|
|
if (!storageResult.success) {
|
|
setStatus('error');
|
|
setMessage(storageResult.error || 'An unknown storage error occurred.');
|
|
return;
|
|
}
|
|
|
|
// All tests passed
|
|
setStatus('success');
|
|
setMessage('Connection successful! Database and Storage are working correctly.');
|
|
|
|
// Reset after a few seconds if it was a manual test
|
|
setTimeout(() => {
|
|
if (status !== 'testing') {
|
|
setStatus('idle');
|
|
setMessage('');
|
|
}
|
|
}, 8000);
|
|
} finally {
|
|
// This is the crucial step: always signal readiness after the test sequence completes.
|
|
onReady();
|
|
}
|
|
}, [status, onReady]);
|
|
|
|
// Auto-run the test once on initial connection
|
|
useEffect(() => {
|
|
if (supabase && !hasRunAutoTest) {
|
|
setHasRunAutoTest(true);
|
|
handleTestConnection();
|
|
}
|
|
}, [supabase, hasRunAutoTest, handleTestConnection]);
|
|
|
|
|
|
if (!supabase) {
|
|
return null; // Don't render anything if Supabase is not configured
|
|
}
|
|
|
|
const statusText = status === 'success' ? 'OK' : status === 'error' ? 'Error' : status === 'testing' ? 'Testing...' : 'Connected';
|
|
const statusColor = status === 'success' ? 'text-green-600 dark:text-green-400'
|
|
: status === 'error' ? 'text-red-600 dark:text-red-400'
|
|
: 'text-gray-600 dark:text-gray-400';
|
|
|
|
return (
|
|
<div className="bg-white dark:bg-gray-900 rounded-lg border border-gray-200 dark:border-gray-700 p-4">
|
|
<h3 className="text-lg font-bold text-gray-800 dark:text-white flex items-center mb-3">
|
|
<ServerIcon className="w-6 h-6 mr-2 text-brand-primary" />
|
|
Backend Status
|
|
</h3>
|
|
<p className="text-sm text-gray-600 dark:text-gray-400 mb-4">
|
|
Status: <span className={`font-semibold ${statusColor}`}>{statusText}</span>. The self-test checks all database permissions.
|
|
</p>
|
|
<button
|
|
onClick={handleTestConnection}
|
|
disabled={status === 'testing'}
|
|
className="w-full bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600 disabled:opacity-50 disabled:cursor-wait text-gray-800 dark:text-white font-bold py-2 px-4 rounded-lg transition-colors duration-300 flex items-center justify-center"
|
|
>
|
|
{status === 'testing' ? (
|
|
<>
|
|
<div className="w-5 h-5 mr-2"><LoadingSpinner /></div>
|
|
Testing...
|
|
</>
|
|
) : (
|
|
'Re-run Connection Test'
|
|
)}
|
|
</button>
|
|
{message && (
|
|
<div className={`mt-3 text-sm p-2 rounded ${
|
|
status === 'success' ? 'bg-green-100 dark:bg-green-900/50 text-green-800 dark:text-green-300' : ''
|
|
} ${
|
|
status === 'error' ? 'bg-red-100 dark:bg-red-900/50 text-red-800 dark:text-red-300' : ''
|
|
}`}>
|
|
{message}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|