Files
iddaai-fe/src/components/matches/match-detail-content.tsx
T
2026-04-24 00:27:14 +03:00

286 lines
8.8 KiB
TypeScript

"use client";
import {
Box,
Flex,
Text,
Heading,
Badge,
VStack,
HStack,
Image,
Spinner,
Button,
Card,
} from "@chakra-ui/react";
import { useTranslations } from "next-intl";
import { useParams, useRouter } from "next/navigation";
import { useColorModeValue } from "@/components/ui/color-mode";
import { SlideUp } from "@/components/motion";
import { useMatchDetails } from "@/lib/api/matches/use-hooks";
import { usePrediction } from "@/lib/api/predictions/use-hooks";
import PredictionCard from "@/components/matches/prediction-card";
import OddsCard from "@/components/matches/odds-card";
import LineupsCard from "@/components/matches/lineups-card";
import { LuArrowLeft, LuRefreshCw } from "react-icons/lu";
export default function MatchDetailContent() {
const t = useTranslations("matches");
const tPred = useTranslations("predictions");
const tCommon = useTranslations("common");
const params = useParams();
const router = useRouter();
const matchId = params.id as string;
const { data: matchData, isLoading: matchLoading } = useMatchDetails(matchId);
const {
data: predictionData,
isLoading: predLoading,
refetch: refetchPrediction,
} = usePrediction(matchId);
const headerBg = useColorModeValue("white", "gray.800");
const borderColor = useColorModeValue("gray.100", "gray.700");
const match = matchData?.data;
const prediction = predictionData?.data;
if (matchLoading) {
return (
<Flex justify="center" align="center" py={20}>
<Spinner size="lg" color="primary.500" />
</Flex>
);
}
if (!match) {
return (
<Flex justify="center" align="center" py={20} direction="column" gap={4}>
<Text color="fg.muted" fontSize="lg">
{t("no-matches")}
</Text>
<Button variant="outline" onClick={() => router.back()}>
<LuArrowLeft />
{tCommon("back")}
</Button>
</Flex>
);
}
const isLive = match.status === "LIVE";
const isFinished = match.status === "Finished";
return (
<SlideUp>
<Box>
{/* Back Button */}
<Button
variant="ghost"
size="sm"
mb={4}
onClick={() => router.back()}
gap={1.5}
>
<LuArrowLeft />
{tCommon("back")}
</Button>
{/* Match Header */}
<Card.Root
bg={headerBg}
borderColor={borderColor}
borderRadius="xl"
mb={6}
>
<Card.Body>
{/* League Info */}
{match.league && (
<Flex justify="center" align="center" gap={2} mb={4}>
{match.league.country?.flag && (
<Image
src={match.league.country.flag}
alt={match.league.country.name || ""}
boxSize="18px"
objectFit="contain"
/>
)}
<Text fontSize="sm" color="fg.muted" fontWeight="medium">
{match.league.name}
</Text>
<Badge
colorPalette={isLive ? "red" : isFinished ? "gray" : "green"}
variant="subtle"
fontSize="xs"
borderRadius="full"
>
{isLive && (
<Box
as="span"
display="inline-block"
w="6px"
h="6px"
borderRadius="full"
bg="red.500"
mr={1}
animation="pulse 1.5s ease-in-out infinite"
/>
)}
{isLive
? t("live")
: isFinished
? t("finished")
: t("not-started")}
</Badge>
</Flex>
)}
{/* Teams & Score */}
<HStack gap={6} justify="center" align="center">
{/* Home Team */}
<VStack gap={2} flex={1} align="center">
{match.homeTeam?.logo ? (
<Image
src={match.homeTeam.logo}
alt={match.homeTeam.name}
boxSize="64px"
objectFit="contain"
/>
) : (
<Flex
boxSize="64px"
bg="primary.subtle"
borderRadius="full"
align="center"
justify="center"
>
<Text fontSize="2xl" fontWeight="bold" color="primary.fg">
{match.homeTeam?.name?.charAt(0) || "H"}
</Text>
</Flex>
)}
<Text fontSize="md" fontWeight="bold" textAlign="center">
{match.homeTeam?.name}
</Text>
<Text fontSize="xs" color="fg.muted">
{t("home-team")}
</Text>
</VStack>
{/* Score */}
<VStack gap={1} flexShrink={0}>
{match.score && (isLive || isFinished) ? (
<HStack gap={3}>
<Text
fontSize="4xl"
fontWeight="900"
color={isLive ? "red.500" : "fg"}
>
{match.score.home}
</Text>
<Text fontSize="2xl" color="fg.muted">
-
</Text>
<Text
fontSize="4xl"
fontWeight="900"
color={isLive ? "red.500" : "fg"}
>
{match.score.away}
</Text>
</HStack>
) : (
<Text fontSize="xl" fontWeight="bold" color="fg.muted">
{t("vs")}
</Text>
)}
<Text fontSize="xs" color="fg.muted">
{new Date(match.mstUtc).toLocaleDateString("tr-TR", {
weekday: "short",
day: "2-digit",
month: "short",
year: "numeric",
hour: "2-digit",
minute: "2-digit",
})}
</Text>
</VStack>
{/* Away Team */}
<VStack gap={2} flex={1} align="center">
{match.awayTeam?.logo ? (
<Image
src={match.awayTeam.logo}
alt={match.awayTeam.name}
boxSize="64px"
objectFit="contain"
/>
) : (
<Flex
boxSize="64px"
bg="primary.subtle"
borderRadius="full"
align="center"
justify="center"
>
<Text fontSize="2xl" fontWeight="bold" color="primary.fg">
{match.awayTeam?.name?.charAt(0) || "A"}
</Text>
</Flex>
)}
<Text fontSize="md" fontWeight="bold" textAlign="center">
{match.awayTeam?.name}
</Text>
<Text fontSize="xs" color="fg.muted">
{t("away-team")}
</Text>
</VStack>
</HStack>
</Card.Body>
</Card.Root>
{/* Lineups Section */}
<LineupsCard match={match} prediction={prediction} />
{/* Prediction Section */}
<Box>
<Flex justify="space-between" align="center" mb={4}>
<Heading as="h2" size="lg">
{tPred("title")}
</Heading>
<Button
variant="outline"
size="sm"
onClick={() => refetchPrediction()}
gap={1.5}
>
<LuRefreshCw />
{tCommon("refresh")}
</Button>
</Flex>
{predLoading ? (
<Flex justify="center" py={10}>
<Spinner size="md" color="primary.500" />
</Flex>
) : prediction ? (
<PredictionCard prediction={prediction} />
) : (
<Card.Root borderColor={borderColor} borderRadius="xl">
<Card.Body>
<Flex justify="center" align="center" py={8}>
<Text color="fg.muted">{tPred("no-predictions")}</Text>
</Flex>
</Card.Body>
</Card.Root>
)}
</Box>
{/* Odds Section */}
{match.odds && Object.keys(match.odds).length > 0 && (
<OddsCard odds={match.odds} />
)}
</Box>
</SlideUp>
);
}