From c1a414afab55731b39b5e80a31e846237e55482c Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 18 Oct 2025 11:49:54 +0200 Subject: [PATCH] Make votes sortable --- backend/supabase/vote_results.sql | 55 +++++++++++++++++++-------- common/src/constants.ts | 1 + common/src/votes/constants.ts | 7 ++++ web/components/votes/vote-buttons.tsx | 6 +-- web/components/votes/vote-info.tsx | 23 ++++++++++- web/components/votes/vote-item.tsx | 4 +- web/lib/supabase/votes.ts | 13 ++++--- web/tailwind.config.js | 13 ++++++- 8 files changed, 93 insertions(+), 29 deletions(-) create mode 100644 common/src/votes/constants.ts diff --git a/backend/supabase/vote_results.sql b/backend/supabase/vote_results.sql index 835bc022..4bd38de7 100644 --- a/backend/supabase/vote_results.sql +++ b/backend/supabase/vote_results.sql @@ -33,9 +33,15 @@ CREATE INDEX vote_id_idx ON vote_results (vote_id); DROP INDEX IF EXISTS idx_vote_results_vote_choice; CREATE INDEX idx_vote_results_vote_choice ON vote_results (vote_id, choice); +DROP INDEX IF EXISTS idx_vote_results_vote_choice_priority; +CREATE INDEX idx_vote_results_vote_choice_priority ON vote_results (vote_id, choice, priority); + +DROP INDEX IF EXISTS idx_votes_created_time; +CREATE INDEX idx_votes_created_time ON votes (created_time DESC); + drop function if exists get_votes_with_results; -create or replace function get_votes_with_results() +create or replace function get_votes_with_results(order_by text default 'recent') returns table ( id BIGINT, title text, @@ -49,21 +55,40 @@ create or replace function get_votes_with_results() priority int ) as $$ +with results as ( + SELECT + v.id, + v.title, + v.description, + v.created_time, + v.creator_id, + v.is_anonymous, + COALESCE(SUM(CASE WHEN r.choice = 1 THEN 1 ELSE 0 END), 0) AS votes_for, + COALESCE(SUM(CASE WHEN r.choice = -1 THEN 1 ELSE 0 END), 0) AS votes_against, + COALESCE(SUM(CASE WHEN r.choice = 0 THEN 1 ELSE 0 END), 0) AS votes_abstain, + COALESCE(SUM(r.priority), 0)::float / GREATEST(COALESCE(SUM(CASE WHEN r.choice = 1 THEN 1 ELSE 0 END), 1), 1) * 100 / 3 AS priority + FROM votes v + LEFT JOIN vote_results r ON v.id = r.vote_id + GROUP BY v.id +) SELECT - v.id, - v.title, - v.description, - v.created_time, - v.creator_id, - v.is_anonymous, - COALESCE(SUM(CASE WHEN r.choice = 1 THEN 1 ELSE 0 END), 0) AS votes_for, - COALESCE(SUM(CASE WHEN r.choice = -1 THEN 1 ELSE 0 END), 0) AS votes_against, - COALESCE(SUM(CASE WHEN r.choice = 0 THEN 1 ELSE 0 END), 0) AS votes_abstain, - coalesce(SUM(r.priority), 0) AS priority -FROM votes v - LEFT JOIN vote_results r ON v.id = r.vote_id -GROUP BY v.id -ORDER BY v.created_time DESC; + id, + title, + description, + created_time, + creator_id, + is_anonymous, + votes_for, + votes_against, + votes_abstain, + priority +FROM results +ORDER BY + CASE WHEN order_by = 'recent' THEN created_time END DESC, + CASE WHEN order_by = 'mostVoted' THEN (votes_for + votes_against + votes_abstain) END DESC, + CASE WHEN order_by = 'mostVoted' THEN created_time END DESC, + CASE WHEN order_by = 'priority' THEN priority END DESC, + CASE WHEN order_by = 'priority' THEN created_time END DESC; $$ language sql stable; diff --git a/common/src/constants.ts b/common/src/constants.ts index bab8eeae..8cd5e09c 100644 --- a/common/src/constants.ts +++ b/common/src/constants.ts @@ -20,3 +20,4 @@ export const pStyle = "mt-1 text-gray-800 dark:text-white whitespace-pre-line"; export const IS_MAINTENANCE = false; // set to true to enable maintenance mode banner export const MIN_BIO_LENGTH = 250; + diff --git a/common/src/votes/constants.ts b/common/src/votes/constants.ts new file mode 100644 index 00000000..2aaf1de9 --- /dev/null +++ b/common/src/votes/constants.ts @@ -0,0 +1,7 @@ +export const ORDER_BY = ['recent', 'mostVoted', 'priority'] as const +export type OrderBy = typeof ORDER_BY[number] +export const Constants: Record = { + recent: 'Most recent', + mostVoted: 'Most voted', + priority: 'Highest Priority', +} \ No newline at end of file diff --git a/web/components/votes/vote-buttons.tsx b/web/components/votes/vote-buttons.tsx index ec0d977c..010f10ae 100644 --- a/web/components/votes/vote-buttons.tsx +++ b/web/components/votes/vote-buttons.tsx @@ -20,11 +20,11 @@ function VoteButton(props: { ) @@ -102,7 +102,7 @@ export function VoteButtons(props: { } return ( - +
('recent') const {data: votes, refresh: refreshVotes} = useGetter( 'votes', - {}, + {orderBy}, getVotes ) @@ -34,7 +36,24 @@ export function VoteComponent() { return ( - Proposals + + Proposals +
+ + +
+

You can discuss any of those proposals through the contact form, the feedback form, or any of our socials.

diff --git a/web/components/votes/vote-item.tsx b/web/components/votes/vote-item.tsx index 239fdeb8..f7ea49e0 100644 --- a/web/components/votes/vote-item.tsx +++ b/web/components/votes/vote-item.tsx @@ -33,8 +33,8 @@ export function VoteItem(props: { - - {!!vote.priority ?
Priority: {((vote.priority / vote.votes_for / 3) * 100).toFixed(0)}%
:

} + + {!!vote.priority ?
Priority: {vote.priority.toFixed(0)}%
:

} {!vote.is_anonymous && creator?.username && {creator.username}}
{ - const {data, error} = await db.rpc('get_votes_with_results' as any); - if (error) throw error; +import {OrderBy} from "common/votes/constants"; - // data.forEach((vote: any) => { - // console.log(vote.title, vote.votes_for, vote.votes_against, vote.votes_abstain); - // }); +export const getVotes = async (params: { orderBy: OrderBy }) => { + const { orderBy } = params + const {data, error} = await db.rpc('get_votes_with_results' as any, { + order_by: orderBy, + }); + if (error) throw error; return data } diff --git a/web/tailwind.config.js b/web/tailwind.config.js index 782602ee..12211232 100644 --- a/web/tailwind.config.js +++ b/web/tailwind.config.js @@ -11,7 +11,18 @@ module.exports = { './components/**/*.{js,ts,jsx,tsx}', ], theme: { - fontFamily: Object.assign( + + screens: { + xxs: '320px', + xs: '480px', + sm: '640px', + md: '768px', + lg: '1024px', + xl: '1280px', + '2xl': '1536px', + }, + + fontFamily: Object.assign( { ...defaultTheme.fontFamily }, { 'major-mono': ['var(--font-logo)', 'monospace'],