From b3b798ff2f86ab46e1f5fd28f8dc750c6b398abd Mon Sep 17 00:00:00 2001 From: Thigazhezhilan J Date: Wed, 8 Apr 2026 22:03:50 +0530 Subject: [PATCH] Align frontend contracts, type safety, and portfolio status handling --- package.json | 3 +- src/api/strategy.js | 21 ----- src/api/strategy.ts | 64 ++++++++++++++ src/components/StrategyTimeline.tsx | 10 +-- src/components/examples/FinalCTA.tsx | 2 +- src/components/examples/HeroSection.tsx | 2 +- src/components/landing/AuthDialogs.tsx | 2 +- src/components/landing/Footer.tsx | 2 +- src/components/landing/PortfolioSection.tsx | 97 +++++++++++---------- src/lib/queryClient.ts | 5 +- src/pages/About.tsx | 7 +- src/pages/Blog.tsx | 7 +- src/pages/Disclosures.tsx | 1 - src/pages/LearnMore.tsx | 1 - src/pages/PaperPortfolio.tsx | 6 +- src/pages/Privacy.tsx | 1 - src/pages/Terms.tsx | 1 - 17 files changed, 141 insertions(+), 91 deletions(-) delete mode 100644 src/api/strategy.js create mode 100644 src/api/strategy.ts diff --git a/package.json b/package.json index 622cc3b4..e6728c10 100644 --- a/package.json +++ b/package.json @@ -6,9 +6,10 @@ "scripts": { "dev": "vite", "build": "vite build", + "typecheck": "tsc --noEmit", + "test": "npm run typecheck", "preview": "vite preview", "start": "vite --host 0.0.0.0 --port 3001" - }, "dependencies": { "@hookform/resolvers": "^3.10.0", diff --git a/src/api/strategy.js b/src/api/strategy.js deleted file mode 100644 index f9d45257..00000000 --- a/src/api/strategy.js +++ /dev/null @@ -1,21 +0,0 @@ -import { apiRequest } from "@/lib/queryClient"; - -export async function startStrategy(data) { - const res = await apiRequest("POST", "/strategy/start", data); - return res.json(); -} - -export async function stopStrategy() { - const res = await apiRequest("POST", "/strategy/stop"); - return res.json(); -} - -export async function resumeStrategy() { - const res = await apiRequest("POST", "/strategy/resume"); - return res.json(); -} - -export async function getStrategyStatus() { - const res = await apiRequest("GET", "/strategy/status"); - return res.json(); -} diff --git a/src/api/strategy.ts b/src/api/strategy.ts new file mode 100644 index 00000000..5f668491 --- /dev/null +++ b/src/api/strategy.ts @@ -0,0 +1,64 @@ +import { apiRequest } from "@/lib/queryClient"; + +export type StrategyFrequencyUnit = "days" | "minutes"; + +export type StrategyStartRequest = { + strategy_name: string; + sip_amount: number; + sip_frequency: { + value: number; + unit: StrategyFrequencyUnit; + }; + mode: "LIVE" | "PAPER"; + initial_cash?: number; +}; + +export type StrategyActionResponse = { + status: string; + run_id?: string | null; + message?: string; + redirect_url?: string | null; + broker?: string | null; + warning?: string; +}; + +export type StrategyStatusResponse = { + status?: string; + last_updated?: string | null; + last_execution_ts?: string | null; + next_eligible_ts?: string | null; + run_id?: string | null; + can_resume?: boolean; + can_restart?: boolean; + config?: { + strategy?: string | null; + sip_amount?: number | null; + sip_frequency?: { + value?: number | null; + unit?: StrategyFrequencyUnit | null; + } | null; + mode?: string | null; + broker?: string | null; + active?: boolean | null; + } | null; +}; + +export async function startStrategy(data: StrategyStartRequest): Promise { + const res = await apiRequest("POST", "/strategy/start", data); + return res.json(); +} + +export async function stopStrategy(): Promise { + const res = await apiRequest("POST", "/strategy/stop"); + return res.json(); +} + +export async function resumeStrategy(): Promise { + const res = await apiRequest("POST", "/strategy/resume"); + return res.json(); +} + +export async function getStrategyStatus(): Promise { + const res = await apiRequest("GET", "/strategy/status"); + return res.json(); +} diff --git a/src/components/StrategyTimeline.tsx b/src/components/StrategyTimeline.tsx index 36af76e4..63fed157 100644 --- a/src/components/StrategyTimeline.tsx +++ b/src/components/StrategyTimeline.tsx @@ -33,9 +33,7 @@ type StrategyTimelineProps = { function parseTimestamp(value?: string | null) { if (!value) return null; - const hasTimezone = /Z|[+-]\d{2}:?\d{2}$/.test(value); - const normalized = hasTimezone ? value : `${value}Z`; - const parsed = new Date(normalized); + const parsed = new Date(value); return Number.isNaN(parsed.getTime()) ? null : parsed; } @@ -199,7 +197,7 @@ function VerboseStrategyTimeline() { prev.map((entry) => entry.seq).filter((seq) => typeof seq === "number"), ); const next = normalized.filter( - (entry) => typeof entry.seq !== "number" || !seenSeq.has(entry.seq), + (entry: StrategyEvent) => typeof entry.seq !== "number" || !seenSeq.has(entry.seq), ); return [...prev, ...next]; }); @@ -208,7 +206,7 @@ function VerboseStrategyTimeline() { latestSeqRef.current = data.latest_seq; } else { const lastSeq = normalized.reduce( - (max, entry) => Math.max(max, entry.seq ?? 0), + (max: number, entry: StrategyEvent) => Math.max(max, entry.seq ?? 0), latestSeqRef.current, ); latestSeqRef.current = lastSeq; @@ -306,7 +304,7 @@ function VerboseStrategyTimeline() {
Reason: {reason}
) : null}
- {run.events.map((entry, index) => { + {run.events.map((entry: StrategyEvent, index: number) => { const badge = getBadge(entry); const timestamp = entry.ts ?? entry.timestamp; const message = entry.message ?? entry.event ?? "Unknown event"; diff --git a/src/components/examples/FinalCTA.tsx b/src/components/examples/FinalCTA.tsx index 1521708b..efcd0645 100644 --- a/src/components/examples/FinalCTA.tsx +++ b/src/components/examples/FinalCTA.tsx @@ -1,5 +1,5 @@ import FinalCTA from "../landing/FinalCTA"; export default function FinalCTAExample() { - return ; + return {}} />; } diff --git a/src/components/examples/HeroSection.tsx b/src/components/examples/HeroSection.tsx index 274858a6..ed14ac79 100644 --- a/src/components/examples/HeroSection.tsx +++ b/src/components/examples/HeroSection.tsx @@ -1,5 +1,5 @@ import HeroSection from "../landing/HeroSection"; export default function HeroSectionExample() { - return ; + return {}} />; } diff --git a/src/components/landing/AuthDialogs.tsx b/src/components/landing/AuthDialogs.tsx index 632f74eb..ffd98090 100644 --- a/src/components/landing/AuthDialogs.tsx +++ b/src/components/landing/AuthDialogs.tsx @@ -252,7 +252,7 @@ export default function AuthDialogs({ layout = "desktop" }: AuthDialogsProps) {