import { useMemo } from "react"; import { useListCompareTools, getListCompareToolsQueryKey, type ToolWithStats, } from "@workspace/api-client-react"; import { Link, useSearch } from "wouter"; import { Layout } from "@/components/layout"; import { useAuth } from "@/hooks/use-auth"; import { RatingStars } from "@/components/rating-stars"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Skeleton } from "@/components/ui/skeleton"; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { ShieldAlert, Trophy, Scale } from "lucide-react"; import { cn } from "@/lib/utils"; import { useTranslation } from "react-i18next"; function fmt(v: number | null | undefined): string { return v != null ? v.toFixed(1) : "–"; } export default function Compare() { const { t } = useTranslation(); const { hasFeature, isLoading: authLoading } = useAuth(); const search = useSearch(); const params = useMemo(() => { const ids = new URLSearchParams(search) .get("ids") ?.split(",") .map((s) => Number(s.trim())) .filter((n) => Number.isInteger(n) && n > 0); return ids && ids.length > 0 ? { ids: ids.join(",") } : undefined; }, [search]); const canCompare = hasFeature("compare"); const { data: tools, isLoading: loading } = useListCompareTools( params ?? { ids: "" }, { query: { queryKey: getListCompareToolsQueryKey(params ?? { ids: "" }), enabled: !!params && canCompare, }, }, ); if (!authLoading && !canCompare) { return (

{t("compare.requiresPremium")}

{t("compare.requiresPremiumSub")}

); } if (loading) { return (
); } const list = tools ?? []; if (list.length === 0) { return (

{t("compare.nothingToCompare")}

{t("compare.nothingToCompareSub")}

); } const bestRating = Math.max(...list.map((t) => t.avgCombined ?? 0)); const bestUsefulness = Math.max(...list.map((t) => t.avgUsefulness ?? 0)); const bestUsability = Math.max(...list.map((t) => t.avgUsability ?? 0)); const bestReviews = Math.max(...list.map((t) => t.ratingCount)); const isBest = (value: number | null, best: number) => value != null && value > 0 && value >= best && value === best; return (

{t("compare.title")}

{t("compare.subtitle", { count: list.length })}

{t("compare.sideBySide")} {t("compare.bestValue")} {t("compare.attribute")} {list.map((t) => (
{t.name} {t.category}
))}
{t("compare.rating")} {list.map((t) => (
{fmt(t.avgCombined)}/5 {isBest(t.avgCombined, bestRating) && }
))}
Usefulness {list.map((t) => ( {fmt(t.avgUsefulness)}/5 ))} Usability {list.map((t) => ( {fmt(t.avgUsability)}/5 ))} {t("compare.reviews")} {list.map((t) => ( {t.ratingCount} ))} {t("compare.description")} {list.map((t) => ( {t.description} ))} Features {list.map((t) => (
{(t.features ?? []).map((f) => ( {f} ))} {(t.features?.length ?? 0) === 0 && }
))}
Tags {list.map((t) => (
{(t.tags ?? []).map((tag) => ( {tag} ))} {(t.tags?.length ?? 0) === 0 && }
))}
{t("compare.lastUpdated")} {list.map((t) => ( {new Date(t.updatedAt).toLocaleDateString()} ))}
); }