"use client"; import { useState, useEffect } from "react"; import PropTypes from "prop-types"; import { Card, Button, Input, Modal, CardSkeleton } from "@/shared/components"; import { useCopyToClipboard } from "@/shared/hooks/useCopyToClipboard"; const CLOUD_URL = process.env.NEXT_PUBLIC_CLOUD_URL; export default function APIPageClient({ machineId }) { const [keys, setKeys] = useState([]); const [loading, setLoading] = useState(true); const [showAddModal, setShowAddModal] = useState(false); const [newKeyName, setNewKeyName] = useState(""); const [createdKey, setCreatedKey] = useState(null); // Cloud sync state const [cloudEnabled, setCloudEnabled] = useState(false); const [showCloudModal, setShowCloudModal] = useState(false); const [showDisableModal, setShowDisableModal] = useState(false); const [cloudSyncing, setCloudSyncing] = useState(false); const [setCloudStatus] = useState(null); const [syncStep, setSyncStep] = useState(""); // "syncing" | "verifying" | "disabling" | "" const { copied, copy } = useCopyToClipboard(); useEffect(() => { fetchData(); loadCloudSettings(); }, []); const loadCloudSettings = async () => { try { const res = await fetch("/api/settings"); if (res.ok) { const data = await res.json(); setCloudEnabled(data.cloudEnabled || false); } } catch (error) { console.log("Error loading cloud settings:", error); } }; const fetchData = async () => { try { const keysRes = await fetch("/api/keys"); const keysData = await keysRes.json(); if (keysRes.ok) { setKeys(keysData.keys || []); } } catch (error) { console.log("Error fetching data:", error); } finally { setLoading(false); } }; const handleCloudToggle = (checked) => { if (checked) { setShowCloudModal(true); } else { setShowDisableModal(true); } }; const handleEnableCloud = async () => { setCloudSyncing(true); setSyncStep("syncing"); try { const res = await fetch("/api/sync/cloud", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action: "enable" }) }); const data = await res.json(); if (res.ok) { setSyncStep("verifying"); if (data.verified) { setCloudEnabled(true); setCloudStatus({ type: "success", message: "Cloud Proxy connected and verified!" }); setShowCloudModal(false); } else { setCloudEnabled(true); setCloudStatus({ type: "warning", message: data.verifyError || "Connected but verification failed" }); setShowCloudModal(false); } // Refresh keys list if new key was created if (data.createdKey) { await fetchData(); } } else { setCloudStatus({ type: "error", message: data.error || "Failed to enable cloud" }); } } catch (error) { setCloudStatus({ type: "error", message: error.message }); } finally { setCloudSyncing(false); setSyncStep(""); } }; const handleConfirmDisable = async () => { setCloudSyncing(true); setSyncStep("syncing"); try { // Step 1: Sync latest data from cloud await fetch("/api/sync/cloud", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action: "sync" }) }); setSyncStep("disabling"); // Step 2: Disable cloud const disableRes = await fetch("/api/sync/cloud", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action: "disable" }) }); if (disableRes.ok) { setCloudEnabled(false); setCloudStatus({ type: "success", message: "Cloud disabled" }); setShowDisableModal(false); } } catch (error) { console.log("Error disabling cloud:", error); setCloudStatus({ type: "error", message: "Failed to disable cloud" }); } finally { setCloudSyncing(false); setSyncStep(""); } }; const handleSyncCloud = async () => { if (!cloudEnabled) return; setCloudSyncing(true); try { const res = await fetch("/api/sync/cloud", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action: "sync" }) }); const data = await res.json(); if (res.ok) { setCloudStatus({ type: "success", message: "Synced successfully" }); } else { setCloudStatus({ type: "error", message: data.error }); } } catch (error) { setCloudStatus({ type: "error", message: error.message }); } finally { setCloudSyncing(false); } }; const handleCreateKey = async () => { if (!newKeyName.trim()) return; try { const res = await fetch("/api/keys", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name: newKeyName }), }); const data = await res.json(); if (res.ok) { setCreatedKey(data.key); await fetchData(); setNewKeyName(""); setShowAddModal(false); } } catch (error) { console.log("Error creating key:", error); } }; const handleDeleteKey = async (id) => { if (!confirm("Delete this API key?")) return; try { const res = await fetch(`/api/keys/${id}`, { method: "DELETE" }); if (res.ok) { setKeys(keys.filter((k) => k.id !== id)); } } catch (error) { console.log("Error deleting key:", error); } }; const [baseUrl, setBaseUrl] = useState("/v1"); const cloudEndpointNew = `${CLOUD_URL}/v1`; // Hydration fix: Only access window on client side useEffect(() => { if (typeof window !== "undefined") { setBaseUrl(`${window.location.origin}/v1`); } }, []); if (loading) { return (
{cloudEnabled ? "Using Cloud Proxy" : "Using Local Server"}
No API keys yet
Create your first API key to get started
{key.name}
{key.key}
Created {new Date(key.createdAt).toLocaleDateString()}
{cloudEnabled ? "Connected & Ready" : "Access your API from anywhere"}
{benefit.title}
{benefit.desc}
What you will get
Note
{syncStep === "syncing" && "Syncing data to cloud..."} {syncStep === "verifying" && "Verifying connection..."}
Save this key now!
This is the only time you will see this key. Store it securely.
Warning
All auth sessions will be deleted from cloud.
{syncStep === "syncing" && "Syncing latest data..."} {syncStep === "disabling" && "Disabling cloud..."}
Are you sure you want to disable cloud proxy?