import { useState } from "react"; import { useQuery, useMutation } from "@tanstack/react-query"; import { useRoute, useLocation } from "wouter"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Card, CardContent } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Textarea } from "@/components/ui/textarea"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog"; import { Gavel, Clock, TrendingUp, Search, Settings, User, LogOut, Grid, List, Edit, Info } from "lucide-react"; import { useAuth } from "@/hooks/useAuth"; import { useToast } from "@/hooks/use-toast"; import { queryClient, apiRequest } from "@/lib/queryClient"; import ArticleCard from "@/components/ArticleCard"; import Footer from "@/components/Footer"; import LoginModal from "@/components/LoginModal"; import SearchModal from "@/components/SearchModal"; import type { MediaOutlet, Article, Auction } from "@shared/schema"; export default function MediaOutlet() { const [, params] = useRoute("/media/:slug"); const [, setLocation] = useLocation(); const [viewMode, setViewMode] = useState<"grid" | "list">("grid"); const [isLoginModalOpen, setIsLoginModalOpen] = useState(false); const [isSearchModalOpen, setIsSearchModalOpen] = useState(false); const [isEditDescModalOpen, setIsEditDescModalOpen] = useState(false); const [enlargedImage, setEnlargedImage] = useState(null); const [newDescription, setNewDescription] = useState(""); const [alternativeDescription, setAlternativeDescription] = useState("Partner at Type3 Capital and Non-Executive Director at TrueFi DAO with a strong background in fund management, venture capital, and digital assets"); const { user, isAuthenticated } = useAuth(); const { toast } = useToast(); const { data: outlet, isLoading: outletLoading } = useQuery({ queryKey: ["/api/media-outlets", params?.slug], enabled: !!params?.slug }); const { data: articles = [], isLoading: articlesLoading } = useQuery({ queryKey: ["/api/media-outlets", params?.slug, "articles"], enabled: !!params?.slug }); const { data: auction, isLoading: auctionLoading } = useQuery({ queryKey: ["/api/media-outlets", params?.slug, "auction"], enabled: !!params?.slug }); const handleLogout = async () => { try { const response = await fetch("/api/logout", { method: "POST", credentials: "include", }); if (response.ok) { toast({ title: "Logout Successful", description: "You have been successfully logged out.", }); queryClient.invalidateQueries({ queryKey: ["/api/auth/user"] }); } } catch (error) { toast({ title: "Logout Error", description: "An error occurred during logout.", variant: "destructive", }); } }; const handleAdminPage = () => { setLocation("/admin"); }; const updateDescriptionMutation = useMutation({ mutationFn: async (description: string) => { await apiRequest("PATCH", `/api/media-outlets/${params?.slug}`, { description }); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/media-outlets", params?.slug] }); toast({ title: "Success", description: "Description updated successfully", }); setIsEditDescModalOpen(false); }, onError: () => { toast({ title: "Error", description: "Failed to update description", variant: "destructive", }); }, }); const handleEditDescription = () => { setNewDescription(outlet?.description || ""); setIsEditDescModalOpen(true); }; const handleSaveDescription = (useAlternative: boolean = false) => { const descToSave = useAlternative ? alternativeDescription : newDescription; updateDescriptionMutation.mutate(descToSave); }; const formatCurrency = (amount: string | null) => { if (!amount) return "$0"; return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(parseFloat(amount)); }; const formatTimeRemaining = (endDate: Date | string) => { const end = new Date(endDate); const now = new Date(); const diff = end.getTime() - now.getTime(); if (diff <= 0) return "Auction Ended"; const days = Math.floor(diff / (1000 * 60 * 60 * 24)); const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); if (days > 0) return `${days}d ${hours}h remaining`; if (hours > 0) return `${hours}h remaining`; return "Less than 1h remaining"; }; if (outletLoading) { return (
{/* Header - Same as Home */}
SAPIENS
setIsSearchModalOpen(true)} data-testid="search-container" >
{isAuthenticated && user ? ( <>
{user.firstName} {user.lastName}
) : ( <> )}
{Array.from({ length: 6 }).map((_, i) => (
))}
); } if (!outlet) { return (

Media Outlet Not Found

The media outlet you're looking for doesn't exist.

); } return (
{/* Header - Same as Home */}
SAPIENS setLocation("/")} />
setIsSearchModalOpen(true)} data-testid="search-container" > setIsSearchModalOpen(true)} />
{isAuthenticated && user ? ( <>
{user.firstName} {user.lastName}
) : ( )}
{/* Outlet Header */}
{outlet.imageUrl ? ( {outlet.name} setEnlargedImage(outlet.imageUrl!)} data-testid="image-outlet-profile" /> ) : (
{outlet.name.charAt(0)}
)}

{outlet.name}

{outlet.category}

{outlet.description}

{user && (user.role === 'admin' || user.role === 'superadmin') && ( )}
{outlet.tags && outlet.tags.length > 0 && (
{outlet.tags.map((tag) => ( {tag} ))}
)} {/* Auction Section */} {!auctionLoading && auction ? (
Management Rights Auction
Current Highest Bid: {formatCurrency(auction.currentBid)}
{formatTimeRemaining(auction.endDate)}
) : !auctionLoading && !auction ? (
No active auction currently
) : (
)}
{/* Articles Section */}

Latest Articles

{articlesLoading ? (
{Array.from({ length: 6 }).map((_, i) => (
))}
) : articles.length > 0 ? (
{articles.map((article) => ( ))}
) : (
📰

No Articles Yet

This media outlet doesn't have any published articles yet. Check back later!

)}