@@ -21,10 +21,20 @@ import { useColorModeValue } from "@/components/ui/color-mode";
|
||||
import { SlideUp, FadeIn } from "@/components/motion";
|
||||
import { useMatchDetails } from "@/lib/api/matches/use-hooks";
|
||||
import { usePrediction } from "@/lib/api/predictions/use-hooks";
|
||||
import { useGetMe } from "@/lib/api/users/use-hooks";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { UsersQueryKeys } from "@/lib/api/users/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, LuShield, LuFlag, LuUser } from "react-icons/lu";
|
||||
import {
|
||||
LuArrowLeft,
|
||||
LuRefreshCw,
|
||||
LuShield,
|
||||
LuFlag,
|
||||
LuUser,
|
||||
LuSparkles,
|
||||
} from "react-icons/lu";
|
||||
import type { MatchResponseDto } from "@/lib/api/matches/types";
|
||||
|
||||
// ─────────────────────────────────────────────────
|
||||
@@ -60,6 +70,10 @@ interface SidelinedData {
|
||||
export default function MatchDetailContent() {
|
||||
const t = useTranslations("matches");
|
||||
const tPred = useTranslations("predictions");
|
||||
const queryClient = useQueryClient();
|
||||
const { data: meData } = useGetMe();
|
||||
const usageLimit = meData?.data?.usageLimit;
|
||||
const hasLimit = usageLimit ? (usageLimit.maxAnalyses - usageLimit.analysisCount > 0) : true;
|
||||
const tCommon = useTranslations("common");
|
||||
const params = useParams();
|
||||
const router = useRouter();
|
||||
@@ -70,9 +84,16 @@ export default function MatchDetailContent() {
|
||||
const {
|
||||
data: predictionData,
|
||||
isLoading: predLoading,
|
||||
refetch: refetchPrediction,
|
||||
refetch: refetchPredictionRaw,
|
||||
isFetching: isPredFetching,
|
||||
} = usePrediction(matchId);
|
||||
|
||||
const refetchPrediction = async () => {
|
||||
await refetchPredictionRaw();
|
||||
// After refetching, update the limits in the header
|
||||
queryClient.invalidateQueries({ queryKey: UsersQueryKeys.me() });
|
||||
};
|
||||
|
||||
const headerBg = useColorModeValue("white", "gray.800");
|
||||
const cardBg = useColorModeValue("white", "gray.800");
|
||||
const borderColor = useColorModeValue("gray.100", "gray.700");
|
||||
@@ -139,7 +160,13 @@ export default function MatchDetailContent() {
|
||||
>
|
||||
{/* League Banner */}
|
||||
{match.league && (
|
||||
<Box bg={subtleBg} px={4} py={2.5} borderBottomWidth="1px" borderColor={borderColor}>
|
||||
<Box
|
||||
bg={subtleBg}
|
||||
px={4}
|
||||
py={2.5}
|
||||
borderBottomWidth="1px"
|
||||
borderColor={borderColor}
|
||||
>
|
||||
<Flex justify="center" align="center" gap={2}>
|
||||
{match.league.country?.flag && (
|
||||
<Image
|
||||
@@ -151,7 +178,8 @@ export default function MatchDetailContent() {
|
||||
/>
|
||||
)}
|
||||
<Text fontSize="sm" fontWeight="semibold" color="fg.muted">
|
||||
{match.league.country?.name && `${match.league.country.name} • `}
|
||||
{match.league.country?.name &&
|
||||
`${match.league.country.name} • `}
|
||||
{match.league.name}
|
||||
</Text>
|
||||
<Badge
|
||||
@@ -300,7 +328,10 @@ export default function MatchDetailContent() {
|
||||
>
|
||||
<LuUser size={14} />
|
||||
<Text fontSize="xs" color="fg.muted">
|
||||
{t("referee")}: <Text as="span" fontWeight="semibold" color="fg">{match.refereeName}</Text>
|
||||
{t("referee")}:{" "}
|
||||
<Text as="span" fontWeight="semibold" color="fg">
|
||||
{match.refereeName}
|
||||
</Text>
|
||||
</Text>
|
||||
</Flex>
|
||||
)}
|
||||
@@ -312,7 +343,12 @@ export default function MatchDetailContent() {
|
||||
{/* ═══════════════════════════════════════════ */}
|
||||
{hasSidelined && (
|
||||
<FadeIn>
|
||||
<Card.Root bg={cardBg} borderColor={borderColor} borderRadius="xl" mb={6}>
|
||||
<Card.Root
|
||||
bg={cardBg}
|
||||
borderColor={borderColor}
|
||||
borderRadius="xl"
|
||||
mb={6}
|
||||
>
|
||||
<Card.Body>
|
||||
<Heading as="h2" size="md" mb={4}>
|
||||
🏥 {t("sidelined")}
|
||||
@@ -361,6 +397,7 @@ export default function MatchDetailContent() {
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => refetchPrediction()}
|
||||
disabled={!hasLimit}
|
||||
gap={1.5}
|
||||
>
|
||||
<LuRefreshCw />
|
||||
@@ -368,7 +405,7 @@ export default function MatchDetailContent() {
|
||||
</Button>
|
||||
</Flex>
|
||||
|
||||
{predLoading ? (
|
||||
{predLoading || isPredFetching ? (
|
||||
<Flex justify="center" py={10}>
|
||||
<Spinner size="md" color="primary.500" />
|
||||
</Flex>
|
||||
@@ -377,8 +414,21 @@ export default function MatchDetailContent() {
|
||||
) : (
|
||||
<Card.Root borderColor={borderColor} borderRadius="xl">
|
||||
<Card.Body>
|
||||
<Flex justify="center" align="center" py={8}>
|
||||
<Text color="fg.muted">{tPred("no-predictions")}</Text>
|
||||
<Flex direction="column" justify="center" align="center" py={8} gap={4}>
|
||||
<Text color="fg.muted">{tPred("no-predictions", { defaultValue: "Tahmin bulunmuyor." })}</Text>
|
||||
<Button
|
||||
colorPalette="primary"
|
||||
onClick={() => refetchPrediction()}
|
||||
disabled={!hasLimit}
|
||||
loading={isPredFetching}
|
||||
>
|
||||
<LuSparkles /> {tPred("generate", { defaultValue: "Yapay Zeka ile Analiz Et" })}
|
||||
</Button>
|
||||
{!hasLimit && (
|
||||
<Text fontSize="sm" color="red.500">
|
||||
{tCommon("limits.out_of_analysis", { defaultValue: "Günlük analiz limitiniz doldu." })}
|
||||
</Text>
|
||||
)}
|
||||
</Flex>
|
||||
</Card.Body>
|
||||
</Card.Root>
|
||||
@@ -409,15 +459,31 @@ interface SidelinedColumnProps {
|
||||
t: ReturnType<typeof useTranslations>;
|
||||
}
|
||||
|
||||
function SidelinedColumn({ team, teamName, teamLogo, injuryBg, injuryBorder, t }: SidelinedColumnProps) {
|
||||
function SidelinedColumn({
|
||||
team,
|
||||
teamName,
|
||||
teamLogo,
|
||||
injuryBg,
|
||||
injuryBorder,
|
||||
t,
|
||||
}: SidelinedColumnProps) {
|
||||
const players = team?.players || [];
|
||||
|
||||
if (players.length === 0) {
|
||||
return (
|
||||
<Box>
|
||||
<HStack gap={2} mb={3}>
|
||||
{teamLogo && <Image src={teamLogo} alt={teamName} boxSize="20px" objectFit="contain" />}
|
||||
<Text fontSize="sm" fontWeight="bold">{teamName}</Text>
|
||||
{teamLogo && (
|
||||
<Image
|
||||
src={teamLogo}
|
||||
alt={teamName}
|
||||
boxSize="20px"
|
||||
objectFit="contain"
|
||||
/>
|
||||
)}
|
||||
<Text fontSize="sm" fontWeight="bold">
|
||||
{teamName}
|
||||
</Text>
|
||||
</HStack>
|
||||
<Text fontSize="xs" color="fg.muted" fontStyle="italic">
|
||||
{t("no-sidelined")}
|
||||
@@ -429,9 +495,23 @@ function SidelinedColumn({ team, teamName, teamLogo, injuryBg, injuryBorder, t }
|
||||
return (
|
||||
<Box>
|
||||
<HStack gap={2} mb={3}>
|
||||
{teamLogo && <Image src={teamLogo} alt={teamName} boxSize="20px" objectFit="contain" />}
|
||||
<Text fontSize="sm" fontWeight="bold">{teamName}</Text>
|
||||
<Badge colorPalette="red" variant="subtle" fontSize="2xs" borderRadius="full">
|
||||
{teamLogo && (
|
||||
<Image
|
||||
src={teamLogo}
|
||||
alt={teamName}
|
||||
boxSize="20px"
|
||||
objectFit="contain"
|
||||
/>
|
||||
)}
|
||||
<Text fontSize="sm" fontWeight="bold">
|
||||
{teamName}
|
||||
</Text>
|
||||
<Badge
|
||||
colorPalette="red"
|
||||
variant="subtle"
|
||||
fontSize="2xs"
|
||||
borderRadius="full"
|
||||
>
|
||||
{players.length}
|
||||
</Badge>
|
||||
</HStack>
|
||||
@@ -458,21 +538,21 @@ function SidelinedColumn({ team, teamName, teamLogo, injuryBg, injuryBorder, t }
|
||||
</Badge>
|
||||
)}
|
||||
<Text fontSize="xs" color="fg.muted">
|
||||
{player.description || (
|
||||
player.type === "injury"
|
||||
{player.description ||
|
||||
(player.type === "injury"
|
||||
? t("injury")
|
||||
: player.type === "suspended"
|
||||
? t("suspended")
|
||||
: t("other-reason")
|
||||
)}
|
||||
: t("other-reason"))}
|
||||
</Text>
|
||||
</HStack>
|
||||
</VStack>
|
||||
{player.matchesMissed !== undefined && player.matchesMissed > 0 && (
|
||||
<Badge colorPalette="red" variant="subtle" fontSize="2xs">
|
||||
{player.matchesMissed} {t("matches-missed")}
|
||||
</Badge>
|
||||
)}
|
||||
{player.matchesMissed !== undefined &&
|
||||
player.matchesMissed > 0 && (
|
||||
<Badge colorPalette="red" variant="subtle" fontSize="2xs">
|
||||
{player.matchesMissed} {t("matches-missed")}
|
||||
</Badge>
|
||||
)}
|
||||
</Flex>
|
||||
</Box>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user