Update Next.js configuration for S3 support and enhance admin dashboard functionality - Added S3 hostname to next.config.js for image uploads - Updated package.json and package-lock.json with AWS SDK dependencies - Improved admin layout with S3 status component and enhanced dashboard statistics loading logic - Refactored news loading in NewsBlock component to handle errors gracefully.
This commit is contained in:
141
app/admin/components/S3Status.tsx
Normal file
141
app/admin/components/S3Status.tsx
Normal file
@ -0,0 +1,141 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import { CheckCircle, XCircle, AlertCircle, RefreshCw } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
|
||||
interface S3StatusProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export default function S3Status({ className = '' }: S3StatusProps) {
|
||||
const [status, setStatus] = useState<'checking' | 'connected' | 'error' | 'unknown'>('unknown');
|
||||
const [error, setError] = useState<string>('');
|
||||
const [isChecking, setIsChecking] = useState(false);
|
||||
|
||||
console.log('S3Status: Компонент инициализирован (версия 2.0)');
|
||||
|
||||
const checkS3Connection = async () => {
|
||||
setIsChecking(true);
|
||||
setStatus('checking');
|
||||
setError('');
|
||||
|
||||
try {
|
||||
console.log('S3Status: Проверяю подключение к S3...');
|
||||
console.log('S3Status: Используется API /api/test-s3');
|
||||
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), 10000); // 10 секунд таймаут
|
||||
|
||||
const response = await fetch(`/api/test-s3?t=${Date.now()}`, {
|
||||
signal: controller.signal,
|
||||
cache: 'no-cache'
|
||||
});
|
||||
|
||||
console.log('S3Status: Запрос отправлен к /api/test-s3, статус:', response.status);
|
||||
|
||||
clearTimeout(timeoutId);
|
||||
const result = await response.json();
|
||||
|
||||
console.log('S3Status: Результат проверки:', result);
|
||||
|
||||
if (result.success) {
|
||||
setStatus('connected');
|
||||
console.log('S3Status: Подключение успешно');
|
||||
} else {
|
||||
setStatus('error');
|
||||
const errorMessage = result.error || 'Ошибка подключения к S3';
|
||||
setError(errorMessage);
|
||||
console.error('S3Status: Ошибка подключения:', result);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('S3Status: Исключение при проверке:', err);
|
||||
setStatus('error');
|
||||
|
||||
if (err instanceof Error && err.name === 'AbortError') {
|
||||
setError('Таймаут подключения к S3 (более 10 секунд)');
|
||||
} else {
|
||||
setError(err instanceof Error ? err.message : 'Ошибка сети при проверке S3');
|
||||
}
|
||||
} finally {
|
||||
setIsChecking(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
checkS3Connection();
|
||||
}, []);
|
||||
|
||||
const getStatusIcon = () => {
|
||||
switch (status) {
|
||||
case 'checking':
|
||||
return <RefreshCw className="h-4 w-4 animate-spin text-blue-500" />;
|
||||
case 'connected':
|
||||
return <CheckCircle className="h-4 w-4 text-green-500" />;
|
||||
case 'error':
|
||||
return <XCircle className="h-4 w-4 text-red-500" />;
|
||||
default:
|
||||
return <AlertCircle className="h-4 w-4 text-gray-500" />;
|
||||
}
|
||||
};
|
||||
|
||||
const getStatusText = () => {
|
||||
switch (status) {
|
||||
case 'checking':
|
||||
return 'Проверка подключения...';
|
||||
case 'connected':
|
||||
return 'S3 подключено';
|
||||
case 'error':
|
||||
return 'Ошибка S3';
|
||||
default:
|
||||
return 'Статус неизвестен';
|
||||
}
|
||||
};
|
||||
|
||||
const getStatusColor = () => {
|
||||
switch (status) {
|
||||
case 'checking':
|
||||
return 'text-blue-400';
|
||||
case 'connected':
|
||||
return 'text-green-400';
|
||||
case 'error':
|
||||
return 'text-red-400';
|
||||
default:
|
||||
return 'text-gray-400';
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`flex items-center space-x-2 ${className}`}>
|
||||
{getStatusIcon()}
|
||||
<span className={`text-sm font-medium ${getStatusColor()}`}>
|
||||
{getStatusText()}
|
||||
</span>
|
||||
|
||||
{status === 'error' && (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={checkS3Connection}
|
||||
disabled={isChecking}
|
||||
className="ml-2"
|
||||
>
|
||||
{isChecking ? (
|
||||
<RefreshCw className="h-3 w-3 animate-spin" />
|
||||
) : (
|
||||
'Повторить'
|
||||
)}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{error && (
|
||||
<div className="ml-2 text-xs text-red-400 max-w-xs" title={error}>
|
||||
<span className="block truncate">{error}</span>
|
||||
<span className="block text-xs text-gray-500 mt-1">
|
||||
Проверьте консоль для подробностей
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user