feat: AI commentary skeleton loading - separate async endpoint
Deploy Iddaai Frontend / build-and-deploy (push) Successful in 2m20s
Deploy Iddaai Frontend / build-and-deploy (push) Successful in 2m20s
This commit is contained in:
@@ -20,7 +20,7 @@ import { useState } from "react";
|
||||
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 { usePrediction, useAiCommentary } 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";
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
LuRefreshCw,
|
||||
LuUser,
|
||||
LuSparkles,
|
||||
LuBrain,
|
||||
LuInfo,
|
||||
LuChevronDown,
|
||||
LuChevronUp,
|
||||
@@ -142,6 +143,11 @@ export default function MatchDetailContent() {
|
||||
isFetching: isPredFetching,
|
||||
} = usePrediction(matchId);
|
||||
|
||||
const { data: commentaryData, isLoading: commentaryLoading } = useAiCommentary(
|
||||
matchId,
|
||||
!!predictionData?.data, // prediction yüklendikten sonra başlat
|
||||
);
|
||||
|
||||
const [officialsOpen, setOfficialsOpen] = useState(false);
|
||||
const [activeTab, setActiveTab] = useState<string>("all");
|
||||
|
||||
@@ -762,7 +768,33 @@ export default function MatchDetailContent() {
|
||||
<Skeleton h="80px" borderRadius="xl" />
|
||||
</VStack>
|
||||
) : prediction ? (
|
||||
<PredictionCard prediction={prediction} />
|
||||
<>
|
||||
<PredictionCard prediction={prediction} />
|
||||
{/* AI Uzman Yorumu — prediction yüklendikten sonra ayrıca çekiliyor */}
|
||||
<Card.Root bg={cardBg} borderColor={borderColor} borderRadius="2xl">
|
||||
<Card.Body gap={3}>
|
||||
<Flex align="center" gap={2}>
|
||||
<LuBrain size={16} />
|
||||
<Text fontWeight="semibold" fontSize="sm">AI Uzman Yorumu</Text>
|
||||
</Flex>
|
||||
{commentaryLoading ? (
|
||||
<VStack align="stretch" gap={2}>
|
||||
<Skeleton h="16px" borderRadius="md" />
|
||||
<Skeleton h="16px" borderRadius="md" w="90%" />
|
||||
<Skeleton h="16px" borderRadius="md" w="75%" />
|
||||
</VStack>
|
||||
) : commentaryData?.data?.commentary ? (
|
||||
<Text fontSize="sm" color="fg.muted" lineHeight="1.7">
|
||||
{commentaryData.data.commentary}
|
||||
</Text>
|
||||
) : (
|
||||
<Text fontSize="sm" color="fg.subtle">
|
||||
Yorum üretilemedi.
|
||||
</Text>
|
||||
)}
|
||||
</Card.Body>
|
||||
</Card.Root>
|
||||
</>
|
||||
) : (
|
||||
<Card.Root borderColor={borderColor} borderRadius="xl">
|
||||
<Card.Body>
|
||||
|
||||
@@ -1627,23 +1627,6 @@ export default function PredictionCard({ prediction }: PredictionCardProps) {
|
||||
)}
|
||||
ui={ui}
|
||||
/>
|
||||
{(prediction as unknown as Record<string, unknown>).ai_expert_commentary ? (
|
||||
<Card.Root bg={cardBg} borderColor={borderColor} borderRadius="2xl">
|
||||
<Card.Body gap={3}>
|
||||
<SectionTitle
|
||||
icon={LuBrain}
|
||||
title={uiText("ai-expert-commentary-title", "AI Uzman Yorumu")}
|
||||
info={uiText(
|
||||
"ai-expert-commentary-info",
|
||||
"Yapay zekanın maç verilerini okuyarak ürettiği uzman bahis analizi.",
|
||||
)}
|
||||
/>
|
||||
<Text fontSize="sm" color="fg.muted" lineHeight="1.7">
|
||||
{String((prediction as unknown as Record<string, unknown>).ai_expert_commentary)}
|
||||
</Text>
|
||||
</Card.Body>
|
||||
</Card.Root>
|
||||
) : null}
|
||||
{prediction.match_commentary?.headline ||
|
||||
prediction.match_commentary?.summary ? (
|
||||
<Card.Root bg={cardBg} borderColor={borderColor} borderRadius="2xl">
|
||||
|
||||
@@ -65,6 +65,14 @@ const checkHealth = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const getCommentary = (matchId: string) => {
|
||||
return apiRequest<ApiResponse<{ commentary: string | null }>>({
|
||||
url: `/predictions/${matchId}/commentary`,
|
||||
client: "core",
|
||||
method: "get",
|
||||
});
|
||||
};
|
||||
|
||||
const generateSmartCoupon = (body: SmartCouponRequestDto) => {
|
||||
return apiRequest<ApiResponse<SmartCouponResponseDto>>({
|
||||
url: "/predictions/smart-coupon",
|
||||
@@ -82,4 +90,5 @@ export const predictionsService = {
|
||||
getHistory,
|
||||
checkHealth,
|
||||
generateSmartCoupon,
|
||||
getCommentary,
|
||||
};
|
||||
|
||||
@@ -7,6 +7,8 @@ export const PredictionsQueryKeys = {
|
||||
all: ["predictions"] as const,
|
||||
detail: (matchId: string) =>
|
||||
[...PredictionsQueryKeys.all, "detail", matchId] as const,
|
||||
commentary: (matchId: string) =>
|
||||
[...PredictionsQueryKeys.all, "commentary", matchId] as const,
|
||||
upcoming: () => [...PredictionsQueryKeys.all, "upcoming"] as const,
|
||||
valueBets: () => [...PredictionsQueryKeys.all, "valueBets"] as const,
|
||||
history: () => [...PredictionsQueryKeys.all, "history"] as const,
|
||||
@@ -21,6 +23,16 @@ export const usePrediction = (matchId: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useAiCommentary = (matchId: string, enabled: boolean) => {
|
||||
return useQuery({
|
||||
queryKey: PredictionsQueryKeys.commentary(matchId),
|
||||
queryFn: () => predictionsService.getCommentary(matchId),
|
||||
enabled,
|
||||
staleTime: 10 * 60 * 1000, // 10 dakika cache
|
||||
retry: 1,
|
||||
});
|
||||
};
|
||||
|
||||
export const useGeneratePrediction = () => {
|
||||
return useMutation({
|
||||
mutationFn: (body: { matchId: string; sport?: SportType }) =>
|
||||
|
||||
Reference in New Issue
Block a user