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

feat: when protocol url is available, load protocol

parent 6b2601e3
No related branches found
No related tags found
No related merge requests found
......@@ -1421,6 +1421,11 @@
"prop-types": "^15.7.2"
}
},
"@rooks/use-interval": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/@rooks/use-interval/-/use-interval-4.5.0.tgz",
"integrity": "sha512-As0DueIAGLJLYATKPPOCDGqoIlwbhPAcYP14TNTHaAj9/ODdvUYFXAP3jFCRzDNpjXCIgSe4oBuzVVmM526n+Q=="
},
"@rooks/use-window-size": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/@rooks/use-window-size/-/use-window-size-4.5.0.tgz",
......
......@@ -4,6 +4,7 @@
"private": true,
"dependencies": {
"@react-keycloak/web": "^2.1.4",
"@rooks/use-interval": "^4.5.0",
"@rooks/use-window-size": "^4.5.0",
"@sentry/react": "^5.29.2",
"classnames": "^2.2.6",
......
......@@ -11,6 +11,7 @@ import Footer from "components/Footer";
import Navbar from "components/Navbar";
import Home from "pages/Home";
import Program from "pages/Program";
import Protocol from "pages/Protocol";
import { AuthStore, PostStore } from "stores";
import { updateWindowPosts } from "utils";
......@@ -82,12 +83,12 @@ const LoadingComponent = (
const NotFound = () => (
<article className="container container--default py-8 lg:py-24">
<h1 className="head-alt-base lg:head-alt-lg mb-8">
404ka: Tahle stránka tu není
404ka: tak tahle stránka tu není
</h1>
<p className="text-base lg:text-xl mb-8">
Dostali jste se na takzvanou „<strong>čtyřystačtyřku</strong>“, což
znamená, že stránka, kterou jste se pokusili navštívit, na tomhle webu
není.
Dostal/a ses na takzvanou „<strong>čtyřystačtyřku</strong>“, což znamená,
že stránka, kterou jsi se pokusil/a navštívit, na tomhle webu není.
Zkontroluj, zda máš správný odkaz.
</p>
<Button routerTo="/" className="text-base lg:text-xl" hoverActive fullwidth>
Přejít na hlavní stránku
......@@ -104,6 +105,7 @@ const BaseApp = () => {
<Switch>
<Route exact path="/" children={<Home />} />
<Route exact path="/program" children={<Program />} />
<Route exact path="/protocol" children={<Protocol />} />
<Route component={NotFound} />
</Switch>
<Footer />
......
import isArray from "lodash/isArray";
import { createAsyncAction, errorResult, successResult } from "pullstate";
import baseFetch from "unfetch";
import { fetch } from "api";
import { markdownConverter } from "markdown";
import { GlobalInfoStore } from "stores";
export const loadConfig = createAsyncAction(
......@@ -30,7 +32,37 @@ export const loadConfig = createAsyncAction(
if (rawConfigItem.id === "websocket_url") {
state.websocketUrl = rawConfigItem.value;
}
if (rawConfigItem.id === "record_url") {
state.protocolUrl = rawConfigItem.value;
}
});
});
}
},
}
);
export const loadProtocol = createAsyncAction(
async () => {
const { protocolUrl } = GlobalInfoStore.getRawState();
try {
const resp = await baseFetch(protocolUrl);
if (resp.status !== 200) {
return errorResult([], `Unexpected status code ${resp.status}`);
}
return successResult(await resp.text());
} catch (err) {
return errorResult([], err.toString());
}
},
{
postActionHook: ({ result }) => {
if (!result.error) {
GlobalInfoStore.update((state) => {
state.protocol = markdownConverter.makeHtml(result.payload);
});
}
},
......
......@@ -12,6 +12,7 @@ const Button = ({
loading = false,
children,
routerTo,
bodyProps = {},
...props
}) => {
const btnClass = classNames(
......@@ -30,7 +31,9 @@ const Button = ({
const inner = (
<div className="btn__body-wrap">
<div className={bodyClass}>{children}</div>
<div className={bodyClass} {...bodyProps}>
{children}
</div>
{!!icon && (
<div className="btn__icon">
<i className={icon}></i>
......
......@@ -30,6 +30,9 @@ const Footer = () => {
<li>
<NavLink to="/program">Program</NavLink>
</li>
<li>
<NavLink to="/protocol">Zápis</NavLink>
</li>
</ul>
</div>
</div>
......
......@@ -100,6 +100,11 @@ const Navbar = () => {
Program
</NavLink>
</li>
<li className="navbar-menu__item">
<NavLink className="navbar-menu__link" to="/protocol">
Zápis
</NavLink>
</li>
</ul>
</div>
<div className="navbar__actions navbar__section navbar__section--expandable container-padding--zero lg:container-padding--auto self-start flex flex-row items-center">
......
......@@ -25,7 +25,7 @@ const Schedule = () => {
);
return (
<article className="container container--wide py-8 lg:py-24">
<article className="container container--default py-8 lg:py-24">
<h1 className="head-alt-md lg:head-alt-lg mb-8">Program zasedání</h1>
<div className="flex flex-col">
{scheduleIds.map((id) => {
......
import React, { useCallback, useState } from "react";
import useInterval from "@rooks/use-interval";
import { loadProtocol } from "actions/global-info";
import Button from "components/Button";
import ErrorMessage from "components/ErrorMessage";
import { useActionState } from "hooks";
import { GlobalInfoStore } from "stores";
const Protocol = () => {
const { protocolUrl, protocol } = GlobalInfoStore.useState();
const [protocolLoading, protocolLoadError] = useActionState(loadProtocol);
const [progressPercent, setProgressPercent] = useState(0);
const [paused, setPaused] = useState(false);
const forceLoad = useCallback(async () => {
try {
setPaused(true);
setProgressPercent(1);
await loadProtocol.run();
} finally {
setPaused(false);
}
}, [setPaused, setProgressPercent]);
const tick = useCallback(async () => {
if (paused) {
return;
}
if (progressPercent % 100 === 0) {
forceLoad();
} else {
setProgressPercent(progressPercent + 1);
}
}, [forceLoad, paused, progressPercent, setProgressPercent]);
useInterval(tick, 100, true);
const htmlContent = protocol
? {
__html: protocol,
}
: null;
const progressStyle = {
position: "absolute",
width: `${progressPercent}%`,
height: "100%",
left: "0",
background:
"linear-gradient(142deg, rgba(2,0,36,1) 0%, rgba(51,51,51,1) 0%, rgba(255,255,255,1) 100%)",
opacity: "0.4",
};
return (
<article className="container container--default py-8 lg:py-24">
<h1 className="head-alt-md lg:head-alt-lg mb-8">Zápis z jednání</h1>
<div className="flex items-start">
<div className="lg:w-2/3">
{!protocolUrl && (
<ErrorMessage>Zápis momentálně není k dispozici.</ErrorMessage>
)}
{protocolLoadError && (
<ErrorMessage>
Při stahování záznamu z jednání došlo k problému:{" "}
{protocolLoadError.toString()}
</ErrorMessage>
)}
{protocolUrl && <></>}
{htmlContent && (
<div
className="leading-tight text-sm lg:text-base content-block"
dangerouslySetInnerHTML={htmlContent}
></div>
)}
</div>
<div className="hidden lg:block card elevation-10 w-1/3">
<div className="lg:card__body content-block">
<h2>Jak to funguje?</h2>
<p>
Zápis se aktualizuje automaticky každých 10 sekund. Pokud chceš
aktualizaci vynutit ručně, můžeš využít tlačítko níže.
</p>
<Button
icon="ico--refresh"
loading={protocolLoading}
className="btn--fullwidth"
onClick={forceLoad}
color="black"
bodyProps={{
style: {
position: "relative",
},
}}
>
<span style={progressStyle}></span>
<span style={{ position: "relative" }}>
{protocolLoading ? "Aktualizace..." : "Aktualizovat"}
</span>
</Button>
</div>
</div>
</div>
</article>
);
};
export default Protocol;
......@@ -8,6 +8,8 @@ const globalInfoStoreInitial = {
onlineUsers: 0,
websocketUrl: null,
streamUrl: null,
protocolUrl: null,
protocol: null,
};
export const GlobalInfoStore = new Store(globalInfoStoreInitial);
......
......@@ -4,6 +4,8 @@ declare namespace CF2021 {
onlineUsers: number;
websocketUrl: string;
streamUrl?: string;
protocolUrl?: string;
protocol?: string;
}
interface ProgramScheduleEntry {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment