add live now panel with time elapsed
This commit is contained in:
@@ -2,6 +2,10 @@ import {useAuth} from "../utils/AuthContext.tsx";
|
||||
import NoAccessPage from "../components/NoAccessPage.tsx";
|
||||
import {Link} from "react-router-dom";
|
||||
import Card from "../components/Card.tsx";
|
||||
import {useEffect, useState} from "react";
|
||||
import IsLivePulse from "../components/IsLivePulse.tsx";
|
||||
import type {StreamStatus} from "../utils/types.ts";
|
||||
import {getCurrentStream} from "../utils/api/stream.ts";
|
||||
|
||||
type TimeOfDay = "morning" | "afternoon" | "evening" | "night";
|
||||
|
||||
@@ -44,16 +48,66 @@ function getGreetingSubtext(date: Date = new Date()): string {
|
||||
return options[Math.floor(Math.random() * options.length)];
|
||||
}
|
||||
|
||||
const Home = () => {
|
||||
const { user } = useAuth();
|
||||
const now = new Date();
|
||||
function getTimeFromISOString(date: string | null): string {
|
||||
if (date == null) {
|
||||
throw new Error("API has returned no start date");
|
||||
}
|
||||
|
||||
const d = new Date(date);
|
||||
return new Intl.DateTimeFormat('en-GB', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
hour12: false
|
||||
}).format(d);
|
||||
}
|
||||
|
||||
const Home = () => {
|
||||
const now = new Date();
|
||||
const formatted: string = new Intl.DateTimeFormat('en-IE', {
|
||||
weekday: 'long',
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
}).format(now);
|
||||
|
||||
const { user } = useAuth();
|
||||
const [ streamStatus, setStreamStatus ] = useState<StreamStatus | null>(null)
|
||||
const [ greeting ] = useState<string>(getGreetingSubtext(new Date()));
|
||||
|
||||
const [elapsed, setElapsed] = useState('00:00:00');
|
||||
|
||||
useEffect(() => {
|
||||
getCurrentStream()
|
||||
.then(streamStatus => {
|
||||
setStreamStatus(streamStatus)
|
||||
|
||||
// ---- FOR TESTING ONLY, REMOVE AT THE END -----
|
||||
streamStatus.isStreaming = true;
|
||||
streamStatus.id = 49;
|
||||
streamStatus.startDate = "2026-07-30T14:23:01.123456Z"
|
||||
})
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (streamStatus?.startDate == null) {
|
||||
setElapsed('00:00:00');
|
||||
return;
|
||||
}
|
||||
|
||||
const startMs = new Date(streamStatus?.startDate).getTime();
|
||||
|
||||
const tick = () => {
|
||||
const diffSec = Math.floor((Date.now() - startMs) / 1000);
|
||||
const hh = String(Math.floor(diffSec / 3600)).padStart(2, '0');
|
||||
const mm = String(Math.floor((diffSec % 3600) / 60)).padStart(2, '0');
|
||||
const ss = String(diffSec % 60).padStart(2, '0');
|
||||
setElapsed(`${hh}:${mm}:${ss}`);
|
||||
};
|
||||
|
||||
tick();
|
||||
const interval = setInterval(tick, 1000);
|
||||
return () => clearInterval(interval);
|
||||
}, [streamStatus?.startDate]);
|
||||
|
||||
if (user == null) {
|
||||
return (<NoAccessPage />)
|
||||
}
|
||||
@@ -63,7 +117,7 @@ const Home = () => {
|
||||
<div className={"flex flex-row justify-between items-start pb-10"}>
|
||||
<div>
|
||||
<p className={"font-data text-faint-mono text-sm tracking-widest"}>{formatted.toLocaleUpperCase()}</p>
|
||||
<h1 className={"font-heading font text-5xl text-text-strong tracking-[-0.015em]"}>{getGreetingSubtext(new Date())}</h1>
|
||||
<h1 className={"font-heading font text-5xl text-text-strong tracking-[-0.015em]"}>{greeting}</h1>
|
||||
</div>
|
||||
|
||||
<Link to={"/stream"} className={"bg-accent rounded-md text-hover text-sm p-2 hover:bg-accent-hover shadow-md"}>
|
||||
@@ -71,11 +125,29 @@ const Home = () => {
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<Card className={"bg-live-card pb-10"}>
|
||||
<p></p>
|
||||
</Card>
|
||||
{streamStatus?.isStreaming &&
|
||||
<Card className={"bg-live-card p-8"}>
|
||||
<div className={"flex flex-row items-center gap-2"}>
|
||||
<IsLivePulse />
|
||||
<p className={"text-xs font-data text-live-red"}>LIVE NOW</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className={"p-1"}></div>
|
||||
|
||||
<h2 className={"font-heading text-2xl"}>
|
||||
Session {String(streamStatus.id).padStart(5, '0')} {' '}
|
||||
recording since {getTimeFromISOString(streamStatus.startDate)}.</h2>
|
||||
|
||||
<div className={"flex flex-row items-center gap-2 pt-4"}>
|
||||
<div className={"flex flex-col"}>
|
||||
<h2 className={"font-data text-xl"}>{elapsed}</h2>
|
||||
<p className={"text-xs text-muted"}>elapsed</p>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
}
|
||||
|
||||
<div className={"pt-10"}>
|
||||
<h2 className={"font-heading text-2xl"}>Recent VoDs</h2>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -243,6 +243,23 @@ const StreamControl = () => {
|
||||
<div className="px-8 py-10 max-w-5xl mx-auto flex flex-col gap-5">
|
||||
<h1 className="text-2xl font-semibold text-gray-900">Stream Control</h1>
|
||||
|
||||
{isStreaming &&
|
||||
<Card className={"bg-card pb-10"}>
|
||||
<div className={"p-6"}>
|
||||
<p className={"pb-3 font-heading text-text-strong text-xl"}>Server credentials</p>
|
||||
|
||||
<p className={"font-body text-muted text-sm p-1"}>Ingest URL</p>
|
||||
<input
|
||||
type={"text"}
|
||||
contentEditable={"false"}
|
||||
className={"bg-fields rounded-xl focus:outline-none w-full p-3 text-text-strong text-sm font-data"}
|
||||
readOnly={true}
|
||||
defaultValue={"rtmp://vodsystem.ddns.net:1935/live"}
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
}
|
||||
|
||||
{/* Hero status bar */}
|
||||
<Card className={clsx(
|
||||
"p-6 flex items-center justify-between gap-6 border-l-4",
|
||||
|
||||
Reference in New Issue
Block a user