Skip to content

Commit 0e496cc

Browse files
committed
feat: refactor stock history type, update API calls with base URL and auth
1 parent 98fee03 commit 0e496cc

File tree

7 files changed

+41
-107
lines changed

7 files changed

+41
-107
lines changed

frontend/src/api/stock.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
2-
import { API_QUERY_KEYS, USER_LANGUAGE } from "@/constants/api";
2+
import {
3+
API_QUERY_KEYS,
4+
USER_LANGUAGE,
5+
VALUECELL_BACKEND_URL,
6+
} from "@/constants/api";
37
import { type ApiResponse, apiClient } from "@/lib/api-client";
8+
import { useSystemStore } from "@/store/system-store";
49
import type {
510
Stock,
611
StockDetail,
@@ -64,7 +69,10 @@ export const useGetStockPrice = (params: { ticker: string }) =>
6469
queryKey: API_QUERY_KEYS.STOCK.stockPrice(Object.values(params)),
6570
queryFn: () =>
6671
apiClient.get<ApiResponse<StockPrice>>(
67-
`watchlist/asset/${params.ticker}/price`,
72+
`${useSystemStore.getState().access_token ? VALUECELL_BACKEND_URL : ""}/watchlist/asset/${params.ticker}/price`,
73+
{
74+
requiresAuth: !!useSystemStore.getState().access_token,
75+
},
6876
),
6977
select: (data) => data.data,
7078
enabled: !!params.ticker,
@@ -79,8 +87,11 @@ export const useGetStockHistory = (params: {
7987
useQuery({
8088
queryKey: API_QUERY_KEYS.STOCK.stockHistory(Object.values(params)),
8189
queryFn: () =>
82-
apiClient.get<ApiResponse<StockHistory>>(
83-
`watchlist/asset/${params.ticker}/price/historical?interval=${params.interval}&start_date=${params.start_date}&end_date=${params.end_date}`,
90+
apiClient.get<ApiResponse<StockHistory[]>>(
91+
`${VALUECELL_BACKEND_URL}/watchlist/asset/${params.ticker}/price/historical?interval=${params.interval}&start_date=${params.start_date}&end_date=${params.end_date}`,
92+
{
93+
requiresAuth: true,
94+
},
8495
),
8596
select: (data) => data.data,
8697
enabled: !!params.ticker,
@@ -91,7 +102,10 @@ export const useGetStockDetail = (params: { ticker: string }) =>
91102
queryKey: API_QUERY_KEYS.STOCK.stockDetail(Object.values(params)),
92103
queryFn: () =>
93104
apiClient.get<ApiResponse<StockDetail>>(
94-
`watchlist/asset/${params.ticker}`,
105+
`${useSystemStore.getState().access_token ? VALUECELL_BACKEND_URL : ""}/watchlist/asset/${params.ticker}`,
106+
{
107+
requiresAuth: !!useSystemStore.getState().access_token,
108+
},
95109
),
96110
select: (data) => data.data,
97111
enabled: !!params.ticker,

frontend/src/api/system.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export interface DefaultTickersResponse {
2424
export const useBackendHealth = () => {
2525
return useQuery({
2626
queryKey: ["backend-health"],
27-
queryFn: () => apiClient.get<boolean>("/healthz/"),
27+
queryFn: () => apiClient.get<boolean>("/healthz"),
2828
retry: false,
2929
refetchInterval: (query) => {
3030
return query.state.status === "error" ? 2000 : 10000;

frontend/src/app/home/components/stock-list.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ function StockList() {
1313
const { data: stockList } = useGetWatchlist();
1414

1515
const stockData = useMemo(() => {
16-
const allStocks = stockList?.flatMap((group) => group.items) ?? [];
17-
return allStocks;
16+
return stockList?.flatMap((group) => group.items) ?? [];
1817
}, [stockList]);
1918

2019
// Extract stock symbol (e.g., AAPL) from path like /stock/AAPL
@@ -30,8 +29,6 @@ function StockList() {
3029
symbol: stock.symbol,
3130
companyName: stock.display_name,
3231
price: stockPrice?.price_formatted ?? "N/A",
33-
currency: stockPrice?.currency ?? "USD",
34-
changeAmount: stockPrice?.change ?? 0,
3532
changePercent: stockPrice?.change_percent,
3633
}),
3734
[stock, stockPrice],

frontend/src/app/home/stock.tsx

Lines changed: 13 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
import BackButton from "@valuecell/button/back-button";
2-
import { memo, useMemo } from "react";
2+
import { memo } from "react";
33
import { useNavigate, useParams } from "react-router";
4-
import {
5-
useGetStockDetail,
6-
useGetStockPrice,
7-
useRemoveStockFromWatchlist,
8-
} from "@/api/stock";
4+
import { useGetStockDetail, useRemoveStockFromWatchlist } from "@/api/stock";
95
import TradingViewAdvancedChart from "@/components/tradingview/tradingview-advanced-chart";
106
import { Button } from "@/components/ui/button";
117
import type { Route } from "./+types/stock";
@@ -16,15 +12,6 @@ function Stock() {
1612
// Use stockId as ticker to fetch real data from API
1713
const ticker = stockId || "";
1814

19-
// Fetch current stock price data
20-
const {
21-
data: stockPriceData,
22-
isLoading: isPriceLoading,
23-
error: priceError,
24-
} = useGetStockPrice({
25-
ticker,
26-
});
27-
2815
// Fetch stock detail data
2916
const {
3017
data: stockDetailData,
@@ -34,36 +21,20 @@ function Stock() {
3421
ticker,
3522
});
3623

37-
const removeStockMutation = useRemoveStockFromWatchlist();
24+
const { mutateAsync: removeStockMutation, isPending: isRemovingStock } =
25+
useRemoveStockFromWatchlist();
3826

3927
const handleRemoveStock = async () => {
4028
try {
41-
await removeStockMutation.mutateAsync(ticker);
29+
await removeStockMutation(ticker);
4230
navigate(-1);
4331
} catch (error) {
4432
console.error("Failed to remove stock from watchlist:", error);
4533
}
4634
};
4735

48-
// Create stock info from API data
49-
const stockInfo = useMemo(() => {
50-
if (!stockPriceData) return null;
51-
52-
// Use display name from detail data if available, otherwise use ticker
53-
const companyName = stockDetailData?.display_name || ticker;
54-
55-
return {
56-
symbol: ticker,
57-
companyName,
58-
price: stockPriceData.price_formatted,
59-
changePercent: stockPriceData.change_percent,
60-
currency: stockPriceData.currency,
61-
changeAmount: stockPriceData.change,
62-
};
63-
}, [stockPriceData, stockDetailData, ticker]);
64-
6536
// Handle loading states
66-
if (isPriceLoading || isDetailLoading) {
37+
if (isDetailLoading) {
6738
return (
6839
<div className="flex h-96 items-center justify-center">
6940
<div className="text-gray-500 text-lg">Loading stock data...</div>
@@ -72,39 +43,31 @@ function Stock() {
7243
}
7344

7445
// Handle error states
75-
if (priceError || detailError) {
46+
if (detailError) {
7647
return (
7748
<div className="flex h-96 items-center justify-center">
7849
<div className="text-lg text-red-500">
79-
Error loading stock data:{" "}
80-
{priceError?.message || detailError?.message}
50+
Error loading stock data: {detailError?.message}
8151
</div>
8252
</div>
8353
);
8454
}
8555

86-
// Handle no data found
87-
if (!stockInfo || !stockPriceData) {
88-
return (
89-
<div className="flex h-96 items-center justify-center">
90-
<div className="text-gray-500 text-lg">Stock {stockId} not found</div>
91-
</div>
92-
);
93-
}
94-
9556
return (
9657
<div className="flex flex-col gap-8 bg-white px-8 py-6">
9758
<div className="flex flex-col gap-4">
9859
<BackButton />
9960
<div className="flex items-center gap-2">
100-
<span className="font-bold text-lg">{stockInfo.companyName}</span>
61+
<span className="font-bold text-lg">
62+
{stockDetailData?.display_name ?? ticker}
63+
</span>
10164
<Button
10265
variant="secondary"
10366
className="ml-auto text-neutral-400"
10467
onClick={handleRemoveStock}
105-
disabled={removeStockMutation.isPending}
68+
disabled={isRemovingStock}
10669
>
107-
{removeStockMutation.isPending ? "Removing..." : "Remove"}
70+
{isRemovingStock ? "Removing..." : "Remove"}
10871
</Button>
10972
</div>
11073
</div>

frontend/src/components/valuecell/menus/stock-menus.tsx

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
import { Link, type LinkProps } from "react-router";
2-
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
32
import { cn, formatChange, getChangeType } from "@/lib/utils";
43
import { useStockColors } from "@/store/settings-store";
5-
import type { StockCurrency } from "@/types/stock";
64

75
interface Stock {
86
symbol: string;
97
companyName: string;
10-
currency: StockCurrency;
118
price: string;
129
changePercent?: number;
1310
icon?: string;
@@ -37,10 +34,6 @@ interface StockMenuGroupHeaderProps
3734
children: React.ReactNode;
3835
}
3936

40-
interface StockIconProps extends React.HTMLAttributes<HTMLDivElement> {
41-
stock: Stock;
42-
}
43-
4437
interface StockMenuListItemProps extends LinkProps {
4538
stock: Stock;
4639
isActive?: boolean;
@@ -96,25 +89,6 @@ function StockMenuGroupHeader({
9689
);
9790
}
9891

99-
function StockIcon({ className, stock, ...props }: StockIconProps) {
100-
return (
101-
<div
102-
className={cn(
103-
"flex size-10 items-center justify-center rounded-full",
104-
className,
105-
)}
106-
{...props}
107-
>
108-
<Avatar className="size-full">
109-
<AvatarImage src={stock.icon} alt={stock.symbol} />
110-
<AvatarFallback className="font-medium text-muted-foreground text-xs">
111-
{stock.symbol.slice(0, 2)}
112-
</AvatarFallback>
113-
</Avatar>
114-
</div>
115-
);
116-
}
117-
11892
function StockMenuListItem({
11993
className,
12094
stock,
@@ -136,9 +110,6 @@ function StockMenuListItem({
136110
{...props}
137111
>
138112
<div className="flex flex-1 items-center gap-2.5 truncate">
139-
{/* icon */}
140-
{/* <StockIcon stock={stock} /> */}
141-
142113
{/* stock info */}
143114
<div className="flex flex-col items-start gap-1">
144115
<p className="font-semibold text-foreground text-sm leading-tight">
@@ -172,5 +143,4 @@ export {
172143
StockMenuGroup,
173144
StockMenuGroupHeader,
174145
StockMenuListItem,
175-
StockIcon,
176146
};

frontend/src/root.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const queryClient = new QueryClient({
3232
staleTime: 5 * 60 * 1000, // Global default 5 minutes fresh time
3333
gcTime: 30 * 60 * 1000, // Global default 30 minutes garbage collection time
3434
refetchOnWindowFocus: false, // Don't refetch on window focus by default
35-
retry: 2, // Default retry 2 times on failure
35+
retry: 1, // Default retry 1 times on failure
3636
},
3737
mutations: {
3838
retry: 1, // Default retry 1 time for mutations

frontend/src/types/stock.ts

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -44,22 +44,12 @@ export type StockInterval =
4444
| "1mo"; // 1 month
4545

4646
export interface StockHistory {
47-
ticker: string;
48-
interval: StockInterval;
49-
prices: {
50-
ticker: string;
51-
price: number;
52-
timestamp: string;
53-
open_price: number;
54-
high_price: number;
55-
low_price: number;
56-
close_price: number;
57-
volume: number;
58-
change: number;
59-
change_percent?: number;
60-
currency: StockCurrency;
61-
source: string;
62-
}[];
47+
time: string;
48+
open: number;
49+
high: number;
50+
low: number;
51+
close: number;
52+
volume: number;
6353
}
6454

6555
export interface StockDetail {

0 commit comments

Comments
 (0)