fix: debounce ticker search on Trends page to preserve input focus
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/push/build-1 Pipeline was successful
ci/woodpecker/push/build-2 Pipeline was successful
ci/woodpecker/push/build-3 Pipeline was successful
ci/woodpecker/push/finalize Pipeline was successful
Build and Push / lint-and-test (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.adapters.broker_adapter name:broker-adapter]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.aggregation.worker name:aggregation]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.extractor.worker name:extractor]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.ingestion.worker name:ingestion]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.lake_publisher.worker name:lake-publisher]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.parser.worker name:parser]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.recommendation.worker name:recommendation]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.scheduler.app name:scheduler]) (push) Has been cancelled
Build and Push / build-services (map[cmd:uvicorn services.api.app:app --host 0.0.0.0 --port 8000 name:query-api]) (push) Has been cancelled
Build and Push / build-services (map[cmd:uvicorn services.risk.app:app --host 0.0.0.0 --port 8000 name:risk]) (push) Has been cancelled
Build and Push / build-services (map[cmd:uvicorn services.symbol_registry.app:app --host 0.0.0.0 --port 8000 name:symbol-registry]) (push) Has been cancelled
Build and Push / build-services (map[cmd:uvicorn services.trading.app:app --host 0.0.0.0 --port 8000 name:trading-engine]) (push) Has been cancelled
Build and Push / build-dashboard (push) Has been cancelled
Build and Push / build-superset (push) Has been cancelled
Build and Push / integration-test (push) Has been cancelled
Build and Push / beta-gate (push) Has been cancelled
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/push/build-1 Pipeline was successful
ci/woodpecker/push/build-2 Pipeline was successful
ci/woodpecker/push/build-3 Pipeline was successful
ci/woodpecker/push/finalize Pipeline was successful
Build and Push / lint-and-test (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.adapters.broker_adapter name:broker-adapter]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.aggregation.worker name:aggregation]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.extractor.worker name:extractor]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.ingestion.worker name:ingestion]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.lake_publisher.worker name:lake-publisher]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.parser.worker name:parser]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.recommendation.worker name:recommendation]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.scheduler.app name:scheduler]) (push) Has been cancelled
Build and Push / build-services (map[cmd:uvicorn services.api.app:app --host 0.0.0.0 --port 8000 name:query-api]) (push) Has been cancelled
Build and Push / build-services (map[cmd:uvicorn services.risk.app:app --host 0.0.0.0 --port 8000 name:risk]) (push) Has been cancelled
Build and Push / build-services (map[cmd:uvicorn services.symbol_registry.app:app --host 0.0.0.0 --port 8000 name:symbol-registry]) (push) Has been cancelled
Build and Push / build-services (map[cmd:uvicorn services.trading.app:app --host 0.0.0.0 --port 8000 name:trading-engine]) (push) Has been cancelled
Build and Push / build-dashboard (push) Has been cancelled
Build and Push / build-superset (push) Has been cancelled
Build and Push / integration-test (push) Has been cancelled
Build and Push / beta-gate (push) Has been cancelled
The TickerFilter triggered a query on every keystroke, causing re-renders that stole focus from the input. Now uses a local input state with a 300ms debounce before updating the query, keeping focus on the text box while typing.
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { useState } from 'react';
|
import { useState, useRef, useEffect } from 'react';
|
||||||
import { useNavigate, Link } from '@tanstack/react-router';
|
import { useNavigate, Link } from '@tanstack/react-router';
|
||||||
import { useTrends, useDocument } from '../api/hooks';
|
import { useTrends, useDocument } from '../api/hooks';
|
||||||
import { TrendArrow, ConfidenceBar, LoadingSpinner, TickerFilter, Card } from '../components/ui';
|
import { TrendArrow, ConfidenceBar, LoadingSpinner, Card } from '../components/ui';
|
||||||
import type { TrendSummary } from '../api/hooks';
|
import type { TrendSummary } from '../api/hooks';
|
||||||
|
|
||||||
const WINDOWS = ['intraday', '1d', '7d', '30d', '90d'];
|
const WINDOWS = ['intraday', '1d', '7d', '30d', '90d'];
|
||||||
@@ -9,8 +9,17 @@ const WINDOWS = ['intraday', '1d', '7d', '30d', '90d'];
|
|||||||
export function TrendsPage() {
|
export function TrendsPage() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [ticker, setTicker] = useState('');
|
const [ticker, setTicker] = useState('');
|
||||||
|
const [debouncedTicker, setDebouncedTicker] = useState('');
|
||||||
const [window, setWindow] = useState<string | undefined>(undefined);
|
const [window, setWindow] = useState<string | undefined>(undefined);
|
||||||
const { data, isLoading } = useTrends({ ticker: ticker || undefined, window, limit: 100 });
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
// Debounce ticker search — only query after 300ms of no typing
|
||||||
|
useEffect(() => {
|
||||||
|
const timer = setTimeout(() => setDebouncedTicker(ticker), 300);
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}, [ticker]);
|
||||||
|
|
||||||
|
const { data, isLoading } = useTrends({ ticker: debouncedTicker || undefined, window, limit: 100 });
|
||||||
|
|
||||||
if (isLoading) return <LoadingSpinner />;
|
if (isLoading) return <LoadingSpinner />;
|
||||||
|
|
||||||
@@ -19,7 +28,15 @@ export function TrendsPage() {
|
|||||||
<div className="mb-4 flex items-center justify-between">
|
<div className="mb-4 flex items-center justify-between">
|
||||||
<h1 className="text-xl font-semibold text-gray-100">Trends</h1>
|
<h1 className="text-xl font-semibold text-gray-100">Trends</h1>
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<TickerFilter value={ticker} onChange={setTicker} />
|
<input
|
||||||
|
ref={inputRef}
|
||||||
|
type="text"
|
||||||
|
placeholder="Ticker…"
|
||||||
|
value={ticker}
|
||||||
|
onChange={(e) => setTicker(e.target.value.toUpperCase())}
|
||||||
|
className="w-24 rounded-md border border-surface-700 bg-surface-900 px-2 py-1 text-xs text-gray-200 placeholder-gray-500 focus:border-brand-500 focus:outline-none"
|
||||||
|
aria-label="Filter by ticker"
|
||||||
|
/>
|
||||||
<div className="inline-flex rounded-md border border-surface-700" role="group" aria-label="Window selector">
|
<div className="inline-flex rounded-md border border-surface-700" role="group" aria-label="Window selector">
|
||||||
<button
|
<button
|
||||||
onClick={() => setWindow(undefined)}
|
onClick={() => setWindow(undefined)}
|
||||||
|
|||||||
Reference in New Issue
Block a user