Add anonymous option for votes

This commit is contained in:
MartinBraquet
2025-10-18 00:53:35 +02:00
parent a19db3bca9
commit 46ffefbbb9
7 changed files with 30 additions and 6 deletions

View File

@@ -6,7 +6,7 @@ import { tryCatch } from 'common/util/try-catch'
export const createVote: APIHandler<
'create-vote'
> = async ({ title, description }, auth) => {
> = async ({ title, description, isAnonymous }, auth) => {
const creator = await getUser(auth.uid)
if (!creator) throw new APIError(401, 'Your account was not found')
@@ -17,6 +17,7 @@ export const createVote: APIHandler<
creator_id: creator.id,
title,
description,
is_anonymous: isAnonymous,
})
)

View File

@@ -34,6 +34,7 @@ DROP INDEX IF EXISTS idx_vote_results_vote_choice;
CREATE INDEX idx_vote_results_vote_choice ON vote_results (vote_id, choice);
drop function if exists get_votes_with_results;
create or replace function get_votes_with_results()
returns table (
id BIGINT,
@@ -41,6 +42,7 @@ create or replace function get_votes_with_results()
description jsonb,
created_time timestamptz,
creator_id TEXT,
is_anonymous boolean,
votes_for int,
votes_against int,
votes_abstain int,
@@ -53,6 +55,7 @@ SELECT
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,

View File

@@ -3,6 +3,7 @@ CREATE TABLE IF NOT EXISTS votes (
created_time TIMESTAMPTZ DEFAULT now() NOT NULL,
creator_id TEXT NOT NULL,
title TEXT NOT NULL,
is_anonymous BOOLEAN NOT NULL,
description JSONB
);

View File

@@ -520,6 +520,7 @@ export const API = (_apiTypeCheck = {
returns: {} as any,
props: z.object({
title: z.string().min(1),
isAnonymous: z.boolean(),
description: contentSchema,
}),
},

View File

@@ -10,7 +10,7 @@ export type Database = {
// Allows to automatically instantiate createClient with right options
// instead of createClient<Database, { PostgrestVersion: 'XX' }>(URL, KEY)
__InternalSupabase: {
PostgrestVersion: '13.0.5'
PostgrestVersion: '13.0.4'
}
public: {
Tables: {
@@ -471,7 +471,7 @@ export type Database = {
geodb_city_id?: string | null
has_kids?: number | null
height_in_inches?: number | null
id?: never
id?: number
is_smoker?: boolean | null
is_vegetarian_or_vegan?: boolean | null
last_modification_time?: string
@@ -519,7 +519,7 @@ export type Database = {
geodb_city_id?: string | null
has_kids?: number | null
height_in_inches?: number | null
id?: never
id?: number
is_smoker?: boolean | null
is_vegetarian_or_vegan?: boolean | null
last_modification_time?: string
@@ -748,6 +748,7 @@ export type Database = {
creator_id: string
description: Json | null
id: number
is_anonymous: boolean | null
title: string
}
Insert: {
@@ -755,6 +756,7 @@ export type Database = {
creator_id: string
description?: Json | null
id?: never
is_anonymous?: boolean | null
title: string
}
Update: {
@@ -762,6 +764,7 @@ export type Database = {
creator_id?: string
description?: Json | null
id?: never
is_anonymous?: boolean | null
title?: string
}
Relationships: [
@@ -814,6 +817,7 @@ export type Database = {
creator_id: string
description: Json
id: number
is_anonymous: boolean
priority: number
title: string
votes_abstain: number
@@ -874,7 +878,7 @@ export type Database = {
Returns: Json
}
ts_to_millis: {
Args: { ts: string }
Args: { ts: string } | { ts: string }
Returns: number
}
}

View File

@@ -25,6 +25,7 @@ export function VoteComponent() {
const [title, setTitle] = useState<string>('')
const [editor, setEditor] = useState<any>(null)
const [isAnonymous, setIsAnonymous] = useState<boolean>(false)
const hideButton = title.length == 0
@@ -53,6 +54,16 @@ export function VoteComponent() {
<VoteCreator
onEditor={(e) => setEditor(e)}
/>
<Row className="mx-2 mb-2 items-center gap-2 text-sm text-gray-500">
<input
type="checkbox"
id="anonymous"
checked={isAnonymous}
onChange={(e) => setIsAnonymous(e.target.checked)}
className="h-4 w-4 rounded-md border-gray-300 text-blue-600 focus:ring-blue-500"
/>
<label htmlFor="anonymous">Anonymous?</label>
</Row>
{!hideButton && (
<Row className="right-1 justify-between gap-2">
<Button
@@ -61,11 +72,14 @@ export function VoteComponent() {
const data = {
title: title,
description: editor.getJSON() as JSONContent,
isAnonymous: isAnonymous,
};
const newVote = await api('create-vote', data).catch(() => {
toast.error('Failed to create vote — try again or contact us...')
})
if (!newVote) return
setTitle('')
editor.commands.clearContent()
toast.success('Vote created')
console.debug('Vote created', newVote)
refreshVotes()

View File

@@ -35,7 +35,7 @@ export function VoteItem(props: {
</Col>
<Row className={'gap-2 mt-2 items-center justify-between w-full customlink'}>
{!!vote.priority ? <div>Priority: {((vote.priority / vote.votes_for / 3) * 100).toFixed(0)}%</div> : <p></p>}
{creator?.username && <Link href={`/${creator.username}`} className="customlink">{creator.username}</Link>}
{!vote.is_anonymous && creator?.username && <Link href={`/${creator.username}`} className="customlink">{creator.username}</Link>}
</Row>
<VoteButtons
voteId={vote.id}