Update the website header to match media outlets and expand search bar
Enhance UI for article pages by synchronizing headers with media outlets and increasing the search bar's length. Add search and user authentication modal components. 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/IfFFLfD
This commit is contained in:
@ -5,19 +5,23 @@ import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { TrendingUp, TrendingDown, DollarSign, Clock, IdCard } from "lucide-react";
|
||||
import { TrendingUp, TrendingDown, DollarSign, Clock, IdCard, Search, User, LogOut, Settings } from "lucide-react";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
import { apiRequest, queryClient } from "@/lib/queryClient";
|
||||
import Footer from "@/components/Footer";
|
||||
import { useAuth } from "@/hooks/useAuth";
|
||||
import LoginModal from "@/components/LoginModal";
|
||||
import SearchModal from "@/components/SearchModal";
|
||||
import type { Article, PredictionMarket, MediaOutlet } from "@shared/schema";
|
||||
|
||||
export default function Article() {
|
||||
const [, params] = useRoute("/articles/:slug");
|
||||
const [, setLocation] = useLocation();
|
||||
const { toast } = useToast();
|
||||
const { user } = useAuth();
|
||||
const { user, isAuthenticated } = useAuth();
|
||||
const [betAmounts, setBetAmounts] = useState<Record<string, string>>({});
|
||||
const [isSearchModalOpen, setIsSearchModalOpen] = useState(false);
|
||||
const [isLoginModalOpen, setIsLoginModalOpen] = useState(false);
|
||||
|
||||
const { data: articleData, isLoading: articleLoading } = useQuery<Article & { outlet?: MediaOutlet }>({
|
||||
queryKey: ["/api/articles", params?.slug],
|
||||
@ -32,6 +36,34 @@ export default function Article() {
|
||||
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 placeBetMutation = useMutation({
|
||||
mutationFn: async ({ marketId, side, amount }: { marketId: string; side: "yes" | "no"; amount: number }) => {
|
||||
return apiRequest("POST", `/api/prediction-markets/${marketId}/bets`, { side, amount });
|
||||
@ -160,29 +192,25 @@ export default function Article() {
|
||||
<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="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-4">
|
||||
<div className="flex items-center space-x-3">
|
||||
{outlet?.imageUrl ? (
|
||||
<img
|
||||
src={outlet.imageUrl}
|
||||
alt={outlet.name}
|
||||
className="w-10 h-10 rounded-full object-cover cursor-pointer"
|
||||
className="w-10 h-10 rounded-full object-cover cursor-pointer hover:ring-2 hover:ring-blue-400 transition-all"
|
||||
onClick={() => setLocation(`/media/${outlet.slug}`)}
|
||||
data-testid="img-outlet-profile"
|
||||
data-testid="image-outlet-header-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">
|
||||
<div className="w-10 h-10 bg-gray-100 rounded-full flex items-center justify-center">
|
||||
<span className="text-gray-600 font-bold text-sm">
|
||||
{outlet?.name.charAt(0)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{outlet && (
|
||||
<div className="flex items-center space-x-2">
|
||||
<span className="text-base font-bold text-gray-900" data-testid="text-outlet-name-header">
|
||||
<span className="text-3xl font-bold text-gray-900" data-testid="text-outlet-name-header">
|
||||
{outlet.name}
|
||||
</span>
|
||||
<Button
|
||||
@ -202,14 +230,69 @@ export default function Article() {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<img
|
||||
src="/attached_assets/logo_black_1759162717640.png"
|
||||
alt="SAPIENS"
|
||||
className="h-4 w-auto cursor-pointer opacity-60 hover:opacity-100 transition-opacity"
|
||||
onClick={() => setLocation("/")}
|
||||
data-testid="logo-sapiens"
|
||||
/>
|
||||
|
||||
<div className="flex items-center space-x-4">
|
||||
<div
|
||||
className="relative cursor-pointer flex items-center"
|
||||
onClick={() => setIsSearchModalOpen(true)}
|
||||
data-testid="search-container"
|
||||
>
|
||||
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-gray-400 pointer-events-none" />
|
||||
<div className="pl-10 pr-16 py-1.5 bg-gray-50 border border-gray-200 rounded-md flex items-center space-x-2 hover:bg-gray-100 transition-colors">
|
||||
<span className="text-sm text-gray-500">search in</span>
|
||||
<img
|
||||
src="/attached_assets/logo_black_1759162717640.png"
|
||||
alt="SAPIENS"
|
||||
className="h-2 w-auto"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isAuthenticated && user ? (
|
||||
<>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={handleAdminPage}
|
||||
data-testid="button-admin-dashboard"
|
||||
>
|
||||
Admin Dashboard
|
||||
</Button>
|
||||
|
||||
<div className="flex items-center space-x-2 px-3 py-1 bg-gray-100 rounded-md">
|
||||
<User className="h-4 w-4 text-gray-600" />
|
||||
<span className="text-sm font-medium text-gray-700" data-testid="user-name">
|
||||
{user.firstName} {user.lastName}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={handleLogout}
|
||||
data-testid="button-logout"
|
||||
>
|
||||
<LogOut className="h-4 w-4" />
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => setIsLoginModalOpen(true)}
|
||||
data-testid="button-login"
|
||||
>
|
||||
Login
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
data-testid="button-settings"
|
||||
>
|
||||
<Settings className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -368,6 +451,16 @@ export default function Article() {
|
||||
</section>
|
||||
</main>
|
||||
|
||||
{/* Modals */}
|
||||
<LoginModal
|
||||
isOpen={isLoginModalOpen}
|
||||
onClose={() => setIsLoginModalOpen(false)}
|
||||
/>
|
||||
<SearchModal
|
||||
isOpen={isSearchModalOpen}
|
||||
onClose={() => setIsSearchModalOpen(false)}
|
||||
/>
|
||||
|
||||
{/* Footer */}
|
||||
<Footer />
|
||||
</div>
|
||||
|
||||
@ -235,7 +235,7 @@ export default function MediaOutlet() {
|
||||
data-testid="search-container"
|
||||
>
|
||||
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-gray-400 pointer-events-none" />
|
||||
<div className="pl-10 pr-6 py-1.5 bg-gray-50 border border-gray-200 rounded-md flex items-center space-x-2 hover:bg-gray-100 transition-colors">
|
||||
<div className="pl-10 pr-16 py-1.5 bg-gray-50 border border-gray-200 rounded-md flex items-center space-x-2 hover:bg-gray-100 transition-colors">
|
||||
<span className="text-sm text-gray-500">search in</span>
|
||||
<img
|
||||
src="/attached_assets/logo_black_1759162717640.png"
|
||||
|
||||
Reference in New Issue
Block a user