Skip to content
Snippets Groups Projects
Commit 0c930d33 authored by xaralis's avatar xaralis
Browse files

feat: load stream URL from API, autosize iframe

parent aab6c422
Branches
No related tags found
No related merge requests found
......@@ -3,6 +3,7 @@ import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import { KeycloakProvider } from "@react-keycloak/web";
import * as Sentry from "@sentry/react";
import { loadConfig } from "actions/global-info";
import { initializeWSChannel } from "actions/ws";
import Footer from "components/Footer";
import Navbar from "components/Navbar";
......@@ -75,6 +76,7 @@ const LoadingComponent = (
const BaseApp = () => {
initializeWSChannel.read();
loadConfig.read();
return (
<Router>
......
import isArray from "lodash/isArray";
import { createAsyncAction, errorResult, successResult } from "pullstate";
import { fetch } from "api";
import { GlobalInfoStore } from "stores";
export const loadConfig = createAsyncAction(
async () => {
try {
const resp = await fetch("/config");
const payload = await resp.json();
if (!isArray(payload)) {
return errorResult([], "Unexpected response format");
}
return successResult(payload);
} catch (err) {
return errorResult([], err.toString());
}
},
{
postActionHook: ({ result }) => {
if (!result.error) {
GlobalInfoStore.update((state) => {
result.payload.forEach((rawConfigItem) => {
if (rawConfigItem.id === "stream_url") {
state.streamUrl = rawConfigItem.value;
}
});
});
}
},
}
);
/* auto-size iframe according to aspect ratio while keeping the 100% height */
.iframe-container {
position: relative;
padding-bottom: 56.25%; /* 16:9 */
height: 0;
}
.iframe-container iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
......@@ -17,7 +17,9 @@ import AnnouncementsContainer from "containers/AnnoucementsContainer";
import PostFilters from "containers/PostFilters";
import PostsContainer from "containers/PostsContainer";
import { useActionConfirm } from "hooks";
import { AuthStore, ProgramStore } from "stores";
import { AuthStore, GlobalInfoStore, ProgramStore } from "stores";
import "./Home.css";
const NotYetStarted = ({ startAt }) => (
<article className="container container--wide py-8 md:py-16 lg:py-32">
......@@ -94,6 +96,7 @@ const Home = () => {
scheduleIds,
} = ProgramStore.useState();
const { isAuthenticated, user } = AuthStore.useState();
const { streamUrl } = GlobalInfoStore.useState();
const programEntry = currentId ? programEntries[currentId] : null;
const [showProgramEditModal, setShowProgramEditModal] = useState(false);
const [
......@@ -191,15 +194,25 @@ const Home = () => {
)}
</div>
<iframe
width="100%"
height="500"
src="https://www.youtube.com/embed/73jJLspL8o8"
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen=""
title="Video stream"
></iframe>
{streamUrl && (
<div className="iframe-container">
<iframe
width="560"
height="315"
src={streamUrl}
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen=""
title="Video stream"
/>
</div>
)}
{!streamUrl && (
<p>
Server neposlal informaci o aktuálním streamu. Vyčkejte na
aktualizaci.
</p>
)}
</section>
<section className="cf2021__notifications">
......
import memoize from "lodash/memoize";
import { Store } from "pullstate";
/** @type {CF2021.GlobalInfoStorePayload} */
const globalInfoStoreInitial = {
onlineUsers: 0,
streamUrl: null,
};
export const GlobalInfoStore = new Store(globalInfoStoreInitial);
/** @type {CF2021.AuthStorePayload} */
const authStoreInitial = {
isAuthenticated: false,
......
declare namespace CF2021 {
export interface GlobalInfoStorePayload {
onlineUsers: number;
streamUrl?: string;
}
interface ProgramScheduleEntry {
id: number;
number: string;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment