mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 15:13:07 +00:00
Some checks are pending
Deploy / preflight (push) Waiting to run
Deploy / verify (push) Blocked by required conditions
Deploy / deploy staging (teqo-staging) (push) Blocked by required conditions
Deploy / requeue when main advanced (push) Blocked by required conditions
Deploy / deploy production (teqo-1313) (push) Blocked by required conditions
82 lines
2.9 KiB
TypeScript
82 lines
2.9 KiB
TypeScript
import { resolveCalendarEventWindow } from '@/lib/calendarEvent'
|
|
import {
|
|
normalizeAbsoluteHttpUrl,
|
|
resolveShareLinkYoutubeVideoId,
|
|
YOUTUBE_HOSTS,
|
|
type ShareLinkDestinationLike,
|
|
type ShareLinkLiveTarget,
|
|
} from '@/lib/shareLink'
|
|
import {
|
|
buildShareLinkAnnouncementView,
|
|
type ShareLinkAnnouncementSource,
|
|
type ShareLinkAnnouncementView,
|
|
} from '@/lib/shareLinkAnnouncement'
|
|
|
|
/**
|
|
* S44 — the pure contract of the home section that announces the Plenária da
|
|
* Vitória. The section reflects the state of one fixed share link: while the
|
|
* event window is open it renders the announcement view (image + agenda before
|
|
* the broadcast; YouTube embed + entry CTA while on air), and it disappears
|
|
* (fail-closed) once the link is unpublished or the window closes. No Payload
|
|
* import here — the server read orchestrates and hands over a serializable view.
|
|
*/
|
|
|
|
export const SHARE_LINK_HOME_SECTION_SLUG = 'plenaria-vitoria'
|
|
|
|
export type ShareLinkHomeSectionSource = ShareLinkAnnouncementSource & {
|
|
destinations?: ShareLinkDestinationLike[] | null
|
|
}
|
|
|
|
export type ShareLinkHomeSectionView = ShareLinkAnnouncementView & {
|
|
/** Epoch ms when the event window closes (`endsAt`, else `startsAt` + 2h). */
|
|
expiresAt: number
|
|
/** Video id of the link's pre-registered YouTube destination, when there is one. */
|
|
youtubeVideoId: string | null
|
|
}
|
|
|
|
/**
|
|
* The visibility window is the S29 calendar window (the same 2h fallback
|
|
* duration): no valid `startsAt` means no event window, and a closed window
|
|
* hides the section entirely — never a stale promo.
|
|
*/
|
|
export const buildShareLinkHomeSectionView = ({
|
|
link,
|
|
imageUrl,
|
|
canonicalUrl,
|
|
nowMs,
|
|
}: {
|
|
link: ShareLinkHomeSectionSource
|
|
imageUrl: string | null
|
|
canonicalUrl: string | null
|
|
nowMs: number
|
|
}): ShareLinkHomeSectionView | null => {
|
|
const window = resolveCalendarEventWindow(link.startsAt, link.endsAt)
|
|
if (!window || nowMs >= window.end.getTime()) return null
|
|
|
|
return {
|
|
...buildShareLinkAnnouncementView({ link, imageUrl, canonicalUrl }),
|
|
expiresAt: window.end.getTime(),
|
|
youtubeVideoId: resolveShareLinkYoutubeVideoId(link.destinations),
|
|
}
|
|
}
|
|
|
|
const MEET_HOST = 'meet.google.com'
|
|
|
|
/**
|
|
* S44 — the entry CTA label follows the destination on air (design gate): the
|
|
* Google Meet is "Entrar na plenária", the YouTube is "Assistir no YouTube".
|
|
* The host is the source of truth (a relabeled destination never mislabels the
|
|
* button); anything else falls back to the S29 generic "Entrar".
|
|
*/
|
|
export const resolveShareLinkLiveActionLabel = (target: ShareLinkLiveTarget): string => {
|
|
const url = normalizeAbsoluteHttpUrl(target.href)
|
|
if (!url) return 'Entrar'
|
|
|
|
const host = new URL(url).hostname.replace(/^www\./, '')
|
|
if (host === MEET_HOST) return 'Entrar na plenária'
|
|
if (host === 'youtu.be' || (YOUTUBE_HOSTS as readonly string[]).includes(host)) {
|
|
return 'Assistir no YouTube'
|
|
}
|
|
|
|
return 'Entrar'
|
|
}
|