"use client"; import React, { useEffect, useState, useCallback } from 'react'; import { useAuth } from '@/context/AuthContext'; import { post } from '@/services/api'; // ApiResponse removed import { InboundFromList } from '@/types/inbound'; // Import the new types import { formatBytes } from '@/lib/formatters'; // formatUptime removed import Link from 'next/link'; // For "Add New Inbound" button // Simple toggle switch component (can be moved to ui components later) const ToggleSwitch: React.FC<{ enabled: boolean; onChange: (enabled: boolean) => void; disabled?: boolean }> = ({ enabled, onChange, disabled }) => { return ( ); }; const InboundsPage: React.FC = () => { const { isAuthenticated, isLoading: authLoading } = useAuth(); const [inbounds, setInbounds] = useState([]); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); // Action loading states const [deletingId, setDeletingId] = useState(null); const [togglingId, setTogglingId] = useState(null); const fetchInbounds = useCallback(async () => { if (!isAuthenticated) return; setIsLoading(true); try { const response = await post('/inbound/list', {}); if (response.success && response.data) { setInbounds(response.data); setError(null); } else { setError(response.message || 'Failed to fetch inbounds.'); setInbounds([]); } } catch (err) { setError(err instanceof Error ? err.message : 'An unknown error occurred.'); setInbounds([]); } finally { setIsLoading(false); } }, [isAuthenticated]); useEffect(() => { if (!authLoading && isAuthenticated) { fetchInbounds(); } else if (!authLoading && !isAuthenticated) { setIsLoading(false); setInbounds([]); } }, [isAuthenticated, authLoading, fetchInbounds]); const handleToggleEnable = async (inboundId: number, currentEnableStatus: boolean) => { setTogglingId(inboundId); // Find the inbound to get all its data for the update const inboundToUpdate = inbounds.find(ib => ib.id === inboundId); if (!inboundToUpdate) { console.error("Inbound not found for toggling"); setTogglingId(null); return; } // Create a payload that matches the expected structure for update, // only changing the 'enable' field. const payload = { ...inboundToUpdate, enable: !currentEnableStatus }; try { const response = await post(`/inbound/update/${inboundId}`, payload); if (response.success) { await fetchInbounds(); // Refresh list } else { setError(response.message || 'Failed to update inbound status.'); } } catch (err) { setError(err instanceof Error ? err.message : 'Error updating inbound.'); } finally { setTogglingId(null); } }; const handleDeleteInbound = async (inboundId: number) => { if (!confirm('Are you sure you want to delete this inbound? This action cannot be undone.')) { return; } setDeletingId(inboundId); try { const response = await post(`/inbound/del/${inboundId}`, {}); if (response.success) { await fetchInbounds(); // Refresh list } else { setError(response.message || 'Failed to delete inbound.'); } } catch (err) { setError(err instanceof Error ? err.message : 'Error deleting inbound.'); } finally { setDeletingId(null); } }; if (authLoading || isLoading) { return
Loading inbounds...
; } // If not authenticated and not loading auth, show message (AuthContext should redirect anyway) if (!isAuthenticated && !authLoading) { return
Please login to view inbounds.
; } return (

Inbounds Management

Add New Inbound
{error &&
Error: {error}
} {inbounds.length === 0 && !error &&

No inbounds found.

} {inbounds.length > 0 && (
{inbounds.map((inbound) => ( ))}
Remark Protocol Port / Listen Traffic (Up/Down) Quota Expiry Status Actions
{inbound.remark || 'N/A'} {inbound.protocol} {inbound.port}{inbound.listen ? ` (${inbound.listen})` : ''} {formatBytes(inbound.up)} / {formatBytes(inbound.down)} {inbound.total > 0 ? formatBytes(inbound.total) : 'Unlimited'} {inbound.expiryTime === 0 ? 'Never' : new Date(inbound.expiryTime).toLocaleDateString()} handleToggleEnable(inbound.id, inbound.enable)} disabled={togglingId === inbound.id} /> Edit {/* Placeholder for Manage Clients/Details */} Clients
)}
); }; export default InboundsPage;