Update article page to display the correct media outlet header
Modify the Article page component to dynamically fetch and display the header information of the associated media outlet, including its logo and name, by introducing a new API call to retrieve MediaOutlet data. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 9a264234-c5d7-4dcc-adf3-a954b149b30d Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3df548ff-50ae-432f-9be4-25d34eccc983/9a264234-c5d7-4dcc-adf3-a954b149b30d/uCJPlBt
This commit is contained in:
4
.replit
4
.replit
@ -50,6 +50,10 @@ externalPort = 3000
|
|||||||
localPort = 43777
|
localPort = 43777
|
||||||
externalPort = 4200
|
externalPort = 4200
|
||||||
|
|
||||||
|
[[ports]]
|
||||||
|
localPort = 45921
|
||||||
|
externalPort = 6800
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
PORT = "5000"
|
PORT = "5000"
|
||||||
|
|
||||||
|
|||||||
@ -5,16 +5,18 @@ import { Button } from "@/components/ui/button";
|
|||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { TrendingUp, TrendingDown, DollarSign, Clock } from "lucide-react";
|
import { TrendingUp, TrendingDown, DollarSign, Clock, IdCard } from "lucide-react";
|
||||||
import { useToast } from "@/hooks/use-toast";
|
import { useToast } from "@/hooks/use-toast";
|
||||||
import { apiRequest, queryClient } from "@/lib/queryClient";
|
import { apiRequest, queryClient } from "@/lib/queryClient";
|
||||||
import Footer from "@/components/Footer";
|
import Footer from "@/components/Footer";
|
||||||
import type { Article, PredictionMarket } from "@shared/schema";
|
import { useAuth } from "@/hooks/useAuth";
|
||||||
|
import type { Article, PredictionMarket, MediaOutlet } from "@shared/schema";
|
||||||
|
|
||||||
export default function Article() {
|
export default function Article() {
|
||||||
const [, params] = useRoute("/articles/:slug");
|
const [, params] = useRoute("/articles/:slug");
|
||||||
const [, setLocation] = useLocation();
|
const [, setLocation] = useLocation();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
const { user } = useAuth();
|
||||||
const [betAmounts, setBetAmounts] = useState<Record<string, string>>({});
|
const [betAmounts, setBetAmounts] = useState<Record<string, string>>({});
|
||||||
|
|
||||||
const { data: article, isLoading: articleLoading } = useQuery<Article>({
|
const { data: article, isLoading: articleLoading } = useQuery<Article>({
|
||||||
@ -22,6 +24,11 @@ export default function Article() {
|
|||||||
enabled: !!params?.slug
|
enabled: !!params?.slug
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { data: outlet, isLoading: outletLoading } = useQuery<MediaOutlet>({
|
||||||
|
queryKey: ["/api/media-outlets", article?.mediaOutletId],
|
||||||
|
enabled: !!article?.mediaOutletId
|
||||||
|
});
|
||||||
|
|
||||||
const { data: markets = [], isLoading: marketsLoading } = useQuery<PredictionMarket[]>({
|
const { data: markets = [], isLoading: marketsLoading } = useQuery<PredictionMarket[]>({
|
||||||
queryKey: ["/api/articles", params?.slug, "markets"],
|
queryKey: ["/api/articles", params?.slug, "markets"],
|
||||||
enabled: !!params?.slug
|
enabled: !!params?.slug
|
||||||
@ -106,20 +113,17 @@ export default function Article() {
|
|||||||
return parts;
|
return parts;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (articleLoading) {
|
if (articleLoading || outletLoading) {
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gray-50">
|
<div className="min-h-screen bg-gray-50">
|
||||||
<header className="bg-white border-b border-gray-200 sticky top-0 z-50">
|
<header className="bg-white border-b border-gray-200 sticky top-0 z-50">
|
||||||
<div className="max-w-7xl mx-auto px-6 py-4">
|
<div className="max-w-7xl mx-auto px-6 py-4">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center space-x-4">
|
||||||
<img
|
<div className="animate-pulse flex space-x-3">
|
||||||
src="/attached_assets/logo_black_1759181850935.png"
|
<div className="rounded-full bg-gray-300 h-10 w-10"></div>
|
||||||
alt="SAPIENS"
|
<div className="h-5 bg-gray-300 rounded w-24"></div>
|
||||||
className="h-5 w-auto cursor-pointer"
|
</div>
|
||||||
data-testid="logo-sapiens"
|
|
||||||
onClick={() => setLocation("/")}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -158,14 +162,55 @@ export default function Article() {
|
|||||||
<header className="bg-white border-b border-gray-200 sticky top-0 z-50">
|
<header className="bg-white border-b border-gray-200 sticky top-0 z-50">
|
||||||
<div className="max-w-7xl mx-auto px-6 py-4">
|
<div className="max-w-7xl mx-auto px-6 py-4">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center space-x-4">
|
||||||
|
{outlet?.imageUrl ? (
|
||||||
<img
|
<img
|
||||||
src="/attached_assets/logo_black_1759181850935.png"
|
src={outlet.imageUrl}
|
||||||
alt="SAPIENS"
|
alt={outlet.name}
|
||||||
className="h-5 w-auto cursor-pointer"
|
className="w-10 h-10 rounded-full object-cover cursor-pointer"
|
||||||
data-testid="logo-sapiens"
|
onClick={() => setLocation(`/media/${outlet.slug}`)}
|
||||||
onClick={() => setLocation("/")}
|
data-testid="img-outlet-profile"
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
<div
|
||||||
|
className="w-10 h-10 rounded-full bg-gradient-to-br from-blue-500 to-purple-600 flex items-center justify-center cursor-pointer"
|
||||||
|
onClick={() => outlet && setLocation(`/media/${outlet.slug}`)}
|
||||||
|
data-testid="img-outlet-profile-fallback"
|
||||||
|
>
|
||||||
|
<span className="text-white font-bold text-lg">
|
||||||
|
{outlet?.name.charAt(0)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="flex items-center space-x-3 cursor-pointer hover:opacity-80 transition-opacity" onClick={() => setLocation("/")}>
|
||||||
|
<img
|
||||||
|
src="/attached_assets/logo_black_1759162717640.png"
|
||||||
|
alt="SAPIENS"
|
||||||
|
className="h-5 w-auto"
|
||||||
|
data-testid="logo-sapiens"
|
||||||
|
/>
|
||||||
|
{outlet && (
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<span className="text-base font-bold text-gray-900" data-testid="text-outlet-name-header">
|
||||||
|
{outlet.name}
|
||||||
|
</span>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
setLocation(`/media/${outlet.slug}/report`);
|
||||||
|
}}
|
||||||
|
className="h-6 px-2 flex items-center gap-1 text-xs border-gray-300 hover:bg-gray-100"
|
||||||
|
aria-label="View complete profile"
|
||||||
|
data-testid="button-profile"
|
||||||
|
>
|
||||||
|
<IdCard className="h-3 w-3" />
|
||||||
|
<span>About</span>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user