diff --git a/frontend/src/components/IsLivePulse.tsx b/frontend/src/components/IsLivePulse.tsx
new file mode 100644
index 0000000..7359af8
--- /dev/null
+++ b/frontend/src/components/IsLivePulse.tsx
@@ -0,0 +1,13 @@
+const IsLivePulse = () => {
+ return (
+
+
+
+
+ );
+}
+
+export default IsLivePulse;
\ No newline at end of file
diff --git a/frontend/src/components/video/VideoCard.tsx b/frontend/src/components/video/VideoCard.tsx
index 5653e7b..b20f548 100644
--- a/frontend/src/components/video/VideoCard.tsx
+++ b/frontend/src/components/video/VideoCard.tsx
@@ -63,7 +63,7 @@ const VideoCard = ({ id, title, duration, createdAt, onEdit, onDelete, className
return (
-
+

{
- 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
(null)
+ const [ greeting ] = useState(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 ()
}
@@ -63,7 +117,7 @@ const Home = () => {
{formatted.toLocaleUpperCase()}
-
{getGreetingSubtext(new Date())}
+
{greeting}
@@ -71,11 +125,29 @@ const Home = () => {
-
-
-
+ {streamStatus?.isStreaming &&
+
+
-
+
+
+
+ Session {String(streamStatus.id).padStart(5, '0')} {' '}
+ recording since {getTimeFromISOString(streamStatus.startDate)}.
+
+
+
+ }
+
+
Recent VoDs
diff --git a/frontend/src/pages/StreamControl.tsx b/frontend/src/pages/StreamControl.tsx
index 5d6f2af..0a332bf 100644
--- a/frontend/src/pages/StreamControl.tsx
+++ b/frontend/src/pages/StreamControl.tsx
@@ -243,6 +243,23 @@ const StreamControl = () => {
Stream Control
+ {isStreaming &&
+
+
+
Server credentials
+
+
Ingest URL
+
+
+
+ }
+
{/* Hero status bar */}