'use client'; import { useState, useEffect, useRef, useMemo } from 'react'; import { Modal, message, Switch, Tooltip, Typography } from 'antd'; import { GlobalOutlined, ApiOutlined, CheckCircleOutlined, CloseCircleOutlined, SyncOutlined, QuestionCircleOutlined } from '@ant-design/icons'; import type { Upload } from '@/service/upload'; import { registerUpload, deleteUpload, connectUpload } from '@/service/upload'; import { useUploadStore } from '@/store/useUploadStore'; import { updateRegisteredUpload } from '@/utils/localRegisteredUpload'; import NetWorkMemberList from './NetWorkMemberList'; import { useLoadInfoStore } from '@/store/useLoadInfoStore'; import { getCurrentInfo } from '@/service/info'; import { copyToClipboard } from '@/utils/copy'; interface RegisterUploadModalProps { open: boolean; onClose: () => void; } export default function RegisterUploadModal({ open, onClose }: RegisterUploadModalProps) { const [currentUpload, setCurrentUpload] = useState(null); const addUpload = useUploadStore((state) => state.addUpload); const removeUpload = useUploadStore((state) => state.removeUpload); const uploadsTotal = useUploadStore((state) => state.total); const fetchUploadList = useUploadStore((state) => state.fetchUploadList); const fetchLoadInfo = useLoadInfoStore((state) => state.fetchLoadInfo); const setLoadInfo = useLoadInfoStore((state) => state.setLoadInfo); const loadInfo = useLoadInfoStore((state) => state.loadInfo); const [registerLoading, setRegisterLoading] = useState(false); const isRegistered = useMemo(() => { return loadInfo?.status === 'online'; }, [loadInfo]); const registerStatus = useMemo(() => { return loadInfo?.status; }, [loadInfo]); const [messageApi, contextHolder] = message.useMessage(); useEffect(() => { if (open) { startPolling(); fetchUploadList(); } }, [open, registerStatus]); useEffect(() => { // Clean up all polling when component closes if (!open && pollingIntervalsRef.current) { clearInterval(pollingIntervalsRef.current); } }, [open]); // Store polling interval IDs for each upload const pollingIntervalsRef = useRef(null); const startPolling = () => { const fetchStatus = async () => { try { const response = await getCurrentInfo(); if (response.data.code === 0) { setLoadInfo(response.data.data); setCurrentUpload({ upload_name: response.data.data.name, description: response.data.data.description, email: response.data.data.email, instance_id: response.data.data.instance_id }); // If the upload is offline, we will continue and try to connect if ( response.data.data.status === 'online' || response.data.data.status === 'unregistered' ) { stopPolling(); } } else { throw new Error(`Failed to poll status: ${response.data.message}`); } } catch (error) { console.error(`Failed to poll status:`, error); stopPolling(); } }; fetchStatus(); // Create polling and save the interval ID const intervalId = setInterval(async () => { fetchStatus(); }, 3000); // Poll every 3 seconds // Save reference to this polling if (pollingIntervalsRef.current) { clearInterval(pollingIntervalsRef.current); } pollingIntervalsRef.current = intervalId; return intervalId; }; // Stop polling for a specific upload const stopPolling = () => { if (pollingIntervalsRef.current) { clearInterval(pollingIntervalsRef.current); } }; // Clean up all polling when component unmounts useEffect(() => { return () => { // Clean up all polling if (pollingIntervalsRef.current) { clearInterval(pollingIntervalsRef.current); } }; }, []); const handleConnectUpload = async () => { const res = await connectUpload(); // Start polling to check upload status if (res.data.code === 0) { fetchLoadInfo(); } else { messageApi.error(`failed to connect, ${res.data.message}`); } }; const handleRegister = async () => { if (!currentUpload) { messageApi.warning('No Second Me available to register'); return; } setRegisterLoading(true); try { const response = await registerUpload({ upload_name: currentUpload.upload_name, description: currentUpload.description || '', email: currentUpload.email, instance_id: currentUpload.instance_id }); if (response.data.code === 0) { const uploadInfo = response.data.data; startPolling(); // Store upload information in the store addUpload(uploadInfo); updateRegisteredUpload({ upload_name: uploadInfo.upload_name, instance_id: uploadInfo.instance_id }); // Start establishing connection // Status === 'offline' ==> auto connect // handleConnectUpload(); } else { messageApi.error( `${currentUpload.upload_name} failed to register, ${response.data.message}` ); } } catch (error) { console.error('Failed to register Second Me:', error); messageApi.error('Failed to register Second Me'); } finally { setRegisterLoading(false); } }; const handleDelete = async (upload: Upload) => { if (!upload.upload_name || !upload.instance_id) { messageApi.error('Invalid Second Me data'); return; } setRegisterLoading(true); try { stopPolling(); const res = await deleteUpload(); if (res.data.code === 0) { // Remove upload from store removeUpload(upload.instance_id); } else { throw new Error(res.data.message); } } catch { messageApi.error('Failed to delete Second Me'); } finally { setRegisterLoading(false); startPolling(); } }; useEffect(() => { if (open && registerStatus === 'offline') { handleConnectUpload(); } }, [open, registerStatus]); const renderLinkCard = () => { if (registerStatus === 'unregistered' || !currentUpload) return null; return (
Second Me URL
https://app.secondme.io/{currentUpload.upload_name}/{currentUpload.instance_id}
Chat Endpoint
https://app.secondme.io/api/chat/{currentUpload.instance_id}/chat/completions
); }; return ( Join the Second Me Network } width={800} > {contextHolder}
Connect your Second Me to the global network to interact with other digital minds. Publish your Second Me to make it discoverable and accessible to others.
{/* Left Side - Current Second Me Status */}

Current Second Me Status

{currentUpload ? (
{currentUpload.upload_name ? currentUpload.upload_name.charAt(0).toUpperCase() : '?'}
{currentUpload.upload_name || 'Unknown'}
{currentUpload.email || 'No email provided'}
{/* {renderUpdateUserInfomation()} */}
{/* Status indicator for current upload if it's registered */} {registerStatus && (
{registerStatus === 'offline' ? ( ) : registerStatus === 'registered' ? ( ) : ( )} {registerStatus}
)}
{/* Publication Control */}
{' '} {/* Increased max-width to prevent text truncation */}

Register on the Network

{isRegistered ? 'Your Second Me is registered and discoverable' : 'Toggle to register your Second Me on the network'}

{' '} {/* Added left margin */} { if (!loadInfo) { return; } if (checked) { handleRegister(); } else if (currentUpload.upload_name && currentUpload.instance_id) { handleDelete(currentUpload); } }} />
{/* Public Connection option - only shown when registered */} {/* {registerStatus !== 'unregistered' && (

Public Access Control

When enabled, anyone can access your Second Me and invite it to Spaces. When disabled, your Second Me will not be accessible.

{ // This is a mock option, so we don't need to implement the backend functionality message.success(`Public access ${checked ? 'enabled' : 'disabled'}`); }} />
)} */} {renderLinkCard()}
) : (

No Second Me Available

You need to create a Second Me before joining the network

)}
{/* Right Side - Registered Second Me List */}

Network Members{' '} {uploadsTotal}

); }