feat(analysis): add monthly variation table with inflation comparison

- New backend endpoint GET /api/quotes/monthly-last
- MonthlyVariationTable component with BELO/Blue/Oficial % changes
- Inflation data from ArgentinaDatos API with 24h cache
- Visual indicators: green if beats inflation, red if below
- Responsive: cards on mobile, table on desktop
This commit is contained in:
Jose Selesan
2026-08-27 10:13:56 -03:00
parent a6e95f0c05
commit 66ab56b46a
6 changed files with 389 additions and 0 deletions

View File

@@ -0,0 +1,28 @@
import type { Context } from "hono";
import { cache } from "../../../lib/cache";
import { prisma } from "../../../lib/prisma";
export async function getMonthlyLast(c: Context) {
const cacheKey = "quotes:monthly-last";
const cached = cache.get(cacheKey);
if (cached) return c.json(cached);
const rows = await prisma.$queryRaw<
Array<{
month: string;
type: string;
buy: number;
}>
>`
SELECT
TO_CHAR(DATE_TRUNC('month', "timeStamp"), 'YYYY-MM') AS month,
"type"::text,
(ARRAY_AGG(buy ORDER BY "timeStamp" DESC))[1]::numeric::float8 AS buy
FROM "quotes_history"
GROUP BY DATE_TRUNC('month', "timeStamp"), "type"
ORDER BY month ASC
`;
cache.set(cacheKey, rows, 300);
return c.json(rows);
}

View File

@@ -4,12 +4,14 @@ import { getCurrentQuotes } from "./handlers/getCurrentQuotes";
import { getDailyMinMax } from "./handlers/getDailyMinMax";
import { getDailyQuotes } from "./handlers/getDailyQuotes";
import { getHistoricalMinMax } from "./handlers/getHistoricalMinMax";
import { getMonthlyLast } from "./handlers/getMonthlyLast";
import { getQuoteHistory } from "./handlers/getQuoteHistory";
import { quoteEvents } from "./handlers/quoteEvents";
const app = new Hono();
app.get("/", getCurrentQuotes);
app.get("/monthly-last", getMonthlyLast);
app.get("/:type/history", getQuoteHistory);
app.get("/:type/daily", getDailyQuotes);
app.get("/:type/min-max", getDailyMinMax);