Skip to content

Commit

Permalink
473 order by amount of hearts user has allocated (#482)
Browse files Browse the repository at this point in the history
* Sort by hearts

* Make voteInfo more readable

* Fix sorting

* Diego/sorting improvement (#503)

* remove ref

* move sorting to a function and state variable

* make sorting one state so there are no race conditions

* improve comments

* fix on first click

---------

Co-authored-by: Diego Alzate <[email protected]>
  • Loading branch information
camilovegag and diegoalzate authored May 17, 2024
1 parent 5473a97 commit 678832c
Showing 1 changed file with 60 additions and 28 deletions.
88 changes: 60 additions & 28 deletions packages/berlin/src/pages/Cycle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useParams } from 'react-router-dom';
import toast from 'react-hot-toast';

// API
import { QuestionOption, fetchCycle, fetchUserVotes, postVotes } from 'api';
import { GetUserVotesResponse, QuestionOption, fetchCycle, fetchUserVotes, postVotes } from 'api';

// Hooks
import useCountdown from '../hooks/useCountdown';
Expand Down Expand Up @@ -50,7 +50,6 @@ function Cycle() {
queryFn: () => fetchCycle(cycleId || ''),
enabled: !!cycleId,
});

const { data: userVotes } = useQuery({
queryKey: ['votes', cycleId],
queryFn: () => fetchUserVotes(cycleId || ''),
Expand All @@ -64,8 +63,13 @@ function Cycle() {
const [startAt, setStartAt] = useState<string | null>(null);
const [endAt, setEndAt] = useState<string | null>(null);
const [localUserVotes, setLocalUserVotes] = useState<LocalUserVotes>([]);
const [sorting, setSorting] = useState<{ column: string; order: Order }>({
column: 'pluralityScore',
const [sortedOptions, setSortedOptions] = useState<{
options: QuestionOption[];
column: 'lead' | 'affiliation' | 'numOfVotes';
order: 'desc' | 'asc';
}>({
options: [],
column: 'numOfVotes',
order: 'desc',
});

Expand All @@ -76,6 +80,22 @@ function Cycle() {
}
}, [cycle]);

useEffect(() => {
// Initial sorting
if (cycle?.forumQuestions[0].questionOptions.length) {
setSortedOptions((prev) => ({
...prev,
options: sortOptions({
options: cycle.forumQuestions[0].questionOptions,
sorting: prev,
votes: userVotes,
}),
}));
}
// no need to add sortOptions to the dependencies array
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [cycle, userVotes]);

const { formattedTime, cycleState, time } = useCountdown(startAt, endAt);

const voteInfo = useMemo(() => {
Expand Down Expand Up @@ -190,8 +210,8 @@ function Cycle() {
};

const sortByAffiliation = (a: QuestionOption, b: QuestionOption, order: Order) => {
const affiliationA = a.user.group.name.toUpperCase();
const affiliationB = b.user.group.name.toUpperCase();
const affiliationA = a.user.group?.name.toUpperCase();
const affiliationB = b.user.group?.name.toUpperCase() ?? '';
return order === 'desc'
? affiliationB.localeCompare(affiliationA)
: affiliationA.localeCompare(affiliationB);
Expand All @@ -201,39 +221,51 @@ function Cycle() {
a: QuestionOption,
b: QuestionOption,
order: Order,
localUserVotes: LocalUserVotes,
localUserVotes: LocalUserVotes | GetUserVotesResponse | null | undefined,
) => {
const votesA = localUserVotes.find((vote) => vote.optionId === a.id)?.numOfVotes || 0;
const votesB = localUserVotes.find((vote) => vote.optionId === b.id)?.numOfVotes || 0;
const votesA = localUserVotes?.find((vote) => vote.optionId === a.id)?.numOfVotes || 0;
const votesB = localUserVotes?.find((vote) => vote.optionId === b.id)?.numOfVotes || 0;
return order === 'desc' ? votesB - votesA : votesA - votesB;
};

const sortByVoteScore = (a: QuestionOption, b: QuestionOption, order: Order) => {
return order === 'desc' ? b.voteScore - a.voteScore : a.voteScore - b.voteScore;
};

const sortedOptions = useMemo(() => {
const { column, order } = sorting;
const sorted = [...(currentCycle?.questionOptions ?? [])].sort((a, b) => {
switch (column) {
const sortOptions = ({
options,
sorting,
votes,
}: {
options: QuestionOption[];
sorting: { column: string; order: Order };
votes: LocalUserVotes | GetUserVotesResponse | null | undefined;
}) => {
const sorted = [...options].sort((a, b) => {
switch (sorting.column) {
case 'lead':
return sortByLead(a, b, order);
return sortByLead(a, b, sorting.order);
case 'affiliation':
return sortByAffiliation(a, b, order);
case 'numOfVotes':
return sortByNumOfVotes(a, b, order, localUserVotes);
return sortByAffiliation(a, b, sorting.order);
default:
return sortByVoteScore(a, b, order);
return sortByNumOfVotes(a, b, sorting.order, votes);
}
});
return sorted;
}, [currentCycle?.questionOptions, localUserVotes, sorting]);
};

const handleColumnClick = (column: string) => {
setSorting((prevSorting) => ({
column,
order: prevSorting.column === column && prevSorting.order === 'asc' ? 'desc' : 'asc',
}));
setSortedOptions(
(prev) =>
({
options: sortOptions({
options: prev.options,
sorting: {
column: column as 'lead' | 'affiliation' | 'numOfVotes',
order: prev.column === column && prev.order === 'asc' ? 'desc' : 'asc',
},
votes: localUserVotes,
}),
column,
order: prev.column === column && prev.order === 'asc' ? 'desc' : 'asc',
}) as typeof sortedOptions,
);
};

return (
Expand Down Expand Up @@ -263,7 +295,7 @@ function Cycle() {
{currentCycle?.questionOptions.length ? (
<FlexColumn $gap="0">
<CycleColumns onColumnClick={handleColumnClick} />
{sortedOptions.map((option) => {
{sortedOptions.options.map((option) => {
const userVote = localUserVotes.find((vote) => vote.optionId === option.id);
const numOfVotes = userVote ? userVote.numOfVotes : 0;
return (
Expand Down

0 comments on commit 678832c

Please sign in to comment.