import { useState, useEffect, useCallback } from 'react' import { createPortal } from 'react-dom' import { X, RefreshCw, Calendar, Power } from 'lucide-react' import { SubscribeLinks } from './SubscribeLinks' interface IcsSubscribeModalProps { /** Token endpoint base, e.g. `/api/trips/123/feed` or `/api/feed/user`. */ endpoint: string title: string description: string onClose: () => void } // A server that has no APP_URL configured hands back a host-relative path; the // webcal:// handoff and Google deep link need an absolute URL, so resolve it // against the current origin as a fallback. function absolutize(url: string): string { if (!url) return '' if (/^https?:\/\//i.test(url)) return url if (url.startsWith('/')) return window.location.origin + url return url } /** * Shared subscribe dialog for the per-trip and all-trips ICS feeds. Opening it * only *reads* the current token — it never mints one silently. The user * explicitly enables the public link, and can rotate or fully turn it off. */ export function IcsSubscribeModal({ endpoint, title, description, onClose }: IcsSubscribeModalProps) { const tokenUrl = `${endpoint}/token` const [feedUrl, setFeedUrl] = useState(null) const [loading, setLoading] = useState(true) const [busy, setBusy] = useState(false) const httpsUrl = feedUrl ? absolutize(feedUrl) : '' const webcalUrl = httpsUrl ? httpsUrl.replace(/^https?:\/\//, 'webcal://') : '' const load = useCallback(async () => { setLoading(true) try { const res = await fetch(tokenUrl, { credentials: 'include' }) if (res.ok) { const data = await res.json() as { feed_url: string | null } setFeedUrl(data.feed_url) } } catch { /* ignore */ } setLoading(false) }, [tokenUrl]) useEffect(() => { load() }, [load]) const mutate = async (method: 'POST' | 'PUT' | 'DELETE') => { setBusy(true) try { const res = await fetch(tokenUrl, { method, credentials: 'include' }) if (res.ok) { const data = await res.json() as { feed_url: string | null } setFeedUrl(data.feed_url) } } catch { /* ignore */ } setBusy(false) } return createPortal(
{ if (e.target === e.currentTarget) onClose() }} >
{/* Header */}
{title}

{description}

{loading ? (
Loading…
) : !feedUrl ? ( <>

Creates a secret link anyone with it can read without logging in. You can turn it off anytime.

) : ( <>

Regenerating creates a new link and invalidates the old one. Turning off disables the link entirely.

)}
, document.body ) }