diff --git a/www/app/(app)/rooms/_components/ICSSettings.tsx b/www/app/(app)/rooms/_components/ICSSettings.tsx index ccdb2b5e..a39780d2 100644 --- a/www/app/(app)/rooms/_components/ICSSettings.tsx +++ b/www/app/(app)/rooms/_components/ICSSettings.tsx @@ -11,15 +11,18 @@ import { createListCollection, Spinner, Box, + IconButton, } from "@chakra-ui/react"; -import { useState, useEffect } from "react"; -import { LuRefreshCw } from "react-icons/lu"; +import { useState, useEffect, useRef } from "react"; +import { LuRefreshCw, LuCopy, LuCheck } from "react-icons/lu"; import { FaCheckCircle, FaExclamationCircle } from "react-icons/fa"; import { useRoomIcsSync, useRoomIcsStatus } from "../../../lib/apiHooks"; +import { toaster } from "../../../components/ui/toaster"; +import { roomAbsoluteUrl } from "../../../lib/routesClient"; +import { assertExists } from "../../../lib/utils"; interface ICSSettingsProps { - roomId?: string; - roomName?: string; + roomName: string; icsUrl?: string; icsEnabled?: boolean; icsFetchInterval?: number; @@ -45,7 +48,6 @@ const fetchIntervalOptions = [ ]; export default function ICSSettings({ - roomId, roomName, icsUrl = "", icsEnabled = false, @@ -66,6 +68,8 @@ export default function ICSSettings({ eventsCreated: number; eventsUpdated: number; } | null>(null); + const [justCopied, setJustCopied] = useState(false); + const roomUrlInputRef = useRef(null); const syncMutation = useRoomIcsSync(); @@ -73,6 +77,51 @@ export default function ICSSettings({ items: fetchIntervalOptions, }); + const handleCopyRoomUrl = async () => { + try { + await navigator.clipboard.writeText( + roomAbsoluteUrl(assertExists(roomName)), + ); + setJustCopied(true); + + toaster + .create({ + placement: "top", + duration: 3000, + render: ({ dismiss }) => ( + + + Room URL copied to clipboard! + + ), + }) + .then(() => {}); + + setTimeout(() => { + setJustCopied(false); + }, 2000); + } catch (err) { + console.error("Failed to copy room url:", err); + } + }; + + const handleRoomUrlClick = () => { + if (roomUrlInputRef.current) { + roomUrlInputRef.current.select(); + handleCopyRoomUrl(); + } + }; + // Clear sync results when dialog closes useEffect(() => { if (!isEditing) { @@ -136,6 +185,39 @@ export default function ICSSettings({ {icsEnabled && ( <> + + Room URL + + To enable Reflector to recognize your calendar events as meetings, + add this URL as the location in your calendar events + + + + + {justCopied ? : } + + + + ICS Calendar URL { - const roomUrl = `${window.location.origin}/${roomName}`; - navigator.clipboard.writeText(roomUrl); - setLinkCopied(roomName); - - setTimeout(() => { - setLinkCopied(""); - }, 2000); + navigator.clipboard.writeText(roomAbsoluteUrl(roomName)).then(() => { + setLinkCopied(roomName); + setTimeout(() => { + setLinkCopied(""); + }, 2000); + }); }; const handleCloseDialog = () => { @@ -620,7 +620,6 @@ export default function RoomsList() { `/${roomName}`; diff --git a/www/app/lib/routesClient.ts b/www/app/lib/routesClient.ts new file mode 100644 index 00000000..6b0e5fb8 --- /dev/null +++ b/www/app/lib/routesClient.ts @@ -0,0 +1,4 @@ +import { roomUrl } from "./routes"; + +export const roomAbsoluteUrl = (roomName: string) => + `${window.location.origin}${roomUrl(roomName)}`;