"use client";
import {
Box,
Flex,
Heading,
Text,
SimpleGrid,
Card,
VStack,
HStack,
Badge,
Button,
} from "@chakra-ui/react";
import { useTranslations } from "next-intl";
import { useColorModeValue } from "@/components/ui/color-mode";
import { SlideUp, StaggerContainer, StaggerItem, ScrollSlideUp } from "@/components/motion";
import { Skeleton } from "@/components/ui/feedback/skeleton";
import { MatchCard } from "@/components/matches";
import { useQueryMatches } from "@/lib/api/matches/use-hooks";
import {
useUpcomingPredictions,
useValueBets,
} from "@/lib/api/predictions/use-hooks";
import { useUserBettingStats } from "@/lib/api/coupons/use-hooks";
import { useSession } from "next-auth/react";
import { LuTrendingUp, LuTarget, LuTicket, LuChartBar } from "react-icons/lu";
import { useRouter } from "next/navigation";
import type { LeagueWithMatchesDto, MatchResponseDto } from "@/lib/api/matches/types";
import type { MatchPredictionDto, ValueBetDto } from "@/lib/api/predictions/types";
// ========================
// Stats Card
// ========================
interface StatCardProps {
label: string;
value: string | number;
icon: React.ReactNode;
colorPalette?: string;
}
function StatCard({
label,
value,
icon,
colorPalette = "primary",
}: StatCardProps) {
const cardBg = useColorModeValue(
"rgba(255, 255, 255, 0.75)",
"rgba(26, 32, 44, 0.65)",
);
const borderColor = useColorModeValue(
"rgba(255, 255, 255, 0.8)",
"rgba(255, 255, 255, 0.06)",
);
return (
{icon}
{value}
{label}
);
}
// ========================
// Value Bet Mini Card
// ========================
interface ValueBetMiniCardProps {
matchName: string;
prediction: string;
odd: number;
expectedValue: number;
confidence: number;
}
function ValueBetMiniCard({
matchName,
prediction,
odd,
expectedValue,
confidence,
}: ValueBetMiniCardProps) {
const cardBg = useColorModeValue("white", "gray.800");
const borderColor = useColorModeValue("gray.100", "gray.700");
return (
{matchName}
{prediction}
EV+ {(expectedValue * 100).toFixed(0)}%
{odd.toFixed(2)}
);
}
// ========================
// Dashboard Content
// ========================
export default function DashboardContent() {
const t = useTranslations("dashboard");
const tCoupons = useTranslations("coupons");
const router = useRouter();
const { data: session } = useSession();
const cardBg = useColorModeValue("white", "gray.800");
const borderColor = useColorModeValue("gray.100", "gray.700");
// Data fetching
const queryMatches = useQueryMatches();
const { data: upcomingData, isLoading: upcomingLoading } =
useUpcomingPredictions();
const { data: valueBetsData, isLoading: valueBetsLoading } = useValueBets();
const { data: statsData, isLoading: statsLoading } = useUserBettingStats();
// Trigger match fetch for today
if (!queryMatches.data && !queryMatches.isPending) {
queryMatches.mutate({ sport: "football", limit: 20 });
}
const todayMatches: MatchResponseDto[] = queryMatches.data?.data?.flatMap((l: LeagueWithMatchesDto) => l.matches) ?? [];
const upcomingPredictions: MatchPredictionDto[] = upcomingData?.data?.matches ?? [];
const valueBets: ValueBetDto[] = valueBetsData?.data ?? [];
const userStats = statsData?.data;
const userName = session?.user?.name || "";
return (
{/* Welcome Header */}
{t("title")}
{userName && (
{t("welcome")},{" "}
{userName}
{" "}
👋
)}
{/* Stats Grid */}
}
colorPalette="primary"
/>
}
colorPalette="green"
/>
}
colorPalette="teal"
/>
}
colorPalette="yellow"
/>
{/* Two Column Layout */}
{/* Left Column — Today's Matches */}
{t("todays-matches")}
{queryMatches.isPending ? (
{Array.from({ length: 4 }).map((_, i) => (
))}
) : todayMatches.length > 0 ? (
{todayMatches.slice(0, 6).map((match: MatchResponseDto) => (
))}
) : (
{t("no-matches")}
)}
{/* Right Column — Predictions & Value Bets */}
{/* Upcoming Predictions */}
{t("upcoming-predictions")}
{upcomingLoading ? (
{Array.from({ length: 3 }).map((_, i) => (
))}
) : upcomingPredictions.length > 0 ? (
{upcomingPredictions.slice(0, 4).map((pred: MatchPredictionDto, idx: number) => (
router.push(`/matches/${pred.match_info.match_id}`)
}
>
{pred.match_info.home_team} vs{" "}
{pred.match_info.away_team}
{pred.main_pick && (
{pred.main_pick.pick}
{Math.round(
pred.main_pick.calibrated_confidence ??
pred.main_pick.confidence,
)}
%
)}
))}
) : (
{t("no-predictions")}
)}
{/* Value Bets */}
{t("value-bets")}
{valueBetsLoading ? (
{Array.from({ length: 3 }).map((_, i) => (
))}
) : valueBets.length > 0 ? (
{valueBets.slice(0, 5).map((vb: ValueBetDto, idx: number) => (
))}
) : (
{t("no-predictions")}
)}
);
}