"use client"; import { useState, useEffect } from "react"; import Image from "next/image"; import { Card, CardSkeleton, Badge } from "@/shared/components"; import { OAUTH_PROVIDERS, APIKEY_PROVIDERS } from "@/shared/constants/config"; import Link from "next/link"; import { getErrorCode, getRelativeTime } from "@/shared/utils"; export default function ProvidersPage() { const [connections, setConnections] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { const fetchData = async () => { try { const res = await fetch("/api/providers"); const data = await res.json(); if (res.ok) setConnections(data.connections || []); } catch (error) { console.log("Error fetching data:", error); } finally { setLoading(false); } }; fetchData(); }, []); const getProviderStats = (providerId, authType) => { const providerConnections = connections.filter( c => c.provider === providerId && c.authType === authType ); // Helper: check if connection is effectively active (cooldown expired) const getEffectiveStatus = (conn) => { const isCooldown = conn.rateLimitedUntil && new Date(conn.rateLimitedUntil).getTime() > Date.now(); return (conn.testStatus === "unavailable" && !isCooldown) ? "active" : conn.testStatus; }; const connected = providerConnections.filter(c => { const status = getEffectiveStatus(c); return status === "active" || status === "success"; }).length; const errorConns = providerConnections.filter(c => { const status = getEffectiveStatus(c); return status === "error" || status === "expired" || status === "unavailable"; }); const error = errorConns.length; const total = providerConnections.length; // Get latest error info const latestError = errorConns.sort((a, b) => new Date(b.lastErrorAt || 0) - new Date(a.lastErrorAt || 0) )[0]; const errorCode = latestError ? getErrorCode(latestError.lastError) : null; const errorTime = latestError?.lastErrorAt ? getRelativeTime(latestError.lastErrorAt) : null; return { connected, error, total, errorCode, errorTime }; }; if (loading) { return (
); } return (
{/* OAuth Providers */}

OAuth Providers

{Object.entries(OAUTH_PROVIDERS).map(([key, info]) => ( ))}
{/* API Key Providers */}

API Key Providers

{Object.entries(APIKEY_PROVIDERS).map(([key, info]) => ( ))}
); } function ProviderCard({ providerId, provider, stats }) { const { connected, error, errorCode, errorTime } = stats; const [imgError, setImgError] = useState(false); const getStatusDisplay = () => { const parts = []; if (connected > 0) { parts.push( {connected} Connected ); } if (error > 0) { const errText = errorCode ? `${error} Error (${errorCode})` : `${error} Error`; parts.push( {errText} ); } if (parts.length === 0) { return No connections; } return parts; }; return (
{!imgError ? ( {provider.name} setImgError(true)} /> ) : ( {provider.textIcon || provider.id.slice(0, 2).toUpperCase()} )}

{provider.name}

{getStatusDisplay()} {errorTime && • {errorTime}}
chevron_right
); } // API Key providers - only use textIcon, no image function ApiKeyProviderCard({ providerId, provider, stats }) { const { connected, error, errorCode, errorTime } = stats; const getStatusDisplay = () => { const parts = []; if (connected > 0) { parts.push( {connected} Connected ); } if (error > 0) { const errText = errorCode ? `${error} Error (${errorCode})` : `${error} Error`; parts.push( {errText} ); } if (parts.length === 0) { return No connections; } return parts; }; return (
{provider.textIcon || provider.id.slice(0, 2).toUpperCase()}

{provider.name}

{getStatusDisplay()} {errorTime && • {errorTime}}
chevron_right
); }