Files
sapiens-web/client/src/components/MainContent.tsx
kimjaehyeon0101 ce6b00cd7b Improve homepage layout and admin dashboard navigation
Remove sorting controls and media outlet title from the homepage. Adjust admin dashboard layout to place the description next to the logo.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 069d4324-6c40-4355-955e-c714a50de1ea
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3df548ff-50ae-432f-9be4-25d34eccc983/069d4324-6c40-4355-955e-c714a50de1ea/gVirbWH
2025-09-29 20:36:59 +00:00

156 lines
5.8 KiB
TypeScript

import { useQuery } from "@tanstack/react-query";
import { Card, CardContent } from "@/components/ui/card";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import type { MediaOutlet } from "@shared/schema";
import { useAuth } from "@/hooks/useAuth";
import Footer from "@/components/Footer";
import { useState } from "react";
import { ArrowUpDown } from "lucide-react";
import { Link } from "wouter";
const categories = [
{ id: "people", name: "People", key: "People" },
{ id: "topics", name: "Topics", key: "Topics" },
{ id: "companies", name: "Companies", key: "Companies" }
];
export default function MainContent() {
const { user } = useAuth();
const [sortBy, setSortBy] = useState<"alphabetical" | "traffic">("alphabetical");
const { data: allOutlets = [], isLoading } = useQuery<MediaOutlet[]>({
queryKey: ["/api/media-outlets"],
queryFn: async () => {
const res = await fetch("/api/media-outlets", {
credentials: "include",
});
if (!res.ok) {
throw new Error(`${res.status}: ${res.statusText}`);
}
return res.json();
},
});
// Group outlets by category and sort
const getOutletsByCategory = (category: string) => {
const filtered = allOutlets.filter(outlet =>
outlet.category.toLowerCase() === category.toLowerCase()
);
return filtered.sort((a, b) => {
if (sortBy === "alphabetical") {
return a.name.localeCompare(b.name);
} else {
// Sort by traffic score (descending - highest traffic first)
return (b.trafficScore || 0) - (a.trafficScore || 0);
}
});
};
const renderOutletCard = (outlet: MediaOutlet) => (
<Link key={outlet.id} href={`/media/${outlet.slug}`} data-testid={`link-outlet-${outlet.id}`}>
<Card
className="hover:shadow-md transition-shadow cursor-pointer bg-white"
data-testid={`card-outlet-${outlet.id}`}
>
<CardContent className="p-2">
<div className="flex items-center space-x-2">
<div className="w-10 h-10 rounded-full bg-gray-100 flex items-center justify-center overflow-hidden">
{outlet.imageUrl ? (
<img
src={outlet.imageUrl}
alt={outlet.name}
className="w-full h-full object-cover"
style={{objectPosition: 'center top'}}
/>
) : (
<div className="w-6 h-6 bg-gray-300 rounded-full flex items-center justify-center">
<span className="text-gray-600 text-sm font-medium">
{outlet.name.charAt(0)}
</span>
</div>
)}
</div>
<div className="flex-1 min-w-0">
<h3 className="font-medium text-gray-900 truncate">
{outlet.name}
</h3>
<p className="text-sm text-gray-500 truncate">
{outlet.description || "Media Outlet"}
</p>
</div>
</div>
</CardContent>
</Card>
</Link>
);
return (
<div className="min-h-screen bg-gray-50">
<div className="max-w-7xl mx-auto px-4 py-4">
{isLoading ? (
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{categories.map((category) => (
<div key={category.id}>
<h2 className="text-xl font-bold text-gray-900 mb-2">{category.name}</h2>
<div className="space-y-2">
{Array.from({ length: 8 }).map((_, i) => (
<Card key={i} className="animate-pulse">
<CardContent className="p-2">
<div className="flex items-center space-x-2">
<div className="w-10 h-10 bg-gray-200 rounded-full"></div>
<div className="flex-1">
<div className="h-4 bg-gray-200 rounded mb-2"></div>
<div className="h-3 bg-gray-200 rounded w-2/3"></div>
</div>
</div>
</CardContent>
</Card>
))}
</div>
</div>
))}
</div>
) : (
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* People Section */}
<div data-testid="section-people">
<h2 className="text-xl font-bold text-gray-900 mb-2">
People
<span className="text-gray-400 text-base ml-2">({getOutletsByCategory("People").length})</span>
</h2>
<div className="space-y-2">
{getOutletsByCategory("People").map(renderOutletCard)}
</div>
</div>
{/* Topics Section */}
<div data-testid="section-topics">
<h2 className="text-xl font-bold text-gray-900 mb-2">
Topics
<span className="text-gray-400 text-base ml-2">({getOutletsByCategory("Topics").length})</span>
</h2>
<div className="space-y-2">
{getOutletsByCategory("Topics").map(renderOutletCard)}
</div>
</div>
{/* Companies Section */}
<div data-testid="section-companies">
<h2 className="text-xl font-bold text-gray-900 mb-2">
Companies
<span className="text-gray-400 text-base ml-2">({getOutletsByCategory("Companies").length})</span>
</h2>
<div className="space-y-2">
{getOutletsByCategory("Companies").map(renderOutletCard)}
</div>
</div>
</div>
)}
</div>
{/* Footer */}
<Footer />
</div>
);
}