From 758c6f4115f33b00c07b7c0cbd8210d96ed238e3 Mon Sep 17 00:00:00 2001 From: Logan Date: Sun, 21 Jun 2026 23:23:36 -0400 Subject: [PATCH] discord link banner --- drb-frontend/app/trips/page.tsx | 94 ++++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/drb-frontend/app/trips/page.tsx b/drb-frontend/app/trips/page.tsx index 8ada768..29aaf7c 100644 --- a/drb-frontend/app/trips/page.tsx +++ b/drb-frontend/app/trips/page.tsx @@ -1,12 +1,102 @@ "use client"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { useRouter } from "next/navigation"; import { useAuth } from "@/components/AuthProvider"; import { useTrips } from "@/lib/useTrips"; import { c2api } from "@/lib/c2api"; import type { TripRecord } from "@/lib/types"; +// --------------------------------------------------------------------------- +// Discord link banner +// --------------------------------------------------------------------------- + +function DiscordLinkBanner() { + const [status, setStatus] = useState<{ linked: boolean; discord_username?: string } | null>(null); + const [code, setCode] = useState(null); + const [codeExpiry, setCodeExpiry] = useState(null); // minutes + const [generating, setGenerating] = useState(false); + const [unlinking, setUnlinking] = useState(false); + + useEffect(() => { + c2api.getLinkStatus().then(setStatus).catch(() => {}); + }, []); + + async function generateCode() { + setGenerating(true); + try { + const res = await c2api.generateLinkCode(); + if (res.already_linked) { + setStatus((prev) => prev ? { ...prev, linked: true } : prev); + } else if (res.code) { + setCode(res.code); + setCodeExpiry(res.expires_minutes ?? 15); + } + } finally { + setGenerating(false); + } + } + + async function unlink() { + setUnlinking(true); + try { + await c2api.unlinkDiscord(); + setStatus({ linked: false }); + setCode(null); + } finally { + setUnlinking(false); + } + } + + if (status === null) return null; // still loading + + if (status.linked) { + return ( +
+ + Discord linked{status.discord_username ? ` as @${status.discord_username}` : ""}. + + +
+ ); + } + + return ( +
+
+
+

Link your Discord account

+

+ Required to access private trips from Discord or the web. +

+
+ {!code && ( + + )} +
+ {code && ( +
+ {code} + + Run /link {code} in Discord. Expires in {codeExpiry}m. +
+ )} +
+ ); +} + function fmtDate(iso: string) { return new Date(`${iso}T12:00:00`).toLocaleDateString("en-US", { month: "short", @@ -183,6 +273,8 @@ export default function TripsPage() { return (
+ +

Trips

{isAdmin && (