"use client"; import { useEffect, useState, useCallback } from "react"; import { Permission } from "../../auth-context"; import { api } from "../../api"; import { sharedStyles } from "../../styles/shared"; import { Header } from "../../components/Header"; import { useRequireAuth } from "../../hooks/useRequireAuth"; import { components } from "../../generated/api"; type RandomNumberOutcome = components["schemas"]["RandomNumberOutcomeResponse"]; export default function AdminRandomJobsPage() { const [outcomes, setOutcomes] = useState([]); const [error, setError] = useState(null); const [isLoadingData, setIsLoadingData] = useState(true); const { user, isLoading, isAuthorized } = useRequireAuth({ requiredPermission: Permission.VIEW_AUDIT, fallbackRedirect: "/", }); const fetchOutcomes = useCallback(async () => { setError(null); try { const data = await api.get("/api/audit/random-jobs"); setOutcomes(data); } catch (err) { setOutcomes([]); setError(err instanceof Error ? err.message : "Failed to load outcomes"); } finally { setIsLoadingData(false); } }, []); useEffect(() => { if (user && isAuthorized) { fetchOutcomes(); } }, [user, isAuthorized, fetchOutcomes]); const formatDate = (dateStr: string) => { return new Date(dateStr).toLocaleString(); }; if (isLoading) { return (
Loading...
); } if (!user || !isAuthorized) { return null; } return (

Random Number Job Outcomes

{outcomes.length} outcomes
{error && ( )} {!error && isLoadingData && ( )} {!error && !isLoadingData && outcomes.length === 0 && ( )} {!error && !isLoadingData && outcomes.map((outcome) => ( ))}
ID Job ID Triggered By Value Duration Status Created At
{error}
Loading...
No job outcomes yet
{outcome.id} {outcome.job_id} {outcome.triggered_by_email} {outcome.value} {outcome.duration_ms}ms {outcome.status} {formatDate(outcome.created_at)}
); } 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: "1200px", margin: "0 auto", }, tableHeader: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "1rem", }, tableTitle: { fontFamily: "'Instrument Serif', Georgia, serif", fontSize: "1.5rem", fontWeight: 400, color: "#fff", margin: 0, }, totalCount: { fontFamily: "'DM Sans', system-ui, sans-serif", fontSize: "0.875rem", color: "rgba(255, 255, 255, 0.4)", }, 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)", }, tdNum: { padding: "0.875rem 1rem", fontSize: "0.875rem", color: "rgba(255, 255, 255, 0.9)", fontFamily: "'DM Mono', monospace", }, tdValue: { padding: "0.875rem 1rem", fontSize: "1rem", color: "#a78bfa", fontWeight: 600, fontFamily: "'DM Mono', monospace", }, tdDate: { padding: "0.875rem 1rem", fontSize: "0.75rem", color: "rgba(255, 255, 255, 0.4)", }, statusBadge: { fontFamily: "'DM Sans', system-ui, sans-serif", fontSize: "0.7rem", fontWeight: 500, padding: "0.25rem 0.5rem", borderRadius: "4px", textTransform: "uppercase", background: "rgba(34, 197, 94, 0.2)", color: "rgba(34, 197, 94, 0.9)", }, 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 };