fix(stock-price): ignore missing data points in price history (#4429)
Co-authored-by: Meier Lukas <meierschlumpf@gmail.com>
This commit is contained in:
@@ -20,11 +20,19 @@ export const fetchStockPriceHandler = createCachedWidgetRequestHandler({
|
|||||||
if (data.chart.result.length !== 1) {
|
if (data.chart.result.length !== 1) {
|
||||||
throw new Error("Received multiple results");
|
throw new Error("Received multiple results");
|
||||||
}
|
}
|
||||||
if (!data.chart.result[0]) {
|
const firstResult = data.chart.result[0];
|
||||||
|
if (!firstResult) {
|
||||||
throw new Error("Received invalid data");
|
throw new Error("Received invalid data");
|
||||||
}
|
}
|
||||||
|
return {
|
||||||
return data.chart.result[0];
|
priceHistory:
|
||||||
|
firstResult.indicators.quote[0]?.close.filter(
|
||||||
|
// Filter out null values from price arrays (Yahoo Finance returns null for missing data points)
|
||||||
|
(value) => value !== null && value !== undefined,
|
||||||
|
) ?? [],
|
||||||
|
symbol: firstResult.meta.symbol,
|
||||||
|
shortName: firstResult.meta.shortName,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
cacheDuration: dayjs.duration(5, "minutes"),
|
cacheDuration: dayjs.duration(5, "minutes"),
|
||||||
});
|
});
|
||||||
@@ -43,7 +51,7 @@ const dataSchema = z
|
|||||||
indicators: z.object({
|
indicators: z.object({
|
||||||
quote: z.array(
|
quote: z.array(
|
||||||
z.object({
|
z.object({
|
||||||
close: z.array(z.number()),
|
close: z.array(z.number().nullish()),
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -26,15 +26,13 @@ export default function StockPriceWidget({ options, width, height }: WidgetCompo
|
|||||||
const theme = useMantineTheme();
|
const theme = useMantineTheme();
|
||||||
const [{ data }] = clientApi.widget.stockPrice.getPriceHistory.useSuspenseQuery(options);
|
const [{ data }] = clientApi.widget.stockPrice.getPriceHistory.useSuspenseQuery(options);
|
||||||
|
|
||||||
const stockValues = data.indicators.quote[0]?.close ?? [];
|
const stockValuesChange = round(calculateChange(data.priceHistory.at(-1) ?? 0, data.priceHistory[0] ?? 0));
|
||||||
|
|
||||||
const stockValuesChange = round(calculateChange(stockValues[stockValues.length - 1] ?? 0, stockValues[0] ?? 0));
|
|
||||||
const stockValuesChangePercentage = round(
|
const stockValuesChangePercentage = round(
|
||||||
calculateChangePercentage(stockValues[stockValues.length - 1] ?? 0, stockValues[0] ?? 0),
|
calculateChangePercentage(data.priceHistory.at(-1) ?? 0, data.priceHistory[0] ?? 0),
|
||||||
);
|
);
|
||||||
|
|
||||||
const stockValuesMin = Math.min(...stockValues);
|
const stockValuesMin = Math.min(...data.priceHistory);
|
||||||
const stockGraphValues = stockValues.map((value) => value - stockValuesMin + 50);
|
const stockGraphValues = data.priceHistory.map((value) => value - stockValuesMin + 50);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex h="100%" w="100%">
|
<Flex h="100%" w="100%">
|
||||||
@@ -57,17 +55,17 @@ export default function StockPriceWidget({ options, width, height }: WidgetCompo
|
|||||||
) : (
|
) : (
|
||||||
<IconTrendingDown size="1.5rem" color={theme.colors.red[7]} />
|
<IconTrendingDown size="1.5rem" color={theme.colors.red[7]} />
|
||||||
)}
|
)}
|
||||||
{data.meta.symbol}
|
{data.symbol}
|
||||||
</Text>
|
</Text>
|
||||||
{width > 280 && height > 280 && (
|
{width > 280 && height > 280 && (
|
||||||
<Text size="md" lh="1">
|
<Text size="md" lh="1">
|
||||||
{data.meta.shortName}
|
{data.shortName}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Title pos="absolute" bottom={10} right={10} order={width > 280 ? 1 : 2} fw={700}>
|
<Title pos="absolute" bottom={10} right={10} order={width > 280 ? 1 : 2} fw={700}>
|
||||||
{new Intl.NumberFormat().format(round(stockValues[stockValues.length - 1] ?? 0))}
|
{new Intl.NumberFormat().format(round(data.priceHistory.at(-1) ?? 0))}
|
||||||
</Title>
|
</Title>
|
||||||
|
|
||||||
{width > 280 && (
|
{width > 280 && (
|
||||||
@@ -90,11 +88,11 @@ export default function StockPriceWidget({ options, width, height }: WidgetCompo
|
|||||||
) : (
|
) : (
|
||||||
<IconTrendingDown size="1.5rem" color={theme.colors.red[7]} />
|
<IconTrendingDown size="1.5rem" color={theme.colors.red[7]} />
|
||||||
)}
|
)}
|
||||||
{data.meta.symbol}
|
{data.symbol}
|
||||||
</Text>
|
</Text>
|
||||||
{width > 280 && height > 280 && (
|
{width > 280 && height > 280 && (
|
||||||
<Text size="md" lh="1">
|
<Text size="md" lh="1">
|
||||||
{data.meta.shortName}
|
{data.shortName}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
Reference in New Issue
Block a user