"use client"; export const dynamic = "force-dynamic"; import { useState } from "react"; import { Permission } from "../../auth-context"; import { adminApi } from "../../api"; import { sharedStyles } from "../../styles/shared"; import { PageLayout } from "../../components/PageLayout"; import { useRequireAuth } from "../../hooks/useRequireAuth"; import { useTranslation } from "../../hooks/useTranslation"; import { useAsyncData } from "../../hooks/useAsyncData"; export default function AdminPriceHistoryPage() { const t = useTranslation("admin"); const { user, isLoading, isAuthorized } = useRequireAuth({ requiredPermission: Permission.VIEW_AUDIT, fallbackRedirect: "/", }); const { data: records = [], isLoading: isLoadingData, error, refetch: fetchRecords, } = useAsyncData(() => adminApi.getPriceHistory(), { enabled: !!user && isAuthorized, initialData: [], }); const [isFetching, setIsFetching] = useState(false); const handleFetchNow = async () => { setIsFetching(true); try { await adminApi.fetchPrice(); await fetchRecords(); } catch (err) { console.error("Failed to fetch price:", err); } finally { setIsFetching(false); } }; const formatDate = (dateStr: string) => { return new Date(dateStr).toLocaleString("es-ES"); }; const formatPrice = (price: number) => { return new Intl.NumberFormat("es-ES", { style: "currency", currency: "EUR", minimumFractionDigits: 2, maximumFractionDigits: 2, }).format(price); }; return (

{t("priceHistory.title")}

{t("priceHistory.recordsCount", { count: records?.length ?? 0 })}
{error && ( )} {!error && isLoadingData && ( )} {!error && !isLoadingData && (records?.length ?? 0) === 0 && ( )} {!error && !isLoadingData && (records ?? []).map((record) => ( ))}
{t("priceHistory.tableHeaders.source")} {t("priceHistory.tableHeaders.pair")} {t("priceHistory.tableHeaders.price")} {t("priceHistory.tableHeaders.timestamp")}
{error}
{t("priceHistory.loading")}
{t("priceHistory.emptyState")}
{record.source} {record.pair} {formatPrice(record.price)} {formatDate(record.timestamp)}
); } const pageStyles: Record = { content: { flex: 1, padding: "2rem", overflowY: "auto", }, tableCard: { background: "rgba(255, 255, 255, 0.03)", backdropFilter: "blur(10px)", border: "1px solid rgba(255, 255, 255, 0.08)", borderRadius: "20px", padding: "1.5rem", boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.5)", maxWidth: "900px", margin: "0 auto", }, tableHeader: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "1rem", flexWrap: "wrap", gap: "1rem", }, tableTitle: { fontFamily: "'Instrument Serif', Georgia, serif", fontSize: "1.5rem", fontWeight: 400, color: "#fff", margin: 0, }, headerActions: { display: "flex", alignItems: "center", gap: "1rem", }, totalCount: { fontFamily: "'DM Sans', system-ui, sans-serif", fontSize: "0.875rem", color: "rgba(255, 255, 255, 0.4)", }, refreshBtn: { fontFamily: "'DM Sans', system-ui, sans-serif", fontSize: "0.875rem", padding: "0.5rem 1rem", background: "rgba(255, 255, 255, 0.08)", border: "1px solid rgba(255, 255, 255, 0.15)", borderRadius: "8px", color: "rgba(255, 255, 255, 0.8)", cursor: "pointer", }, fetchBtn: { fontFamily: "'DM Sans', system-ui, sans-serif", fontSize: "0.875rem", padding: "0.5rem 1rem", background: "linear-gradient(135deg, #a78bfa, #8b5cf6)", border: "none", borderRadius: "8px", color: "#fff", cursor: "pointer", fontWeight: 500, }, tableWrapper: { overflowX: "auto", }, table: { width: "100%", borderCollapse: "collapse", fontFamily: "'DM Sans', system-ui, sans-serif", }, th: { textAlign: "left", padding: "0.75rem 1rem", fontSize: "0.75rem", fontWeight: 600, color: "rgba(255, 255, 255, 0.4)", textTransform: "uppercase", letterSpacing: "0.05em", borderBottom: "1px solid rgba(255, 255, 255, 0.08)", }, tr: { borderBottom: "1px solid rgba(255, 255, 255, 0.04)", }, td: { padding: "0.875rem 1rem", fontSize: "0.875rem", color: "rgba(255, 255, 255, 0.7)", }, tdPrice: { padding: "0.875rem 1rem", fontSize: "1rem", color: "#fbbf24", fontWeight: 600, fontFamily: "'DM Mono', monospace", }, tdDate: { padding: "0.875rem 1rem", fontSize: "0.75rem", color: "rgba(255, 255, 255, 0.4)", }, emptyRow: { padding: "2rem 1rem", textAlign: "center", color: "rgba(255, 255, 255, 0.3)", fontSize: "0.875rem", }, errorRow: { padding: "2rem 1rem", textAlign: "center", color: "#f87171", fontSize: "0.875rem", }, }; const styles = { ...sharedStyles, ...pageStyles };