modified layout and made it so you can switch between card modals and keep the pricing chart

This commit is contained in:
zach
2026-03-16 11:05:10 -04:00
parent 9c81a13c69
commit c4ebbfb060
4 changed files with 323 additions and 346 deletions

View File

@@ -8,7 +8,6 @@ export const prerender = false;
export const GET: APIRoute = async ({ url }) => {
const cardId = Number(url.searchParams.get('cardId')) || 0;
// Get all skus for this card
const cardSkus = await db
.select()
.from(skus)
@@ -20,8 +19,7 @@ export const GET: APIRoute = async ({ url }) => {
const skuIds = cardSkus.map(s => s.skuId);
// Fetch price history for all skus
const history = await db
const historyRows = await db
.select({
skuId: priceHistory.skuId,
calculatedAt: priceHistory.calculatedAt,
@@ -33,7 +31,41 @@ export const GET: APIRoute = async ({ url }) => {
.where(inArray(priceHistory.skuId, skuIds))
.orderBy(priceHistory.calculatedAt);
return new Response(JSON.stringify(history), {
// Rolling 30-day cutoff for volatility
const thirtyDaysAgo = new Date(Date.now() - 30 * 86_400_000);
const byCondition: Record<string, number[]> = {};
for (const row of historyRows) {
if (row.marketPrice == null) continue;
if (!row.calculatedAt) continue;
if (new Date(row.calculatedAt) < thirtyDaysAgo) continue;
const price = Number(row.marketPrice);
if (price <= 0) continue;
if (!byCondition[row.condition]) byCondition[row.condition] = [];
byCondition[row.condition].push(price);
}
function computeVolatility(prices: number[]): { label: string; monthlyVol: number } {
if (prices.length < 2) return { label: '—', monthlyVol: 0 };
const returns: number[] = [];
for (let i = 1; i < prices.length; i++) {
returns.push(Math.log(prices[i] / prices[i - 1]));
}
const mean = returns.reduce((a, b) => a + b, 0) / returns.length;
const variance = returns.reduce((sum, r) => sum + (r - mean) ** 2, 0) / (returns.length - 1);
const monthlyVol = Math.sqrt(variance) * Math.sqrt(30);
const label = monthlyVol >= 0.30 ? 'High'
: monthlyVol >= 0.15 ? 'Medium'
: 'Low';
return { label, monthlyVol: Math.round(monthlyVol * 100) / 100 };
}
const volatilityByCondition: Record<string, { label: string; monthlyVol: number }> = {};
for (const [condition, prices] of Object.entries(byCondition)) {
volatilityByCondition[condition] = computeVolatility(prices);
}
return new Response(JSON.stringify({ history: historyRows, volatilityByCondition }), {
headers: { 'Content-Type': 'application/json' }
});
};