nice-bill commited on
Commit
f543d7d
·
1 Parent(s): 03c12a3

frontend build fixed

Browse files
Files changed (1) hide show
  1. frontend/src/App.jsx +107 -3
frontend/src/App.jsx CHANGED
@@ -1,4 +1,4 @@
1
- import React, { useState } from 'react';
2
  import axios from 'axios';
3
  import { Search, Share2, Activity, Database, Zap, Wallet, ChevronRight, Terminal, Layers, Hash } from 'lucide-react';
4
  import { motion, AnimatePresence } from 'framer-motion';
@@ -40,8 +40,112 @@ function App() {
40
  const [status, setStatus] = useState("idle");
41
  const [data, setData] = useState(null);
42
  const [errorMsg, setErrorMsg] = useState("");
43
-
44
- // ... (rest of code) ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
 
46
  {/* Main Content - Flex Layout to avoid scroll */}
47
  <main className="flex-grow flex flex-col md:flex-row items-center justify-center p-4 md:p-6 overflow-y-auto md:overflow-hidden relative">
 
1
+ import React, { useState, useEffect } from 'react';
2
  import axios from 'axios';
3
  import { Search, Share2, Activity, Database, Zap, Wallet, ChevronRight, Terminal, Layers, Hash } from 'lucide-react';
4
  import { motion, AnimatePresence } from 'framer-motion';
 
40
  const [status, setStatus] = useState("idle");
41
  const [data, setData] = useState(null);
42
  const [errorMsg, setErrorMsg] = useState("");
43
+
44
+ const analyzeWallet = async () => {
45
+ if (!wallet.startsWith("0x")) {
46
+ setErrorMsg("INVALID_ADDRESS: Must start with 0x");
47
+ return;
48
+ }
49
+
50
+ setStatus("loading");
51
+ setErrorMsg("");
52
+ setData(null);
53
+
54
+ try {
55
+ const startRes = await axios.post(`${API_BASE}/analyze/start/${wallet}`);
56
+ pollStatus(startRes.data.job_id);
57
+ } catch (err) {
58
+ console.error(err);
59
+ setErrorMsg("CONNECTION_ERR: API Unreachable");
60
+ setStatus("error");
61
+ }
62
+ };
63
+
64
+ const pollStatus = (jobId) => {
65
+ const interval = setInterval(async () => {
66
+ try {
67
+ const res = await axios.get(`${API_BASE}/analyze/status/${jobId}`);
68
+ const result = res.data;
69
+
70
+ if (result.status === "completed") {
71
+ clearInterval(interval);
72
+ setData(result);
73
+ setStatus("success");
74
+ } else if (result.status === "failed") {
75
+ clearInterval(interval);
76
+ setErrorMsg(result.error || "Analysis Failed");
77
+ setStatus("error");
78
+ }
79
+ } catch (err) {
80
+ clearInterval(interval);
81
+ setErrorMsg("POLLING_ERR: Lost connection");
82
+ setStatus("error");
83
+ }
84
+ }, 2000);
85
+ };
86
+
87
+ const handleExport = () => {
88
+ if (!data) return;
89
+ const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent(
90
+ JSON.stringify(data, null, 2)
91
+ )}`;
92
+ const link = document.createElement("a");
93
+ link.href = jsonString;
94
+ link.download = `analysis_${data.wallet_address || "wallet"}.json`;
95
+ link.click();
96
+ };
97
+
98
+ return (
99
+ <div className="h-screen flex flex-col overflow-hidden bg-bg-main text-sm">
100
+
101
+ {/* 1. Compact Top Navigation Bar (Command Deck Layout) */}
102
+ <header className="h-auto md:h-14 border-b border-border bg-bg-panel flex flex-col md:flex-row items-stretch md:items-center px-4 py-3 md:py-0 gap-3 md:gap-0 justify-between shrink-0 z-20">
103
+
104
+ {/* Deck 1: Brand HUD */}
105
+ <div className="flex items-center justify-between md:justify-start gap-3">
106
+ <div className="flex items-center gap-3">
107
+ <div className="w-8 h-8 text-accent flex items-center justify-center">
108
+ <img src={Logo} alt="Cluster Protocol" className="w-full h-full text-accent" />
109
+ </div>
110
+ <h1 className="font-mono font-semibold tracking-tight text-text-primary">
111
+ CLUSTER<span className="text-text-secondary">PROTOCOL</span>
112
+ </h1>
113
+ </div>
114
+ <span className="px-2 py-0.5 rounded-full bg-border text-[10px] text-text-secondary font-mono">v2.1.0</span>
115
+ </div>
116
+
117
+ {/* Deck 2: Command Line (Search) */}
118
+ <div className="flex items-center gap-2 w-full md:max-w-md">
119
+ <div className="relative flex-grow group">
120
+ <div className="absolute left-3 top-1/2 -translate-y-1/2 text-text-secondary">
121
+ <Terminal size={14} />
122
+ </div>
123
+ <input
124
+ type="text"
125
+ value={wallet}
126
+ onChange={(e) => setWallet(e.target.value)}
127
+ onKeyDown={(e) => e.key === 'Enter' && analyzeWallet()}
128
+ placeholder="0x..."
129
+ className="w-full bg-bg-main border border-border text-text-primary pl-9 pr-3 py-1.5 font-mono text-xs focus:outline-none focus:border-accent transition-colors rounded-sm"
130
+ disabled={status === 'loading'}
131
+ />
132
+ </div>
133
+ <button
134
+ onClick={analyzeWallet}
135
+ disabled={status === 'loading'}
136
+ className="px-4 py-1.5 bg-accent hover:bg-amber-400 text-black font-semibold text-xs uppercase tracking-wide rounded-sm transition-colors disabled:opacity-50"
137
+ >
138
+ {status === 'loading' ? "..." : "RUN"}
139
+ </button>
140
+ </div>
141
+ </header>
142
+
143
+ {/* Error Toast */}
144
+ {errorMsg && (
145
+ <div className="bg-red-900/20 border-b border-red-900/50 text-red-400 px-4 py-2 text-xs font-mono text-center">
146
+ ! {errorMsg}
147
+ </div>
148
+ )}
149
 
150
  {/* Main Content - Flex Layout to avoid scroll */}
151
  <main className="flex-grow flex flex-col md:flex-row items-center justify-center p-4 md:p-6 overflow-y-auto md:overflow-hidden relative">