Add status on proposals

This commit is contained in:
MartinBraquet
2025-10-26 10:51:52 +01:00
parent 0fa562e6fd
commit 4c4f2e720d
7 changed files with 56 additions and 16 deletions

View File

@@ -18,6 +18,7 @@ export const createVote: APIHandler<
title,
description,
is_anonymous: isAnonymous,
status: 'voting_open',
})
)

View File

@@ -44,6 +44,7 @@ create or replace function get_votes_with_results(order_by text default 'recent'
created_time timestamptz,
creator_id TEXT,
is_anonymous boolean,
status text,
votes_for int,
votes_against int,
votes_abstain int,
@@ -58,6 +59,7 @@ with results as (
v.created_time,
v.creator_id,
v.is_anonymous,
v.status,
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,
@@ -73,6 +75,7 @@ SELECT
created_time,
creator_id,
is_anonymous,
status,
votes_for,
votes_against,
votes_abstain,

View File

@@ -4,7 +4,8 @@ CREATE TABLE IF NOT EXISTS votes (
creator_id TEXT NOT NULL,
title TEXT NOT NULL,
is_anonymous BOOLEAN NOT NULL,
description JSONB
description JSONB,
status TEXT
);
-- Foreign Keys

View File

@@ -945,6 +945,7 @@ export type Database = {
description: Json | null
id: number
is_anonymous: boolean | null
status: string | null
title: string
}
Insert: {
@@ -953,6 +954,7 @@ export type Database = {
description?: Json | null
id?: never
is_anonymous?: boolean | null
status?: string | null
title: string
}
Update: {
@@ -961,6 +963,7 @@ export type Database = {
description?: Json | null
id?: never
is_anonymous?: boolean | null
status?: string | null
title?: string
}
Relationships: [
@@ -1009,6 +1012,7 @@ export type Database = {
id: number
is_anonymous: boolean
priority: number
status: string
title: string
votes_abstain: number
votes_against: number

View File

@@ -1,7 +1,26 @@
export const ORDER_BY = ['recent', 'mostVoted', 'priority'] as const
export type OrderBy = typeof ORDER_BY[number]
export const Constants: Record<OrderBy, string> = {
export const ORDER_BY_CHOICES: Record<OrderBy, string> = {
recent: 'Most recent',
mostVoted: 'Most voted',
priority: 'Highest Priority',
}
}
export const STATUS_CHOICES: Record<string, string> = {
draft: "Draft",
under_review: "Under Review",
voting_open: "Voting Open",
voting_closed: "Voting Closed",
accepted: "Accepted",
pending: "Pending Implementation",
implemented: "Implemented ✔️",
rejected: "Rejected ❌",
cancelled: "Cancelled 🚫",
superseded: "Superseded",
expired: "Expired ⌛",
archived: "Archived",
}
export const REVERSED_STATUS_CHOICES: Record<string, string> = Object.fromEntries(
Object.entries(STATUS_CHOICES).map(([key, value]) => [value, key])
)

View File

@@ -42,13 +42,14 @@ export function VoteButtons(props: {
counts: { for: number; abstain: number; against: number }
onVoted?: () => void | Promise<void>
className?: string
disabled?: boolean
}) {
const {voteId, counts, onVoted, className, disabled: disabledProp} = props
const user = useUser()
const {voteId, counts, onVoted, className} = props
const [loading, setLoading] = useState<VoteChoice | null>(null)
const [showPriority, setShowPriority] = useState(false)
const containerRef = useRef<HTMLDivElement>(null)
const disabled = loading !== null
const disabled = disabledProp || loading !== null
// Close the dropdown when clicking outside or pressing Escape
useEffect(() => {

View File

@@ -7,12 +7,14 @@ import {VoteButtons} from 'web/components/votes/vote-buttons'
import {getVoteCreator} from "web/lib/supabase/votes";
import {useEffect, useState} from "react";
import Link from "next/link";
import {STATUS_CHOICES} from "common/votes/constants";
export type Vote = rowFor<'votes'> & {
votes_for: number
votes_against: number
votes_abstain: number
priority: number
status?: string
}
export function VoteItem(props: {
@@ -24,7 +26,7 @@ export function VoteItem(props: {
useEffect(() => {
getVoteCreator(vote.creator_id).then(setCreator)
}, [vote.creator_id])
// console.debug('creator', creator)
// console.debug('creator', creator, vote)
return (
<Col className={'mb-4 rounded-lg border border-canvas-200 p-4'}>
<Row className={'mb-2'}>
@@ -35,19 +37,28 @@ export function VoteItem(props: {
</Col>
<Row className={'gap-2 mt-2 items-center justify-between w-full custom-link flex-wrap'}>
{!!vote.priority ? <div>Priority: {vote.priority.toFixed(0)}%</div> : <p></p>}
{!vote.is_anonymous && creator?.username && <Link href={`/${creator.username}`} className="custom-link">{creator.username}</Link>}
{!vote.is_anonymous && creator?.username &&
<Link href={`/${creator.username}`} className="custom-link">{creator.username}</Link>}
</Row>
<VoteButtons
voteId={vote.id}
counts={{
for: vote.votes_for,
abstain: vote.votes_abstain,
against: vote.votes_against,
}}
onVoted={onVoted}
/>
</Col>
</Row>
<Row className="flex-wrap gap-2 items-center justify-between">
<VoteButtons
voteId={vote.id}
counts={{
for: vote.votes_for,
abstain: vote.votes_abstain,
against: vote.votes_against,
}}
onVoted={onVoted}
disabled={vote.status !== 'voting_open'}
/>
{vote.status && (
<p className="text-ink-500">
{STATUS_CHOICES[vote.status]}
</p>
)}
</Row>
</Col>
)
}