Files
trading_bot_v3/components/SessionStatus.tsx
mindesbunister a9bbcc7b5f Fix Tailwind CSS styling configuration
- Add tailwind.config.ts with proper content paths and theme config
- Add postcss.config.js for Tailwind and autoprefixer processing
- Downgrade tailwindcss to v3.4.17 and add missing PostCSS dependencies
- Update Dockerfile to clarify build process
- Fix UI styling issues in Docker environment
2025-07-12 23:29:42 +02:00

203 lines
7.2 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client"
import React, { useState, useEffect } from 'react'
interface SessionInfo {
isAuthenticated: boolean
hasSavedCookies: boolean
hasSavedStorage: boolean
cookiesCount: number
currentUrl: string
browserActive: boolean
connectionStatus: 'connected' | 'disconnected' | 'unknown' | 'error'
lastChecked: string
dockerEnv?: boolean
environment?: string
}
export default function SessionStatus() {
const [sessionInfo, setSessionInfo] = useState<SessionInfo | null>(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
const [refreshing, setRefreshing] = useState(false)
const fetchSessionStatus = async () => {
try {
setError(null)
const response = await fetch('/api/session-status', {
cache: 'no-cache' // Important for Docker environment
})
const data = await response.json()
if (data.success) {
setSessionInfo(data.session)
} else {
setError(data.error || 'Failed to fetch session status')
setSessionInfo(data.session || null)
}
} catch (e) {
setError(e instanceof Error ? e.message : 'Network error')
setSessionInfo(null)
} finally {
setLoading(false)
}
}
const handleSessionAction = async (action: string) => {
try {
setRefreshing(true)
setError(null)
const response = await fetch('/api/session-status', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action }),
cache: 'no-cache' // Important for Docker environment
})
const data = await response.json()
if (data.success) {
// Refresh session status after action
await fetchSessionStatus()
} else {
setError(data.error || `Failed to ${action} session`)
}
} catch (e) {
setError(e instanceof Error ? e.message : `Failed to ${action} session`)
} finally {
setRefreshing(false)
}
}
useEffect(() => {
fetchSessionStatus()
// Auto-refresh more frequently in Docker environment (30s vs 60s)
const refreshInterval = 30000 // Start with 30 seconds for all environments
const interval = setInterval(fetchSessionStatus, refreshInterval)
return () => clearInterval(interval)
}, [])
const getConnectionStatus = () => {
if (!sessionInfo) return { color: 'bg-gray-500', text: 'Unknown', icon: '❓' }
if (sessionInfo.isAuthenticated && sessionInfo.connectionStatus === 'connected') {
return { color: 'bg-green-500', text: 'Connected & Authenticated', icon: '✅' }
} else if (sessionInfo.hasSavedCookies || sessionInfo.hasSavedStorage) {
return { color: 'bg-yellow-500', text: 'Session Available', icon: '🟡' }
} else if (sessionInfo.connectionStatus === 'connected') {
return { color: 'bg-blue-500', text: 'Connected (Not Authenticated)', icon: '🔵' }
} else {
return { color: 'bg-red-500', text: 'Disconnected', icon: '🔴' }
}
}
const status = getConnectionStatus()
return (
<div className="card card-gradient">
<div className="flex items-center justify-between mb-6">
<h2 className="text-lg font-bold text-white flex items-center">
<span className="w-8 h-8 bg-gradient-to-br from-blue-400 to-indigo-600 rounded-lg flex items-center justify-center mr-3">
🌐
</span>
Session Status
</h2>
<button
onClick={fetchSessionStatus}
disabled={loading || refreshing}
className="p-2 text-gray-400 hover:text-gray-300 transition-colors"
title="Refresh Status"
>
<svg className={`w-4 h-4 ${(loading || refreshing) ? 'animate-spin' : ''}`} fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
</button>
</div>
{/* Connection Status */}
<div className="mb-6">
<div className="flex items-center justify-between p-4 bg-gray-800/30 rounded-lg border border-gray-700">
<div className="flex items-center space-x-3">
<div className={`w-3 h-3 ${status.color} rounded-full ${sessionInfo?.isAuthenticated ? 'animate-pulse' : ''}`}></div>
<div>
<h3 className="text-sm font-semibold text-white">{status.text}</h3>
<p className="text-xs text-gray-400">
{sessionInfo?.dockerEnv ? 'Docker Environment' : 'Local Environment'}
{sessionInfo?.environment && `${sessionInfo.environment}`}
</p>
</div>
</div>
<span className="text-2xl">{status.icon}</span>
</div>
</div>
{/* Session Details */}
<div className="space-y-4">
<div className="grid grid-cols-2 gap-4">
<div className="p-3 bg-gray-800/20 rounded-lg">
<div className="text-xs text-gray-400">Browser Status</div>
<div className={`text-sm font-medium ${sessionInfo?.browserActive ? 'text-green-400' : 'text-red-400'}`}>
{loading ? 'Checking...' : sessionInfo?.browserActive ? 'Active' : 'Inactive'}
</div>
</div>
<div className="p-3 bg-gray-800/20 rounded-lg">
<div className="text-xs text-gray-400">Cookies</div>
<div className="text-sm font-medium text-white">
{loading ? '...' : sessionInfo?.cookiesCount || 0} stored
</div>
</div>
</div>
{sessionInfo?.currentUrl && (
<div className="p-3 bg-gray-800/20 rounded-lg">
<div className="text-xs text-gray-400 mb-1">Current URL</div>
<div className="text-xs text-gray-300 font-mono break-all">
{sessionInfo.currentUrl}
</div>
</div>
)}
{sessionInfo?.lastChecked && (
<div className="text-xs text-gray-500 text-center">
Last updated: {new Date(sessionInfo.lastChecked).toLocaleString()}
</div>
)}
</div>
{/* Error Display */}
{error && (
<div className="mt-4 p-3 bg-red-500/10 border border-red-500/30 rounded-lg">
<div className="flex items-start space-x-2">
<span className="text-red-400 text-sm"></span>
<div>
<h4 className="text-red-400 font-medium text-sm">Connection Error</h4>
<p className="text-red-300 text-xs mt-1">{error}</p>
</div>
</div>
</div>
)}
{/* Action Buttons */}
<div className="mt-6 grid grid-cols-2 gap-3">
<button
onClick={() => handleSessionAction('reconnect')}
disabled={refreshing}
className="btn-primary py-2 px-4 text-sm"
>
{refreshing ? 'Connecting...' : 'Reconnect'}
</button>
<button
onClick={() => handleSessionAction('clear')}
disabled={refreshing}
className="btn-secondary py-2 px-4 text-sm"
>
Clear Session
</button>
</div>
</div>
)
}