Add sync financials button on financials page
This commit is contained in:
@@ -17,7 +17,7 @@ import {
|
|||||||
XAxis,
|
XAxis,
|
||||||
YAxis
|
YAxis
|
||||||
} from 'recharts';
|
} from 'recharts';
|
||||||
import { ChartNoAxesCombined, ChevronDown, RefreshCcw, Search } from 'lucide-react';
|
import { ChartNoAxesCombined, ChevronDown, Download, RefreshCcw, Search } from 'lucide-react';
|
||||||
import { AppShell } from '@/components/shell/app-shell';
|
import { AppShell } from '@/components/shell/app-shell';
|
||||||
import { MetricCard } from '@/components/dashboard/metric-card';
|
import { MetricCard } from '@/components/dashboard/metric-card';
|
||||||
import {
|
import {
|
||||||
@@ -30,11 +30,13 @@ import { Input } from '@/components/ui/input';
|
|||||||
import { Panel } from '@/components/ui/panel';
|
import { Panel } from '@/components/ui/panel';
|
||||||
import { useAuthGuard } from '@/hooks/use-auth-guard';
|
import { useAuthGuard } from '@/hooks/use-auth-guard';
|
||||||
import { useLinkPrefetch } from '@/hooks/use-link-prefetch';
|
import { useLinkPrefetch } from '@/hooks/use-link-prefetch';
|
||||||
|
import { queueFilingSync } from '@/lib/api';
|
||||||
import {
|
import {
|
||||||
formatCurrencyByScale,
|
formatCurrencyByScale,
|
||||||
formatPercent,
|
formatPercent,
|
||||||
type NumberScaleUnit
|
type NumberScaleUnit
|
||||||
} from '@/lib/format';
|
} from '@/lib/format';
|
||||||
|
import { queryKeys } from '@/lib/query/keys';
|
||||||
import { companyFinancialStatementsQueryOptions } from '@/lib/query/options';
|
import { companyFinancialStatementsQueryOptions } from '@/lib/query/options';
|
||||||
import type {
|
import type {
|
||||||
CompanyFinancialStatementsResponse,
|
CompanyFinancialStatementsResponse,
|
||||||
@@ -320,6 +322,7 @@ function FinancialsPageContent() {
|
|||||||
const [dimensionsEnabled, setDimensionsEnabled] = useState(false);
|
const [dimensionsEnabled, setDimensionsEnabled] = useState(false);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [loadingMore, setLoadingMore] = useState(false);
|
const [loadingMore, setLoadingMore] = useState(false);
|
||||||
|
const [syncingFinancials, setSyncingFinancials] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -413,6 +416,28 @@ function FinancialsPageContent() {
|
|||||||
loadOverview
|
loadOverview
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const syncFinancials = useCallback(async () => {
|
||||||
|
const targetTicker = (financials?.company.ticker ?? ticker).trim().toUpperCase();
|
||||||
|
if (!targetTicker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setSyncingFinancials(true);
|
||||||
|
setError(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await queueFilingSync({ ticker: targetTicker, limit: 20 });
|
||||||
|
void queryClient.invalidateQueries({ queryKey: queryKeys.recentTasks(20) });
|
||||||
|
void queryClient.invalidateQueries({ queryKey: ['filings'] });
|
||||||
|
void queryClient.invalidateQueries({ queryKey: ['financials-v2'] });
|
||||||
|
await loadFinancials(targetTicker);
|
||||||
|
} catch (err) {
|
||||||
|
setError(err instanceof Error ? err.message : `Failed to queue financial sync for ${targetTicker}`);
|
||||||
|
} finally {
|
||||||
|
setSyncingFinancials(false);
|
||||||
|
}
|
||||||
|
}, [financials?.company.ticker, ticker, queryClient, loadFinancials]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isPending && isAuthenticated) {
|
if (!isPending && isAuthenticated) {
|
||||||
void loadFinancials(ticker);
|
void loadFinancials(ticker);
|
||||||
@@ -559,15 +584,27 @@ function FinancialsPageContent() {
|
|||||||
subtitle="Dual-mode financial statements with standardized comparability and filing-faithful presentation."
|
subtitle="Dual-mode financial statements with standardized comparability and filing-faithful presentation."
|
||||||
activeTicker={financials?.company.ticker ?? ticker}
|
activeTicker={financials?.company.ticker ?? ticker}
|
||||||
actions={(
|
actions={(
|
||||||
<Button
|
<div className="flex w-full flex-wrap items-center justify-end gap-2 sm:w-auto">
|
||||||
variant="secondary"
|
<Button
|
||||||
onClick={() => {
|
variant="secondary"
|
||||||
void loadFinancials(ticker);
|
disabled={syncingFinancials}
|
||||||
}}
|
onClick={() => {
|
||||||
>
|
void syncFinancials();
|
||||||
<RefreshCcw className="size-4" />
|
}}
|
||||||
Refresh
|
>
|
||||||
</Button>
|
<Download className="size-4" />
|
||||||
|
{syncingFinancials ? 'Syncing...' : 'Sync Financials'}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
onClick={() => {
|
||||||
|
void loadFinancials(ticker);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<RefreshCcw className="size-4" />
|
||||||
|
Refresh
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Panel title="Company Selector" subtitle="Load statement history by ticker. Default window is 10 years; full history is on demand.">
|
<Panel title="Company Selector" subtitle="Load statement history by ticker. Default window is 10 years; full history is on demand.">
|
||||||
|
|||||||
Reference in New Issue
Block a user