MCPcopy Create free account
hub / github.com/AmazingAng/PolyWorld / SentimentPanel

Function SentimentPanel

src/components/SentimentPanel.tsx:162–239  ·  view source on GitHub ↗
()

Source from the content-addressed store, hash-verified

160}
161
162export default function SentimentPanel() {
163 const { t } = useI18n();
164 const [data, setData] = useState<SentimentIndex | null>(null);
165 const [loading, setLoading] = useState(true);
166 const [error, setError] = useState<string | null>(null);
167 const retryCount = useRef(0);
168
169 const fetchSentiment = useCallback(async () => {
170 try {
171 const res = await fetch("/api/sentiment");
172 if (!res.ok) throw new Error("fetch failed");
173 const json: SentimentIndex = await res.json();
174 setData(json);
175 setError(null);
176 retryCount.current = 0;
177 } catch {
178 if (retryCount.current < 3) {
179 const delay = 2000 * Math.pow(2, retryCount.current);
180 retryCount.current++;
181 setTimeout(fetchSentiment, delay);
182 } else {
183 setError("load failed");
184 }
185 } finally {
186 setLoading(false);
187 }
188 }, []);
189
190 useEffect(() => {
191 fetchSentiment();
192 }, [fetchSentiment]);
193
194 useVisibilityPolling(fetchSentiment, 45_000);
195
196 if (loading && !data) {
197 return (
198 <div style={{ padding: 12, fontFamily: "monospace", fontSize: 11, color: "var(--text-muted)" }}>
199 {t("sentiment.loadingSentiment")}
200 </div>
201 );
202 }
203
204 if (error && !data) {
205 return (
206 <div className="text-[11px] text-[var(--red)] font-mono py-2 text-center" aria-live="polite">
207 {t("common.loadFailed")} <button onClick={() => { retryCount.current = 0; setLoading(true); fetchSentiment(); }} className="ml-2 underline">{t("common.retry")}</button>
208 </div>
209 );
210 }
211
212 if (!data) return null;
213
214 const color = scoreColor(data.score);
215
216 return (
217 <div data-testid="sentiment-panel" style={{ padding: "6px 10px", fontFamily: "monospace", display: "flex", flexDirection: "column", gap: 6 }}>
218 {/* Gauge + label */}
219 <div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 0 }}>

Callers

nothing calls this directly

Calls 3

useI18nFunction · 0.90
useVisibilityPollingFunction · 0.90
scoreColorFunction · 0.85

Tested by

no test coverage detected