Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • to/cf-online-ui
  • vpfafrin/cf2021
2 results
Show changes
Showing
with 113 additions and 111 deletions
...@@ -4,7 +4,7 @@ import pick from "lodash/pick"; ...@@ -4,7 +4,7 @@ import pick from "lodash/pick";
import property from "lodash/property"; import property from "lodash/property";
import { createAsyncAction, errorResult, successResult } from "pullstate"; import { createAsyncAction, errorResult, successResult } from "pullstate";
import { fetch } from "api"; import { fetchApi } from "api";
import { markdownConverter } from "markdown"; import { markdownConverter } from "markdown";
import { ProgramStore } from "stores"; import { ProgramStore } from "stores";
...@@ -13,7 +13,7 @@ import { loadPosts } from "./posts"; ...@@ -13,7 +13,7 @@ import { loadPosts } from "./posts";
export const loadProgram = createAsyncAction( export const loadProgram = createAsyncAction(
async () => { async () => {
try { try {
const resp = await fetch("/program"); const resp = await fetchApi("/program");
const mappings = await resp.json(); const mappings = await resp.json();
return successResult(mappings); return successResult(mappings);
} catch (err) { } catch (err) {
...@@ -49,17 +49,17 @@ export const loadProgram = createAsyncAction( ...@@ -49,17 +49,17 @@ export const loadProgram = createAsyncAction(
expectedStartAt: parse( expectedStartAt: parse(
entry.expected_start_at, entry.expected_start_at,
"yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm:ss",
new Date() new Date(),
), ),
expectedFinishAt: entry.expected_finish_at expectedFinishAt: entry.expected_finish_at
? parse( ? parse(
entry.expected_finish_at, entry.expected_finish_at,
"yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm:ss",
new Date() new Date(),
) )
: undefined, : undefined,
}; };
} },
) )
.sort((a, b) => a.expectedStartAt - b.expectedStartAt); .sort((a, b) => a.expectedStartAt - b.expectedStartAt);
...@@ -75,7 +75,7 @@ export const loadProgram = createAsyncAction( ...@@ -75,7 +75,7 @@ export const loadProgram = createAsyncAction(
}); });
} }
}, },
} },
); );
/** /**
...@@ -87,7 +87,7 @@ export const renameProgramPoint = createAsyncAction( ...@@ -87,7 +87,7 @@ export const renameProgramPoint = createAsyncAction(
const body = JSON.stringify({ const body = JSON.stringify({
title: newTitle, title: newTitle,
}); });
await fetch(`/program/${programEntry.id}`, { await fetchApi(`/program/${programEntry.id}`, {
method: "PUT", method: "PUT",
body, body,
expectedStatus: 204, expectedStatus: 204,
...@@ -108,7 +108,7 @@ export const renameProgramPoint = createAsyncAction( ...@@ -108,7 +108,7 @@ export const renameProgramPoint = createAsyncAction(
}); });
} }
}, },
} },
); );
/** /**
...@@ -124,7 +124,7 @@ export const endProgramPoint = createAsyncAction( ...@@ -124,7 +124,7 @@ export const endProgramPoint = createAsyncAction(
const body = JSON.stringify({ const body = JSON.stringify({
is_live: false, is_live: false,
}); });
await fetch(`/program/${programEntry.id}`, { await fetchApi(`/program/${programEntry.id}`, {
method: "PUT", method: "PUT",
body, body,
expectedStatus: 204, expectedStatus: 204,
...@@ -142,7 +142,7 @@ export const endProgramPoint = createAsyncAction( ...@@ -142,7 +142,7 @@ export const endProgramPoint = createAsyncAction(
}); });
} }
}, },
} },
); );
/** /**
...@@ -158,7 +158,7 @@ export const activateProgramPoint = createAsyncAction( ...@@ -158,7 +158,7 @@ export const activateProgramPoint = createAsyncAction(
const body = JSON.stringify({ const body = JSON.stringify({
is_live: true, is_live: true,
}); });
await fetch(`/program/${programEntry.id}`, { await fetchApi(`/program/${programEntry.id}`, {
method: "PUT", method: "PUT",
body, body,
expectedStatus: 204, expectedStatus: 204,
...@@ -179,7 +179,7 @@ export const activateProgramPoint = createAsyncAction( ...@@ -179,7 +179,7 @@ export const activateProgramPoint = createAsyncAction(
loadPosts.run({}, { respectCache: false }); loadPosts.run({}, { respectCache: false });
} }
}, },
} },
); );
/** /**
...@@ -195,7 +195,7 @@ export const openDiscussion = createAsyncAction( ...@@ -195,7 +195,7 @@ export const openDiscussion = createAsyncAction(
const body = JSON.stringify({ const body = JSON.stringify({
discussion_opened: true, discussion_opened: true,
}); });
await fetch(`/program/${programEntry.id}`, { await fetchApi(`/program/${programEntry.id}`, {
method: "PUT", method: "PUT",
body, body,
expectedStatus: 204, expectedStatus: 204,
...@@ -215,7 +215,7 @@ export const openDiscussion = createAsyncAction( ...@@ -215,7 +215,7 @@ export const openDiscussion = createAsyncAction(
}); });
} }
}, },
} },
); );
/** /**
...@@ -227,7 +227,7 @@ export const closeDiscussion = createAsyncAction( ...@@ -227,7 +227,7 @@ export const closeDiscussion = createAsyncAction(
const body = JSON.stringify({ const body = JSON.stringify({
discussion_opened: false, discussion_opened: false,
}); });
await fetch(`/program/${programEntry.id}`, { await fetchApi(`/program/${programEntry.id}`, {
method: "PUT", method: "PUT",
body, body,
expectedStatus: 204, expectedStatus: 204,
...@@ -247,5 +247,5 @@ export const closeDiscussion = createAsyncAction( ...@@ -247,5 +247,5 @@ export const closeDiscussion = createAsyncAction(
}); });
} }
}, },
} },
); );
import * as Sentry from "@sentry/react"; import * as Sentry from "@sentry/react";
import { createAsyncAction, errorResult, successResult } from "pullstate"; import { createAsyncAction, errorResult, successResult } from "pullstate";
import { fetch } from "api"; import { fetchApi } from "api";
import keycloak from "keycloak"; import keycloak from "keycloak";
import { AuthStore, PostStore } from "stores"; import { AuthStore, PostStore } from "stores";
import { updateWindowPosts } from "utils"; import { updateWindowPosts } from "utils";
...@@ -12,7 +12,7 @@ export const loadMe = createAsyncAction( ...@@ -12,7 +12,7 @@ export const loadMe = createAsyncAction(
*/ */
async () => { async () => {
try { try {
const response = await fetch(`/users/me`, { const response = await fetchApi(`/users/me`, {
method: "GET", method: "GET",
expectedStatus: 200, expectedStatus: 200,
}); });
...@@ -35,7 +35,7 @@ export const loadMe = createAsyncAction( ...@@ -35,7 +35,7 @@ export const loadMe = createAsyncAction(
}); });
} }
}, },
} },
); );
export const ban = createAsyncAction( export const ban = createAsyncAction(
...@@ -44,7 +44,7 @@ export const ban = createAsyncAction( ...@@ -44,7 +44,7 @@ export const ban = createAsyncAction(
*/ */
async (user) => { async (user) => {
try { try {
await fetch(`/users/${user.id}/ban`, { await fetchApi(`/users/${user.id}/ban`, {
method: "PATCH", method: "PATCH",
expectedStatus: 204, expectedStatus: 204,
}); });
...@@ -52,7 +52,7 @@ export const ban = createAsyncAction( ...@@ -52,7 +52,7 @@ export const ban = createAsyncAction(
} catch (err) { } catch (err) {
return errorResult([], err.toString()); return errorResult([], err.toString());
} }
} },
); );
export const unban = createAsyncAction( export const unban = createAsyncAction(
...@@ -61,7 +61,7 @@ export const unban = createAsyncAction( ...@@ -61,7 +61,7 @@ export const unban = createAsyncAction(
*/ */
async (user) => { async (user) => {
try { try {
await fetch(`/users/${user.id}/unban`, { await fetchApi(`/users/${user.id}/unban`, {
method: "PATCH", method: "PATCH",
expectedStatus: 204, expectedStatus: 204,
}); });
...@@ -69,7 +69,7 @@ export const unban = createAsyncAction( ...@@ -69,7 +69,7 @@ export const unban = createAsyncAction(
} catch (err) { } catch (err) {
return errorResult([], err.toString()); return errorResult([], err.toString());
} }
} },
); );
export const inviteToJitsi = createAsyncAction( export const inviteToJitsi = createAsyncAction(
...@@ -81,7 +81,7 @@ export const inviteToJitsi = createAsyncAction( ...@@ -81,7 +81,7 @@ export const inviteToJitsi = createAsyncAction(
const body = JSON.stringify({ const body = JSON.stringify({
allowed: true, allowed: true,
}); });
await fetch(`/users/${user.id}/jitsi`, { await fetchApi(`/users/${user.id}/jitsi`, {
method: "PATCH", method: "PATCH",
body, body,
expectedStatus: 204, expectedStatus: 204,
...@@ -90,7 +90,7 @@ export const inviteToJitsi = createAsyncAction( ...@@ -90,7 +90,7 @@ export const inviteToJitsi = createAsyncAction(
} catch (err) { } catch (err) {
return errorResult([], err.toString()); return errorResult([], err.toString());
} }
} },
); );
export const refreshAccessToken = async () => { export const refreshAccessToken = async () => {
...@@ -105,7 +105,7 @@ export const refreshAccessToken = async () => { ...@@ -105,7 +105,7 @@ export const refreshAccessToken = async () => {
console.info("[auth] access token refreshed"); console.info("[auth] access token refreshed");
} catch (exc) { } catch (exc) {
console.warn( console.warn(
"[auth] could not refresh the access token, refresh token possibly expired, logging out" "[auth] could not refresh the access token, refresh token possibly expired, logging out",
); );
Sentry.setUser(null); Sentry.setUser(null);
......
import baseFetch from "unfetch";
import { AuthStore } from "./stores"; import { AuthStore } from "./stores";
export const fetch = async ( export const fetchApi = async (
url, url,
{ headers = {}, expectedStatus = 200, method = "GET", body = null } = {} { headers = {}, expectedStatus = 200, method = "GET", body = null } = {},
) => { ) => {
const { isAuthenticated, user } = AuthStore.getRawState(); const { isAuthenticated, user } = AuthStore.getRawState();
...@@ -16,10 +14,11 @@ export const fetch = async ( ...@@ -16,10 +14,11 @@ export const fetch = async (
headers["Content-Type"] = "application/json"; headers["Content-Type"] = "application/json";
} }
const response = await baseFetch(process.env.REACT_APP_API_BASE_URL + url, { const response = await fetch(process.env.REACT_APP_API_BASE_URL + url, {
body, body,
method, method,
headers, headers,
redirect: "follow",
}); });
if (!!expectedStatus && response.status !== expectedStatus) { if (!!expectedStatus && response.status !== expectedStatus) {
......
...@@ -19,7 +19,7 @@ const Footer = () => { ...@@ -19,7 +19,7 @@ const Footer = () => {
className="w-32 md:w-40 pb-6" className="w-32 md:w-40 pb-6"
/> />
<p className="para hidden md:block md:mb-4 lg:mb-0 text-grey-200"> <p className="para hidden md:block md:mb-4 lg:mb-0 text-grey-200">
Piráti, 2021. Všechna práva vyhlazena. Sdílejte a nechte ostatní Piráti, 2024. Všechna práva vyhlazena. Sdílejte a nechte ostatní
sdílet za stejných podmínek. sdílet za stejných podmínek.
</p> </p>
</section> </section>
...@@ -35,7 +35,7 @@ const Footer = () => { ...@@ -35,7 +35,7 @@ const Footer = () => {
)} )}
onClick={() => setShowCfMenu(!showCfMenu)} onClick={() => setShowCfMenu(!showCfMenu)}
> >
CF 2021 CF 2024
</span>{" "} </span>{" "}
<div className={showCfMenu || isLg ? "" : "hidden"}> <div className={showCfMenu || isLg ? "" : "hidden"}>
<ul className="mt-6 space-y-2 text-grey-200"> <ul className="mt-6 space-y-2 text-grey-200">
......
...@@ -77,7 +77,7 @@ const Navbar = ({ onGetHelp }) => { ...@@ -77,7 +77,7 @@ const Navbar = ({ onGetHelp }) => {
to="/" to="/"
className="pl-4 font-bold text-xl lg:border-r lg:border-grey-300 lg:pr-8 hover:no-underline" className="pl-4 font-bold text-xl lg:border-r lg:border-grey-300 lg:pr-8 hover:no-underline"
> >
Celostátní fórum 2021 Celostátní fórum 2024
</NavLink> </NavLink>
</div> </div>
<div className="navbar__menutoggle my-4 flex justify-end lg:hidden"> <div className="navbar__menutoggle my-4 flex justify-end lg:hidden">
......
...@@ -9,7 +9,7 @@ const NotYetStarted = ({ startAt }) => ( ...@@ -9,7 +9,7 @@ const NotYetStarted = ({ startAt }) => (
Jejda ... Jejda ...
</div> </div>
<h1 className="head-alt-base md:head-alt-md lg:head-alt-xl mb-2"> <h1 className="head-alt-base md:head-alt-md lg:head-alt-xl mb-2">
Jednání ještě nebylo zahájeno :( Jednání ještě nebylo zahájeno
</h1> </h1>
<p className="text-xl leading-snug mb-8"> <p className="text-xl leading-snug mb-8">
<span>Jednání celostátního fóra ještě nezačalo. </span> <span>Jednání celostátního fóra ještě nezačalo. </span>
......
import React from "react"; import React from "react";
import Chip from "components/Chip"; // import Chip from "components/Chip";
export { default as Beacon } from "./Beacon"; export { default as Beacon } from "./Beacon";
...@@ -9,11 +9,12 @@ export const steps = [ ...@@ -9,11 +9,12 @@ export const steps = [
target: "body", target: "body",
content: ( content: (
<> <>
<h1 className="head-alt-sm mb-4">Vítej na celostátním fóru 2021</h1> <h1 className="head-alt-sm mb-4">Vítej na celostátním fóru 2024</h1>
<p className="leading-snug text-base"> <p className="leading-snug text-base">
Letošní Pirátské fórum bude online. Abychom to celé zvládli, Víme, že volebního zasedání se nemohou zúčastnit všichni.
připravili jsme tuhle aplikaci, která se snaží alespoň částečně Abychom nepřítomným umožnili zasedání lépe sledovat, připravili
nahradit fyzickou přítomnost. Nejprve si vysvětlíme, jak funguje. jsme tuhle aplikaci, která umožňuje zasáhnout do rozpravy.
Nejprve si vysvětlíme, jak funguje.
</p> </p>
</> </>
), ),
...@@ -60,24 +61,6 @@ export const steps = [ ...@@ -60,24 +61,6 @@ export const steps = [
<p> <p>
<strong>Běžné příspěvky</strong> se zobrazí ihned po přidání. <strong>Běžné příspěvky</strong> se zobrazí ihned po přidání.
</p> </p>
<p>
<strong>Návrhy postupu</strong> po přidání nejprve zkontroluje
předsedající a pokud sezná, že je takový návrh přípusný, prohlásí ho
za{" "}
<Chip color="blue-300" condensed>
hlasovatelný
</Chip>
. Pro vyjádření podpory používej palce. Na základě míry podpory
předsedající buď návrh označí za{" "}
<Chip color="green-400" condensed>
schválený
</Chip>
, nebo za{" "}
<Chip color="red-600" condensed>
zamítnutý
</Chip>
.
</p>
<p> <p>
U příspěvků se též zobrazuje celková míra podpory. Legenda barevného U příspěvků se též zobrazuje celková míra podpory. Legenda barevného
odlišení je následující: odlišení je následující:
...@@ -110,6 +93,11 @@ export const steps = [ ...@@ -110,6 +93,11 @@ export const steps = [
je označen příspěvek, který zatím není ohodnocen. je označen příspěvek, který zatím není ohodnocen.
</li> </li>
</ul> </ul>
<p>
<strong>Návrhy postupui</strong> po přidání nejprve zkontroluje předsedající a pokud sezná,
že je takový návrh přípusný, prohlásí ho za hlasovatelný a předloží k hlasování
v plénu. Na základě toho návrh předsedající označí za schválený, nebo za zamítnutý.
</p>
</div> </div>
</> </>
), ),
...@@ -152,7 +140,7 @@ export const steps = [ ...@@ -152,7 +140,7 @@ export const steps = [
<> <>
<h1 className="head-alt-sm mb-4">To je vše!</h1> <h1 className="head-alt-sm mb-4">To je vše!</h1>
<p className="leading-snug text-base"> <p className="leading-snug text-base">
Ať se ti letošní „CFko“ líbí i v těchto ztížených podmínkách. Ať se ti letošní „CFko“ líbí.
</p> </p>
</> </>
), ),
......
...@@ -328,7 +328,7 @@ const Post = ({ ...@@ -328,7 +328,7 @@ const Post = ({
{labels} {labels}
</div> </div>
<div <div
className="text-sm lg:text-base text-black leading-normal content-block overflow-x-scroll overflow-y-hidden mt-1" className="text-sm lg:text-base text-black leading-normal content-block overflow-x-auto overflow-y-hidden mt-1"
dangerouslySetInnerHTML={htmlContent} dangerouslySetInnerHTML={htmlContent}
></div> ></div>
</div> </div>
......
...@@ -46,6 +46,8 @@ const AddAnnouncementForm = ({ className }) => { ...@@ -46,6 +46,8 @@ const AddAnnouncementForm = ({ className }) => {
}; };
const onAdd = async (evt) => { const onAdd = async (evt) => {
evt.preventDefault();
let preventAction = false; let preventAction = false;
const payload = { const payload = {
content: text, content: text,
...@@ -82,7 +84,7 @@ const AddAnnouncementForm = ({ className }) => { ...@@ -82,7 +84,7 @@ const AddAnnouncementForm = ({ className }) => {
}; };
return ( return (
<div className={className}> <form className={className} onSubmit={onAdd}>
{addingError && ( {addingError && (
<ErrorMessage> <ErrorMessage>
Při přidávání oznámení došlo k problému: {addingError}. Při přidávání oznámení došlo k problému: {addingError}.
...@@ -150,7 +152,7 @@ const AddAnnouncementForm = ({ className }) => { ...@@ -150,7 +152,7 @@ const AddAnnouncementForm = ({ className }) => {
</div> </div>
<Button <Button
onClick={onAdd} type="submit"
className="text-sm mt-4" className="text-sm mt-4"
hoverActive hoverActive
loading={adding} loading={adding}
...@@ -159,7 +161,7 @@ const AddAnnouncementForm = ({ className }) => { ...@@ -159,7 +161,7 @@ const AddAnnouncementForm = ({ className }) => {
> >
Přidat oznámení Přidat oznámení
</Button> </Button>
</div> </form>
); );
}; };
......
...@@ -74,6 +74,8 @@ const AddPostForm = ({ className, canAddProposal }) => { ...@@ -74,6 +74,8 @@ const AddPostForm = ({ className, canAddProposal }) => {
}; };
const onAdd = async (evt) => { const onAdd = async (evt) => {
evt.preventDefault();
if (!!text) { if (!!text) {
if (!error) { if (!error) {
const result = await (type === "post" ? addPost : addProposal).run({ const result = await (type === "post" ? addPost : addProposal).run({
...@@ -125,7 +127,7 @@ const AddPostForm = ({ className, canAddProposal }) => { ...@@ -125,7 +127,7 @@ const AddPostForm = ({ className, canAddProposal }) => {
"p-4 lg:p-8 " + (showAddConfirm || !expanded ? "hidden" : "") "p-4 lg:p-8 " + (showAddConfirm || !expanded ? "hidden" : "")
} }
> >
<div className="space-y-4"> <form className="space-y-4" onSubmit={onAdd}>
{apiError && is429ApiError && ( {apiError && is429ApiError && (
<div className="alert alert--warning"> <div className="alert alert--warning">
<i className="alert__icon ico--clock text-lg" /> <i className="alert__icon ico--clock text-lg" />
...@@ -203,7 +205,7 @@ const AddPostForm = ({ className, canAddProposal }) => { ...@@ -203,7 +205,7 @@ const AddPostForm = ({ className, canAddProposal }) => {
<div className="space-x-4"> <div className="space-x-4">
<Button <Button
onClick={onAdd} type="submit"
disabled={error || addingPost || addingProposal} disabled={error || addingPost || addingProposal}
loading={addingPost || addingProposal} loading={addingPost || addingProposal}
fullwidth fullwidth
...@@ -227,7 +229,7 @@ const AddPostForm = ({ className, canAddProposal }) => { ...@@ -227,7 +229,7 @@ const AddPostForm = ({ className, canAddProposal }) => {
. .
</span> </span>
</div> </div>
</div> </form>
</CardBody> </CardBody>
</Card> </Card>
); );
......
...@@ -8,6 +8,10 @@ import { useActionState } from "hooks"; ...@@ -8,6 +8,10 @@ import { useActionState } from "hooks";
import { AuthStore } from "stores"; import { AuthStore } from "stores";
const JitsiInviteCard = () => { const JitsiInviteCard = () => {
// docasne zablokovano
return null;
const { showJitsiInvitePopup, jitsiPopupDismissed } = AuthStore.useState(); const { showJitsiInvitePopup, jitsiPopupDismissed } = AuthStore.useState();
const [loading, errorMessage] = useActionState(loadMe); const [loading, errorMessage] = useActionState(loadMe);
......
...@@ -22,16 +22,12 @@ const PostFilters = () => { ...@@ -22,16 +22,12 @@ const PostFilters = () => {
{ title: "Jen příspěvky", value: "discussionOnly" }, { title: "Jen příspěvky", value: "discussionOnly" },
]; ];
const setFilter = (prop, newValue, resetPage = true) => { const setFilter = (prop, newValue) => {
PostStore.update((state) => { PostStore.update((state) => {
state.filters[prop] = newValue; state.filters[prop] = newValue;
state.window.itemCount = state.window.items.length; state.window.itemCount = state.window.items.length;
updateWindowPosts(state); updateWindowPosts(state);
if (resetPage) {
state.window.page = 1;
}
}); });
}; };
......
...@@ -13,7 +13,7 @@ export const useItemActionConfirm = (actionFn, actionParamsBuilder = null) => { ...@@ -13,7 +13,7 @@ export const useItemActionConfirm = (actionFn, actionParamsBuilder = null) => {
if (item) { if (item) {
const newActionArgs = (actionParamsBuilder || baseActionParamsBuilder)( const newActionArgs = (actionParamsBuilder || baseActionParamsBuilder)(
item, item,
args args,
); );
setActionArgs(newActionArgs); setActionArgs(newActionArgs);
const result = await actionFn.run(newActionArgs); const result = await actionFn.run(newActionArgs);
...@@ -23,7 +23,7 @@ export const useItemActionConfirm = (actionFn, actionParamsBuilder = null) => { ...@@ -23,7 +23,7 @@ export const useItemActionConfirm = (actionFn, actionParamsBuilder = null) => {
} }
} }
}, },
[item, setItem, actionFn, actionParamsBuilder, setActionArgs] [item, setItem, actionFn, actionParamsBuilder, setActionArgs],
); );
const onActionCancel = useCallback(() => { const onActionCancel = useCallback(() => {
......
import React from "react"; import React from "react";
import ReactDOM from "react-dom"; import ReactDOM from "react-dom/client";
import ReactModal from "react-modal"; import ReactModal from "react-modal";
import { refreshAccessToken } from "actions/users"; import { refreshAccessToken } from "actions/users";
...@@ -7,7 +7,7 @@ import { refreshAccessToken } from "actions/users"; ...@@ -7,7 +7,7 @@ import { refreshAccessToken } from "actions/users";
import App from "./App"; import App from "./App";
import * as serviceWorker from "./serviceWorker"; import * as serviceWorker from "./serviceWorker";
const root = document.getElementById("root"); const root = ReactDOM.createRoot(document.getElementById("root"));
function handleVisibilityChange() { function handleVisibilityChange() {
if (!document.hidden) { if (!document.hidden) {
...@@ -17,14 +17,12 @@ function handleVisibilityChange() { ...@@ -17,14 +17,12 @@ function handleVisibilityChange() {
document.addEventListener("visibilitychange", handleVisibilityChange, false); document.addEventListener("visibilitychange", handleVisibilityChange, false);
ReactDOM.render( root.render(
<React.StrictMode> <React.StrictMode>
<App /> <App />
</React.StrictMode>, </React.StrictMode>
root
); );
ReactModal.setAppElement(document.getElementById("root"));
ReactModal.setAppElement(root);
// If you want your app to work offline and load faster, you can change // If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls. // unregister() to register() below. Note this comes with some pitfalls.
......
...@@ -2,7 +2,7 @@ import Keycloak from "keycloak-js"; ...@@ -2,7 +2,7 @@ import Keycloak from "keycloak-js";
// Setup Keycloak instance as needed // Setup Keycloak instance as needed
// Pass initialization options as required or leave blank to load from 'keycloak.json' // Pass initialization options as required or leave blank to load from 'keycloak.json'
const keycloak = Keycloak({ const keycloak = new Keycloak({
url: "https://auth.pirati.cz/auth", url: "https://auth.pirati.cz/auth",
realm: "pirati", realm: "pirati",
clientId: "cf-online", clientId: "cf-online",
......
...@@ -6,20 +6,30 @@ import { markdownConverter } from "markdown"; ...@@ -6,20 +6,30 @@ import { markdownConverter } from "markdown";
const content = markdownConverter.makeHtml(` const content = markdownConverter.makeHtml(`
**Celostátní fórum Pirátské strany** je [podle Stanov](https://wiki.pirati.cz/rules/st#cl_8_celostatni_forum) nejvyšším orgánem strany a zasedání se podle možností účastní každý člen strany. **Celostátní fórum Pirátské strany** je [podle Stanov](https://wiki.pirati.cz/rules/st#cl_8_celostatni_forum) nejvyšším orgánem strany a zasedání se podle možností účastní každý člen strany.
Celostátní fórum ve výlučné působnosti: > #### Celostátní fórum ve výlučné působnosti:
>
> * a. volí a odvolává republikové předsednictvo,
> * b. volí a odvolává členy republikového výboru volené celostátním fórem,
> * c. zřizuje a ruší komise a odbory na celostátní úrovni,
> * d. volí a odvolává členy komise a vedoucího odboru,
> * e. schvaluje změny stanov,
> * f. projednává a schvaluje výroční zprávu předsedy strany,
> * g. mimořádně přezkoumává rozhodnutí orgánu strany,
> * h. schvaluje zakládací dokument politického institutu,
> * i. může schválit Předpis o institutu,
> * j. může volit a odvolávat některé členy správní rady politického institutu.
>
> #### Celostátní fórum dále
>
> * a. přijímá v mezích stanov další předpisy,
> * b. ukládá úkoly republikovému předsednictvu a republikovému výboru,
> * c. může projednávat a schvalovat základní programové a ideové dokumenty,
> * d. má veškerou působnost, kterou stanovy neurčují jinému orgánu strany.
a. volí a odvolává republikové předsednictvo,
b. volí a odvolává členy republikového výboru volené celostátním fórem,
c. zřizuje a ruší komise a odbory,
d. volí a odvolává členy komise a vedoucího odboru,
e. schvaluje změny stanov,
f. projednává a schvaluje výroční zprávu předsedy strany,
g. projednává a schvaluje výroční finanční zprávu podle ZPS,
h. mimořádně přezkoumává rozhodnutí orgánu strany
### Zasedání na Internetu ### Zasedání na Internetu
Zimní zasedání Celostátního fóru, z důvodu mimořádných okolnosti spojenych s mimořádným stavem, bude probihat **na Internetu**. postup zasedání na Internetu je definovan [§42a](https://wiki.pirati.cz/rules/jdr#zasedani_na_internetu) Jednacího řádu Celostátního fóra v nasledujim znění: Zasedání Celostátního fóra může z důvodu mimořádných okolností probíhat na Internetu. Postup zasedání na Internetu je definován §42a Jednacího řádu Celostátního fóra v následujícím znění:
> **(1)** Pokud mimořádné okolnosti nedovolují konání běžného zasedání, může, v rámci krizového řízení, republikové předsednictvo pověřit předsedu strany svoláním zasedání na Internetu nebo změnou již svolaného běžného zasedání na zasedání na Internetu. > **(1)** Pokud mimořádné okolnosti nedovolují konání běžného zasedání, může, v rámci krizového řízení, republikové předsednictvo pověřit předsedu strany svoláním zasedání na Internetu nebo změnou již svolaného běžného zasedání na zasedání na Internetu.
> >
...@@ -37,10 +47,10 @@ Zimní zasedání Celostátního fóru, z důvodu mimořádných okolnosti spoje ...@@ -37,10 +47,10 @@ Zimní zasedání Celostátního fóru, z důvodu mimořádných okolnosti spoje
> >
> **(4)** Právo účasti v jednání zvukem a obrazem mají zejména: > **(4)** Právo účasti v jednání zvukem a obrazem mají zejména:
> >
> a) předsedající a další činovníci jednání, > * a) předsedající a další činovníci jednání,
> b) osoby s právem na závěrečné slovo v rozpravě k bodům k rozhodnutí, > * b) osoby s právem na závěrečné slovo v rozpravě k bodům k rozhodnutí,
> c) osoby určené navrhovatelem bodu v rozpravě k jiným bodům, > * c) osoby určené navrhovatelem bodu v rozpravě k jiným bodům,
> d) další osoby, pro něž je schválen takový postup. > * d) další osoby, pro něž je schválen takový postup.
> >
> **(5)** Jinak se při zasedání na Internetu postupuje přiměřeně jako při běžném zasedání. > **(5)** Jinak se při zasedání na Internetu postupuje přiměřeně jako při běžném zasedání.
> >
...@@ -58,14 +68,14 @@ const About = () => { ...@@ -58,14 +68,14 @@ const About = () => {
return ( return (
<> <>
<Helmet> <Helmet>
<title>Co je to celostátní fórum? | CF 2021 | Pirátská strana</title> <title>Co je to celostátní fórum? | CF 2024 | Pirátská strana</title>
<meta <meta
name="description" name="description"
content="Nevíte co je to celostátní fórum České pirátské strany? Tady se dočtete vše potřebné." content="Nevíte co je to celostátní fórum České pirátské strany? Tady se dočtete vše potřebné."
/> />
<meta <meta
property="og:title" property="og:title"
content="Co je to celostátní fórum? | CF 2021 | Pirátská strana" content="Co je to celostátní fórum? | CF 2024 | Pirátská strana"
/> />
<meta <meta
property="og:description" property="og:description"
......
...@@ -136,18 +136,18 @@ const Home = () => { ...@@ -136,18 +136,18 @@ const Home = () => {
return ( return (
<> <>
<Helmet> <Helmet>
<title>Přímý přenos | CF 2021 | Pirátská strana</title> <title>Přímý přenos | CF 2024 | Pirátská strana</title>
<meta <meta
name="description" name="description"
content="Přímý přenos a diskuse z on-line zasedání Celostátního fóra České pirátské strany, 9. 1. 2021." content="Přímý přenos a diskuse z on-line zasedání Celostátního fóra České pirátské strany, 13. 1. 2024."
/> />
<meta <meta
property="og:title" property="og:title"
content="Přímý přenos | CF 2021 | Pirátská strana" content="Přímý přenos | CF 2024 | Pirátská strana"
/> />
<meta <meta
property="og:description" property="og:description"
content="Přímý přenos a diskuse z on-line zasedání Celostátního fóra České pirátské strany, 9. 1. 2021." content="Přímý přenos a diskuse z on-line zasedání Celostátního fóra České pirátské strany, 13. 1. 2024."
/> />
</Helmet> </Helmet>
<Joyride <Joyride
......
...@@ -6,9 +6,9 @@ import Button from "components/Button"; ...@@ -6,9 +6,9 @@ import Button from "components/Button";
const NotFound = () => ( const NotFound = () => (
<> <>
<Helmet> <Helmet>
<title>404ka | CF 2021 | Pirátská strana</title> <title>404ka | CF 2024 | Pirátská strana</title>
<meta name="description" content="Tahle stránka tu není." /> <meta name="description" content="Tahle stránka tu není." />
<meta property="og:title" content="404ka | CF 2021 | Pirátská strana" /> <meta property="og:title" content="404ka | CF 2024 | Pirátská strana" />
<meta property="og:description" content="Tahle stránka tu není." /> <meta property="og:description" content="Tahle stránka tu není." />
</Helmet> </Helmet>
<article className="container container--default py-8 lg:py-24"> <article className="container container--default py-8 lg:py-24">
......
...@@ -28,22 +28,25 @@ const Schedule = () => { ...@@ -28,22 +28,25 @@ const Schedule = () => {
return ( return (
<> <>
<Helmet> <Helmet>
<title>Program zasedání | CF 2021 | Pirátská strana</title> <title>Program zasedání | CF 2024 | Pirátská strana</title>
<meta <meta
name="description" name="description"
content="Přečtěte si program on-line zasedání Celostátního fóra České pirátské strany, 9. 1. 2021." content="Přečtěte si program on-line zasedání Celostátního fóra České pirátské strany, 13. 1. 2024."
/> />
<meta <meta
property="og:title" property="og:title"
content="Program zasedání | CF 2021 | Pirátská strana" content="Program zasedání | CF 2024 | Pirátská strana"
/> />
<meta <meta
property="og:description" property="og:description"
content="Přečtěte si program on-line zasedání Celostátního fóra České pirátské strany, 9. 1. 2021." content="Přečtěte si program on-line zasedání Celostátního fóra České pirátské strany, 13. 1. 2024."
/> />
</Helmet> </Helmet>
<article className="container container--default 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> <h1 className="head-alt-md lg:head-alt-lg mb-8">Program zasedání</h1>
<div class="my-4">
Program zde neobsahuje z technických důvodů všechny podrobnosti. Kompletní program naleznete na <a href="https://cf2024.pirati.cz/program">webu</a>.
</div>
<div className="flex flex-col"> <div className="flex flex-col">
{scheduleIds.map((id) => { {scheduleIds.map((id) => {
const isCurrent = id === currentId; const isCurrent = id === currentId;
......
...@@ -57,18 +57,18 @@ const Protocol = () => { ...@@ -57,18 +57,18 @@ const Protocol = () => {
return ( return (
<> <>
<Helmet> <Helmet>
<title>Zápis ze zasedání | CF 2021 | Pirátská strana</title> <title>Zápis ze zasedání | CF 2024 | Pirátská strana</title>
<meta <meta
name="description" name="description"
content="Interaktivní zápis z on-line zasedání Celostátního fóra České pirátské strany, 9. 1. 2021." content="Interaktivní zápis z on-line zasedání Celostátního fóra České pirátské strany, 13. 1. 2024."
/> />
<meta <meta
property="og:title" property="og:title"
content="Zápis ze zasedání | CF 2021 | Pirátská strana" content="Zápis ze zasedání | CF 2024 | Pirátská strana"
/> />
<meta <meta
property="og:description" property="og:description"
content="Interaktivní zápis z on-line zasedání Celostátního fóra České pirátské strany, 9. 1. 2021." content="Interaktivní zápis z on-line zasedání Celostátního fóra České pirátské strany, 13. 1. 2024."
/> />
</Helmet> </Helmet>
<article className="container container--default py-8 lg:py-24"> <article className="container container--default py-8 lg:py-24">
......