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

feat: show and highlight current post score

parent ea3c0619
No related branches found
No related tags found
No related merge requests found
......@@ -78,6 +78,38 @@ export const steps = [
</Chip>
.
</p>
<p>
U příspěvků se též zobrazuje celková míra podpory. Legenda barevného
odlišení je následující:
</p>
<ul className="unordered-list unordered-list--dense">
<li>
<div className="px-1 text-sm font-bold inline-block bg-green-400 text-white">
Zelenou
</div>{" "}
je označen příspěvek, na kterém je konsensus, nebo takový, který
získal podporu skupiny členů.
</li>
<li>
<div className="px-1 text-sm font-bold inline-block bg-yellow-400 text-grey-300">
Žlutou
</div>{" "}
je označen příspěvek, který podporu teprve sbírá.
</li>
<li>
<div className="px-1 text-sm font-bold inline-block bg-red-600 text-white">
Červeně
</div>{" "}
je označen příspěvek, který má spíše negativní odezvu.
</li>
<li>
<div className="px-1 text-sm font-bold inline-block bg-grey-125 text-grey-200">
Šedivě
</div>{" "}
je označen příspěvek, který zatím není ohodnocen.
</li>
</ul>
</div>
</>
),
......
......@@ -5,6 +5,7 @@ import { format, isToday } from "date-fns";
import Chip from "components/Chip";
import { DropdownMenu, DropdownMenuItem } from "components/dropdown-menu";
import PostScore from "components/posts/PostScore";
import Thumbs from "components/Thumbs";
const Post = ({
......@@ -20,6 +21,7 @@ const Post = ({
state,
dimIfArchived = true,
currentUser,
supportThreshold,
canThumb,
onLike,
onDislike,
......@@ -82,28 +84,53 @@ const Post = ({
labels.push(
{
pending: (
<Chip key="state__pending" condensed color="grey-500">
<Chip
key="state__pending"
condensed
color="grey-500"
title="Návrh čekající na zpracování"
>
Čeká na zpracování
</Chip>
),
announced: (
<Chip key="state__announced" condensed color="blue-300">
<Chip
key="state__announced"
condensed
color="blue-300"
title="Návrh k hlasování"
>
K hlasování
</Chip>
),
accepted: (
<Chip key="state__accepted" condensed color="green-400">
<Chip
key="state__accepted"
condensed
color="green-400"
title="Schválený návrh"
>
Schválený
</Chip>
),
rejected: (
<Chip key="state__rejected" condensed color="red-600">
<Chip
key="state__rejected"
condensed
color="red-600"
title="Zamítnutý návrh"
>
Zamítnutý
</Chip>
),
"rejected-by-chairman": (
<Chip key="state__rejected-by-chairmen" condensed color="red-600">
Zamítnutý předsedajícím
<Chip
key="state__rejected-by-chairmen"
condensed
color="red-600"
title="Návrh zamítnutý předsedajícím"
>
Zamítnutý předs.
</Chip>
),
}[state]
......@@ -159,8 +186,7 @@ const Post = ({
__html: content,
};
const thumbsEnabled =
canThumb && !archived && (type === "post" || state === "announced");
const thumbsVisible = !archived && (type === "post" || state === "announced");
return (
<div className={wrapperClassName} ref={ref}>
......@@ -177,14 +203,14 @@ const Post = ({
<span className="font-bold">{author.name}</span>
<div className="mt-1 xl:mt-0 xl:ml-2 leading-tight">
<span className="text-grey-200 text-sm">{author.group}</span>
<span className="text-grey-200 ml-1 text-sm">
<span className="text-grey-200 ml-1 text-xs">
@{" "}
{format(
datetime,
isToday(datetime) ? "H:mm" : "dd. MM. H:mm"
)}
{modified && (
<span className="text-grey-200 text-sm block md:inline md:ml-2">
<span className="text-grey-200 text-xs block md:inline md:ml-2">
(upraveno)
</span>
)}
......@@ -196,13 +222,22 @@ const Post = ({
</div>
</div>
<div className="flex items-center">
<Thumbs
likes={ranking.likes}
dislikes={ranking.dislikes}
readOnly={!thumbsEnabled}
onLike={onLike}
onDislike={onDislike}
myVote={ranking.myVote}
{thumbsVisible && (
<Thumbs
likes={ranking.likes}
dislikes={ranking.dislikes}
readOnly={!canThumb}
onLike={onLike}
onDislike={onDislike}
myVote={ranking.myVote}
/>
)}
<PostScore
className="ml-2"
score={ranking.score}
hasDislikes={ranking.dislikes > 0}
rankingReadonly={!thumbsVisible}
supportThreshold={supportThreshold}
/>
{showActions && (
<DropdownMenu right className="pl-4">
......
......@@ -8,6 +8,7 @@ const PostList = ({
items,
showAddPostCta,
currentUser,
supportThreshold,
canThumb,
dimArchived,
onLike,
......@@ -67,6 +68,7 @@ const PostList = ({
archived={item.archived}
dimIfArchived={dimArchived}
currentUser={currentUser}
supportThreshold={supportThreshold}
canThumb={canThumb}
onLike={onPostLike(item)}
onDislike={onPostDislike(item)}
......
import React from "react";
import classNames from "classnames";
const PostScore = ({
score,
hasDislikes,
supportThreshold,
rankingReadonly,
className,
}) => {
const coloring = rankingReadonly
? "bg-grey-125 text-grey-200"
: {
"bg-red-600 text-white": score < 0,
"bg-grey-125 text-grey-200": score === 0,
"bg-yellow-400 text-grey-300":
score > 0 && hasDislikes && score < supportThreshold,
"bg-green-400 text-white":
score >= supportThreshold || (score > 0 && !hasDislikes),
};
return (
<span
className={classNames(
"p-1 text-sm flex items-center space-x-1",
coloring,
className
)}
title={`Míra podpory je ${score}.`}
>
<i className="ico--power" />
<span className="font-bold">{score}</span>
</span>
);
};
export default React.memo(PostScore);
......@@ -22,7 +22,7 @@ import ModalWithActions from "components/modals/ModalWithActions";
import PostEditModal from "components/posts/PostEditModal";
import PostList from "components/posts/PostList";
import { useActionState, useItemActionConfirm } from "hooks";
import { AuthStore, PostStore } from "stores";
import { AuthStore, GlobalInfoStore, PostStore } from "stores";
const PostsContainer = ({ className, showAddPostCta }) => {
const [
......@@ -98,13 +98,18 @@ const PostsContainer = ({ className, showAddPostCta }) => {
archive,
}));
const { isAuthenticated, user } = AuthStore.useState();
const { isAuthenticated, user } = AuthStore.useState((state) =>
pick(state, ["isAuthenticated", "user"])
);
const { window, items } = PostStore.useState((state) =>
pick(state, ["window", "items"])
);
const showingArchivedOnly = PostStore.useState(
(state) => state.filters.flags === "archived"
);
const groupSizeHalf = GlobalInfoStore.useState(
(state) => state.groupSizeHalf
);
const [acceptingProposal, acceptingProposalError] = useActionState(
acceptProposal,
......@@ -184,6 +189,7 @@ const PostsContainer = ({ className, showAddPostCta }) => {
className={className}
dimArchived={!showingArchivedOnly}
currentUser={user}
supportThreshold={groupSizeHalf}
onHide={setPostToHide}
onBanUser={onBanUser}
onUnbanUser={onUnbanUser}
......
......@@ -6,6 +6,7 @@ const globalInfoStoreInitial = {
connectionState: "connecting",
onlineMembers: 0,
onlineUsers: 0,
groupSizeHalf: null,
websocketUrl: null,
streamUrl: null,
protocolUrl: null,
......
......@@ -6,5 +6,8 @@ export const handleOnlineUsersUpdated = (payload) => {
GlobalInfoStore.update((state) => {
state.onlineUsers = isNumber(payload.all) ? payload.all : 0;
state.onlineMembers = isNumber(payload.members) ? payload.members : 0;
state.groupSizeHalf = isNumber(payload.group_size_half)
? payload.group_size_half
: null;
});
};
declare namespace CF2021 {
export interface GlobalInfoStorePayload {
connectionState: "connected" | "offline" | "connecting";
onlineMembers: number;
onlineUsers: number;
websocketUrl: string;
groupSizeHalf?: number;
streamUrl?: string;
protocolUrl?: string;
protocol?: string;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment