import type { Metadata } from "next"; import { getTranslations } from "next-intl/server"; import Link from "@/components/link"; import { LocalEventTime } from "@/components/public/local-event-time"; import { ContentCard, EmptyState } from "@/components/public/ui"; import { UserAvatarThumbnail } from "@/components/shared/user-avatar-thumbnail"; import { withPublicPagePerformance } from "@/lib/public-page-performance"; import { loadProfilePrivacyMap } from "@/lib/services/profile-privacy"; import { loadPublicSearch } from "@/lib/services/public-search"; export async function generateMetadata(): Promise { const t = await getTranslations("pages.search"); return { title: t("title"), description: t("subtitle") }; } type Params = { q?: string; usersPage?: string; roomsPage?: string; newsPage?: string; eventsPage?: string; }; async function SearchPage({ searchParams }: { searchParams: Promise }) { const t = await getTranslations("pages.search"); const params = await searchParams; const result = await loadPublicSearch({ query: params.q ?? "", usersPage: Number(params.usersPage ?? 1), roomsPage: Number(params.roomsPage ?? 1), newsPage: Number(params.newsPage ?? 1), eventsPage: Number(params.eventsPage ?? 1), }); const query = result?.query ?? ""; // Users who hide their online state must not have it surfaced here either โ€” // the listing, not just the profile, is what makes it enumerable. const userRows = result?.users.status === "fulfilled" ? result.users.value.rows : []; const userPrivacy = await loadProfilePrivacyMap(userRows.map((u) => u.id)); const pagination = ( kind: "users" | "rooms" | "news" | "events", data: { page: number; lastPage: number; total: number }, ) => { const href = (page: number) => `/search?${new URLSearchParams({ ...Object.fromEntries(Object.entries(params).filter((entry): entry is [string, string] => typeof entry[1] === "string")), q: query, [`${kind}Page`]: String(page) })}#${kind}`; return ( ); }; return (
{!result ? ( {t("enterQuery")} ) : ( <>

{t("resultsFor", { query })}

{result.users.status === "rejected" ? (

{t("loadError")}

) : ( <> {result.users.value.rows.length === 0 ? ( {t("empty")} ) : (
{result.users.value.rows.map((user) => ( {user.username} {t( user.online === "1" && userPrivacy.get(user.id)?.online !== false ? "online" : "offline", )} ))}
)} {pagination("users", result.users.value)} )}
{result.rooms.status === "rejected" ? (

{t("loadError")}

) : ( <> {result.rooms.value.rows.length === 0 ? ( {t("empty")} ) : (
{result.rooms.value.rows.map((room) => (

{room.name}

{room.ownerName} ยท {room.users}/{room.usersMax}

))}
)} {pagination("rooms", result.rooms.value)} )}
{result.news.status === "rejected" ? (

{t("loadError")}

) : ( <> {result.news.value.rows.length === 0 ? ( {t("empty")} ) : (
{result.news.value.rows.map((article) => (

{article.title}

))}
)} {pagination("news", result.news.value)} )}
{result.events.status === "rejected" ? (

{t("loadError")}

) : ( <> {result.events.value.rows.length === 0 ? ( {t("empty")} ) : (
{result.events.value.rows.map((event) => (

{event.title}

))}
)} {pagination("events", result.events.value)} )}
)}
); } export default withPublicPagePerformance("/search", SearchPage);