Skip to content

Commit

Permalink
Merge pull request #1595 from ecency/feature/polls-improvements
Browse files Browse the repository at this point in the history
Polls improvements
  • Loading branch information
feruzm authored May 3, 2024
2 parents c9ebd9f + 11c98c7 commit d1e54df
Show file tree
Hide file tree
Showing 11 changed files with 106 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ export class EntryMetadataBuilder {

if (nextImages) {
if (selectionTouched && selectedThumbnail) {
nextImages = [selectedThumbnail, ...image!.splice(0, 9)];
nextImages = [selectedThumbnail, ...(image?.splice(0, 9) ?? [])];
} else {
nextImages = [...image!.splice(0, 9)];
nextImages = [...(image?.splice(0, 9) ?? [])];
}
} else if (selectedThumbnail === localThumbnail) {
ls.remove("draft_selected_image");
Expand Down Expand Up @@ -146,7 +146,7 @@ export class EntryMetadataBuilder {
question: poll.title,
choices: poll.choices,
preferred_interpretation: poll.interpretation,
token: null,
token: poll.interpretation === "tokens" ? "HIVE:HP" : null,
hide_votes: poll.hideVotes,
vote_change: poll.voteChange,
filters: {
Expand Down
8 changes: 6 additions & 2 deletions src/common/features/polls/api/get-poll-details-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@ interface GetPollDetailsQueryResponse {
parent_permlink: string;
permlink: string;
platform: null;
poll_choices: { choice_num: number; choice_text: string; votes?: { total_votes: number } }[];
poll_stats: { total_voting_accounts_num: number };
poll_choices: {
choice_num: number;
choice_text: string;
votes?: { total_votes: number; hive_hp_incl_proxied: number | null };
}[];
poll_stats: { total_voting_accounts_num: number; total_hive_hp_incl_proxied: number | null };
poll_trx_id: string;
poll_voters?: { name: string; choice_num: number }[];
post_body: string;
Expand Down
6 changes: 4 additions & 2 deletions src/common/features/polls/api/sign-poll-vote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export function useSignPollVoteByKey(poll: ReturnType<typeof useGetPollDetailsQu
...data,
poll_choices: [
...notTouchedChoices,
previousUserChoice
previousUserChoice && previousUserChoice.choice_text !== choice.choice_text
? {
...previousUserChoice,
votes: {
Expand All @@ -67,7 +67,9 @@ export function useSignPollVoteByKey(poll: ReturnType<typeof useGetPollDetailsQu
{
...choice,
votes: {
total_votes: (choice?.votes?.total_votes ?? 0) + 1
total_votes:
(choice?.votes?.total_votes ?? 0) +
(previousUserChoice?.choice_text !== choice.choice_text ? 1 : 0)
}
}
].filter((el) => !!el),
Expand Down
30 changes: 27 additions & 3 deletions src/common/features/polls/components/poll-option-with-results.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@ import React, { useMemo } from "react";
import { PollCheck } from "./poll-option";
import { useGetPollDetailsQuery } from "../api";
import { Entry } from "../../../store/entries/types";
import { PollSnapshot } from "./polls-creation";
import { _t } from "../../../i18n";

export interface Props {
activeChoice?: string;
choice: string;
entry?: Entry;
interpretation: PollSnapshot["interpretation"];
}

export function PollOptionWithResults({ choice, activeChoice, entry }: Props) {
export function PollOptionWithResults({ choice, activeChoice, entry, interpretation }: Props) {
const pollDetails = useGetPollDetailsQuery(entry);

const votesCount = useMemo(
Expand All @@ -24,6 +26,24 @@ export function PollOptionWithResults({ choice, activeChoice, entry }: Props) {
() => Math.max(pollDetails.data?.poll_stats.total_voting_accounts_num ?? 0, 1),
[pollDetails.data?.poll_stats.total_voting_accounts_num]
);
const totalHp = useMemo(
() => pollDetails.data?.poll_stats.total_hive_hp_incl_proxied ?? 0,
[pollDetails.data?.poll_stats.total_hive_hp_incl_proxied]
);
const choiceHp = useMemo(
() =>
pollDetails.data?.poll_choices.find((pc) => pc.choice_text === choice)?.votes
?.hive_hp_incl_proxied ?? 0,
[pollDetails.data?.poll_choices, choice]
);

const progress = useMemo(() => {
if (interpretation === "tokens") {
return ((choiceHp * 100) / totalHp).toFixed(2);
}

return ((votesCount * 100) / totalVotes).toFixed(2);
}, [totalHp, choiceHp, votesCount, totalVotes, interpretation]);

return (
<div
Expand All @@ -38,14 +58,18 @@ export function PollOptionWithResults({ choice, activeChoice, entry }: Props) {
"bg-blue-dark-sky bg-opacity-50 min-h-[52px] absolute top-0 left-0 bottom-0": true
})}
style={{
width: `${((votesCount * 100) / totalVotes).toFixed(2)}%`
width: `${progress}%`
}}
/>
{activeChoice === choice && <PollCheck checked={activeChoice === choice} />}
<div className="flex w-full gap-2 justify-between">
<span>{choice}</span>
<span className="text-xs whitespace-nowrap">
{((votesCount * 100) / totalVotes).toFixed(2)}% ({votesCount} {_t("polls.votes")})
{progress}% (
{interpretation === "number_of_votes"
? `${votesCount} ${_t("polls.votes")}`
: choiceHp.toFixed(2)}
)
</span>
</div>
</div>
Expand Down
37 changes: 37 additions & 0 deletions src/common/features/polls/components/poll-widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { useMappedStore } from "../../../store/use-mapped-store";
import { format, isBefore } from "date-fns";
import useLocalStorage from "react-use/lib/useLocalStorage";
import { PREFIX } from "../../../util/local-storage";
import { FormControl } from "@ui/input";

interface Props {
poll: PollSnapshot;
Expand All @@ -34,6 +35,8 @@ export function PollWidget({ poll, isReadOnly, entry }: Props) {
const [resultsMode, setResultsMode] = useState(false);
const [isVotedAlready, setIsVotedAlready] = useState(false);
const [showEndDate, setShowEndDate] = useLocalStorage(PREFIX + "_plls_set", false);
const [interpretation, setInterpretation] =
useState<PollSnapshot["interpretation"]>("number_of_votes");

const endTimeFullDate = useMemo(() => format(poll.endTime, "dd.MM.yyyy HH:mm"), [poll.endTime]);
const isFinished = useMemo(() => isBefore(poll.endTime, new Date()), [poll.endTime]);
Expand All @@ -49,6 +52,10 @@ export function PollWidget({ poll, isReadOnly, entry }: Props) {
() => pollDetails.data?.status === "Active" && !resultsMode,
[pollDetails.data?.status, resultsMode]
);
const isInterpretationSelectionDisabled = useMemo(
() => pollDetails.data?.poll_stats.total_hive_hp_incl_proxied === null,
[pollDetails.data?.poll_stats.total_hive_hp_incl_proxied]
);

useEffect(() => {
if (activeUserVote) {
Expand All @@ -67,6 +74,17 @@ export function PollWidget({ poll, isReadOnly, entry }: Props) {
setIsVotedAlready(!!activeUserVote);
}, [activeUserVote]);

useEffect(() => {
if (isInterpretationSelectionDisabled) {
setInterpretation("number_of_votes");
} else {
setInterpretation(
(pollDetails.data?.preferred_interpretation ??
"number_of_votes") as PollSnapshot["interpretation"]
);
}
}, [pollDetails.data, isInterpretationSelectionDisabled]);

return (
<div className="grid grid-cols-4">
<div className="col-span-4 sm:col-span-3 flex flex-col gap-4 border border-[--border-color] rounded-3xl p-4 dark:border-gray-900">
Expand Down Expand Up @@ -104,6 +122,7 @@ export function PollWidget({ poll, isReadOnly, entry }: Props) {
{poll.choices.map((choice) =>
resultsMode ? (
<PollOptionWithResults
interpretation={interpretation}
key={choice}
entry={entry}
choice={choice}
Expand All @@ -118,6 +137,24 @@ export function PollWidget({ poll, isReadOnly, entry }: Props) {
/>
)
)}
{resultsMode && (
<div className="flex items-center gap-2 flex-wrap">
<div>{_t("polls.interpretation")}</div>
<FormControl
full={false}
disabled={isInterpretationSelectionDisabled}
type="select"
size="xs"
value={interpretation}
onChange={(e: React.ChangeEvent<HTMLSelectElement>) =>
setInterpretation(e.target.value as PollSnapshot["interpretation"])
}
>
<option value="number_of_votes">{_t("polls.number_of_votes")}</option>
<option value="tokens">{_t("polls.tokens")}</option>
</FormControl>
</div>
)}
</div>
{showVote && (
<Button
Expand Down
16 changes: 13 additions & 3 deletions src/common/features/polls/components/polls-creation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import {
UilPlus,
UilQuestionCircle,
UilSave,
UilTrash
UilTrash,
UilTrashAlt
} from "@iconscout/react-unicons";
import { Button } from "@ui/button";
import { format } from "date-fns";
Expand Down Expand Up @@ -61,7 +62,8 @@ export function PollsCreation({
setHideVotes,
voteChange,
setVoteChange,
isExpiredEndDate
isExpiredEndDate,
clearAll
} = usePollsCreationManagement(existingPoll);

const formatDate = useMemo(() => format(endDate ?? new Date(), "yyyy-MM-dd"), [endDate]);
Expand Down Expand Up @@ -176,6 +178,15 @@ export function PollsCreation({
checked={!!hideVotes}
onChange={(e: boolean) => setHideVotes(e)}
/>
<Button
onClick={() => clearAll()}
outline={true}
size="sm"
icon={<UilTrashAlt />}
className="mt-4"
>
{_t("g.reset-form")}
</Button>
</div>
</ModalBody>
<ModalFooter sticky={true}>
Expand Down Expand Up @@ -212,7 +223,6 @@ export function PollsCreation({
hasEmptyOrDuplicatedChoices ||
!title ||
typeof accountAge !== "number" ||
interpretation === "tokens" ||
isExpiredEndDate
}
iconPlacement="left"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ export function usePollsCreationManagement(poll?: PollSnapshot) {
setHideVotes,
voteChange,
setVoteChange,
isExpiredEndDate
isExpiredEndDate,
clearAll: () => {
clearTitle();
clearChoices();
clearAccountAge();
clearEndDate();
}
};
}
2 changes: 1 addition & 1 deletion src/common/features/ui/button/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const BUTTON_STYLES: Record<ButtonAppearance, string> = {

export const BUTTON_OUTLINE_STYLES: Record<ButtonAppearance, string> = {
primary:
"border-blue-dark-sky hover:border-blue-dark-sky-hover focus:border-blue-dark-sky-active text-blue-dark-sky hover:text-blue-dark-sky-hover focus:text-blue-dark-sky-active",
"border-blue-dark-sky hover:border-blue-dark-sky-hover focus:border-blue-dark-sky-active text-blue-dark-sky hover:text-blue-dark-sky-hover focus:text-blue-dark-sky-active disabled:opacity-50",
secondary:
"border-gray-400 hover:border-gray-700 focus:border-gray-800 text-gray-600 hover:text-gray-700 focus:gray-800",
link: "",
Expand Down
4 changes: 3 additions & 1 deletion src/common/features/ui/input/form-controls/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import { useFilteredProps } from "../../../../util/props-filter";

// TODO: Add styles for select in input-group

export interface SelectProps extends HTMLProps<HTMLSelectElement> {
export interface SelectProps extends Omit<HTMLProps<HTMLSelectElement>, "size"> {
type: "select";
children: ReactNode;
full?: boolean;
size?: "md" | "xs";
}

export function Select(props: SelectProps) {
Expand All @@ -20,6 +21,7 @@ export function Select(props: SelectProps) {
className={classNameObject({
[INPUT_STYLES]: true,
[INPUT_DARK_STYLES]: true,
"px-2 py-1 text-sm": props.size === "xs",
[props.className ?? ""]: true,
"!w-auto": props.full === false
})}
Expand Down
6 changes: 4 additions & 2 deletions src/common/i18n/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@
"actions": "Actions",
"restore": "Restore",
"success": "Success",
"error": "Error"
"error": "Error",
"reset-form": "Reset form"
},
"confirm": {
"title": "Are you sure?",
Expand Down Expand Up @@ -2450,6 +2451,7 @@
"vote-change": "Changing a vote",
"current-standing": "Hide votes",
"finished": "Finished",
"expired-date": "End date should be in present or future"
"expired-date": "End date should be in present or future",
"interpretation": "Interpretation"
}
}
1 change: 1 addition & 0 deletions tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ module.exports = {
"green-040": "#e3fceb",
warning: {
default: "#fcc920",
"020": "#c39f2a",
"030": "#ffe08a",
"040": "#fff0c7",
"046": "#fffcf2"
Expand Down

0 comments on commit d1e54df

Please sign in to comment.