import Link from "next/link"; import { getTranslations } from "next-intl/server"; import { redirect } from "next/navigation"; import { ContentCard } from "@/components/public/ui"; import { auth } from "@/lib/auth"; import { prisma } from "@/lib/prisma"; import { env } from "@/env"; export const dynamic = "force-dynamic"; // Social providers we can link. `available` reflects whether the OAuth app // credentials are configured (mirrors src/lib/auth.ts, which only registers a // provider when both its id + secret env vars are set). When unavailable the // connect button is disabled so we don't bounce the user to a 404 sign-in URL. const PROVIDERS = [ { key: "discord", label: "Discord", icon: "🎮", available: Boolean(env.DISCORD_CLIENT_ID && env.DISCORD_CLIENT_SECRET), }, { key: "google", label: "Google", icon: "🔵", available: Boolean(env.GOOGLE_CLIENT_ID && env.GOOGLE_CLIENT_SECRET), }, ] as const; export default async function ConnectionsPage() { const t = await getTranslations("pages.connections"); const session = await auth(); if (!session?.user?.id) redirect("/login"); const id = Number(session.user.id); // social_accounts is a CMS-only table that may not exist in every install // (it has no bundled migration). Fall back to "nothing linked" on any error so // the page still renders the generic connect buttons. let linked: Set = new Set(); let lookupFailed = false; try { const rows = await prisma.socialAccounts.findMany({ where: { userId: BigInt(id) }, select: { provider: true }, }); linked = new Set(rows.map((r) => r.provider.toLowerCase())); } catch { lookupFailed = true; } // After connecting/erroring, NextAuth bounces back here so we land on a known page. const callbackUrl = "/settings/connections"; return (

{t("backToSettings")}

{t("matchByEmail")}{" "} {session.user.name}.

{lookupFailed ? (

{t("lookupFailed")}

) : null}
{PROVIDERS.map((p) => { const isLinked = linked.has(p.key); return ( {isLinked ? ( {t("connected")} ) : p.available ? ( // Plain link into NextAuth's built-in sign-in handler. Re-using // the same OAuth flow as /login binds the provider to the // matching hotel account (see auth.ts signIn callback). {t("connectProvider", { provider: p.label })} ) : ( {t("unavailable")} )} ); })}

{t("footerNote")}

); }