Skip to content

Commit b80b12c

Browse files
✨feature: Enable absolute and simple majorities; sorting countries (#286)
1 parent 788639b commit b80b12c

File tree

11 files changed

+76
-42
lines changed

11 files changed

+76
-42
lines changed

src/api/handlers/committee.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
import { isDMUNEmail } from '$api/services/isDMUNEmail';
1212
import { assertFirstEntryExists } from '@m1212e/rumble';
1313
import { and, count, eq, type InferSelectModel } from 'drizzle-orm';
14+
import { calculateMajority } from '$lib/utils/majorities';
1415

1516
const statusEnum = enum_({
1617
tsName: 'committeeStatus'
@@ -70,13 +71,7 @@ const ref = object({
7071
return parent.customSimpleMajority;
7172
}
7273
const total = await getTotalPresentCount(parent as any);
73-
let majority: number;
74-
if ((total / 2) % 1 == 0) {
75-
majority = total / 2 + 1;
76-
} else {
77-
majority = Math.ceil(total / 2);
78-
}
79-
return majority > total ? total : majority;
74+
return calculateMajority(total, 'simple');
8075
}
8176
}),
8277
twoThirdsMajority: t.field({
@@ -86,7 +81,7 @@ const ref = object({
8681
return parent.customSimpleMajority;
8782
}
8883
const total = await getTotalPresentCount(parent as any);
89-
return Math.ceil((total * 2) / 3);
84+
return calculateMajority(total, 'twoThirds');
9085
}
9186
}),
9287
paperSupportThreshold: t.field({

src/lib/components/voting/FlagRow.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
: 'base-100'} flex flex-1 flex-row items-center gap-4 overflow-hidden p-4 shadow-sm {className ||
1919
''}"
2020
>
21-
<div class="flex w-26 flex-shrink-0 flex-col items-center gap-2 font-mono text-5xl">
21+
<div class="flex w-26 flex-shrink-0 flex-row items-center gap-2 font-mono text-5xl">
2222
{#if faIcon}
2323
<i class="fas fa-{faIcon.replace('fa-', '')} text-{color || 'content'}"></i>
2424
{/if}

src/lib/components/voting/ResultChart.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,11 @@
6868
</div>
6969

7070
<div
71-
class="bg-neutral absolute h-full w-2 -translate-x-1/2"
71+
class="bg-neutral absolute h-full w-2 -translate-x-1/2 transition-all duration-500"
7272
style="left: {getMajorityPercent()};"
7373
></div>
7474
<div
75-
class="badge badge-neutral absolute top-2 -translate-x-1/2"
75+
class="badge badge-neutral absolute top-2 -translate-x-1/2 transition-all duration-500"
7676
style="left: {getMajorityPercent()};"
7777
>
7878
{majorityAmount ? majorityAmount : ''}

src/lib/components/voting/RollCallVotingChair.svelte

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
getTranslatedCountryNameFromAlpha3Code,
1313
sortTranslatedCountries
1414
} from '$lib/utils/nationTranslationHelper.svelte';
15+
import { calculateMajority } from '$lib/utils/majorities';
1516
1617
interface Props {
1718
active: boolean;
@@ -30,9 +31,19 @@
3031
.filter((member) => member.present && member.representation?.type === 'DELEGATION')
3132
.sort((a, b) => sortTranslatedCountries(a.representation!, b.representation!));
3233
34+
let chairSettings = liveQuery(() => localDB.committeeSettings.get(committee.id));
35+
let rollCallVotingAbstain = $derived($chairSettings?.rollCallVotingAbstain ?? []);
36+
let rollCallVotingPro = $derived($chairSettings?.rollCallVotingPro ?? []);
37+
let rollCallVotingCon = $derived($chairSettings?.rollCallVotingCon ?? []);
38+
3339
let majorityAmount = $derived.by(() => {
3440
switch (majority) {
3541
case 'SIMPLE':
42+
return calculateMajority(
43+
(committee?.totalPresent ?? 0) - (rollCallVotingAbstain?.length ?? 0),
44+
'simple'
45+
);
46+
case 'ABSOLUTE':
3647
return committee?.simpleMajority ?? 0;
3748
case 'TWO_THIRDS':
3849
return committee?.twoThirdsMajority ?? 0;
@@ -41,11 +52,6 @@
4152
}
4253
});
4354
44-
let chairSettings = liveQuery(() => localDB.committeeSettings.get(committee.id));
45-
let rollCallVotingAbstain = $derived($chairSettings?.rollCallVotingAbstain ?? []);
46-
let rollCallVotingPro = $derived($chairSettings?.rollCallVotingPro ?? []);
47-
let rollCallVotingCon = $derived($chairSettings?.rollCallVotingCon ?? []);
48-
4955
let scrollingListIcons = $derived.by(() => {
5056
return members.map((member) => {
5157
let icon: string = '';
@@ -126,6 +132,14 @@
126132
}
127133
};
128134
135+
$effect(() => {
136+
if (active) {
137+
localDB.committeeSettings.update(committee.id, {
138+
votingMajorityAmount: majorityAmount
139+
});
140+
}
141+
});
142+
129143
$effect(() => {
130144
if (active) {
131145
hotkeys('j, k, l, esc', 'rollCallVote', (event, handler) => {
@@ -169,8 +183,7 @@
169183
rollCallVotingPro: [],
170184
rollCallVotingCon: [],
171185
rollCallVotingAbstain: [],
172-
votingWithAbstentions: withAbstentions,
173-
votingMajorityAmount: majorityAmount
186+
votingWithAbstentions: withAbstentions
174187
});
175188
} else {
176189
localDB.committeeSettings.update(committee.id, {

src/lib/components/voting/RollCallVotingPresentation.svelte

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import { flip } from 'svelte/animate';
1212
import FlagRow from './FlagRow.svelte';
1313
import { crossfade } from 'svelte/transition';
14+
import { sortTranslatedCountries } from '$lib/utils/nationTranslationHelper.svelte';
1415
1516
interface Props {
1617
committeeSettings?: CommitteeSettings;
@@ -30,9 +31,9 @@
3031
};
3132
3233
let members = $derived(
33-
committee?.members.filter(
34-
(member) => member.present && member.representation?.type === 'DELEGATION'
35-
)
34+
committee?.members
35+
.filter((member) => member.present && member.representation?.type === 'DELEGATION')
36+
.sort((a, b) => sortTranslatedCountries(a.representation!, b.representation!))
3637
);
3738
3839
let remainingMembers = $derived(

src/lib/components/voting/ShowOfHandsVotingChair.svelte

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import { localDB, type VotingMajority, type VotingStage } from '$lib/local-db/localDB';
88
import VoteClicker from './VoteClicker.svelte';
99
import ResultChart from './ResultChart.svelte';
10+
import { calculateMajority } from '$lib/utils/majorities';
1011
1112
interface Props {
1213
active: boolean;
@@ -23,15 +24,24 @@
2324
let votesPro = $state(0);
2425
let votesCon = $state(0);
2526
let votesAbstain = $state(0);
26-
let votesOutstanding = $derived(
27-
committee?.totalPresent ?? 0 - (votesPro + votesCon + votesAbstain)
28-
);
27+
let votesTotal = $derived.by(() => {
28+
switch (majority) {
29+
case 'SIMPLE':
30+
case 'TWO_THIRDS':
31+
return votesPro + votesCon;
32+
case 'ABSOLUTE':
33+
return votesPro + votesCon + votesAbstain;
34+
default:
35+
return 0;
36+
}
37+
});
2938
let majorityAmount = $derived.by(() => {
3039
switch (majority) {
3140
case 'SIMPLE':
32-
return committee?.simpleMajority ?? 0;
41+
case 'ABSOLUTE':
42+
return calculateMajority(votesTotal, 'simple');
3343
case 'TWO_THIRDS':
34-
return committee?.twoThirdsMajority ?? 0;
44+
return calculateMajority(votesTotal, 'twoThirds');
3545
default:
3646
return 0;
3747
}
@@ -110,7 +120,7 @@
110120
showOfHandsVotingVotesPro: votesPro,
111121
showOfHandsVotingVotesCon: votesCon,
112122
showOfHandsVotingVotesAbstain: votesAbstain,
113-
showOfHandsVotingVotesTotal: votesOutstanding,
123+
showOfHandsVotingVotesTotal: votesTotal,
114124
votingVoteName: voteName,
115125
votingMajority: majority,
116126
votingWithAbstentions: withAbstentions,
@@ -138,13 +148,7 @@
138148
{m.showOfHandsVoting()}
139149
</h3>
140150

141-
<ResultChart
142-
total={committee?.totalPresent}
143-
{votesPro}
144-
{votesCon}
145-
{votesAbstain}
146-
{majorityAmount}
147-
/>
151+
<ResultChart total={votesTotal} {votesPro} {votesCon} {majorityAmount} />
148152

149153
<div class="mt-6 flex gap-4">
150154
<div

src/lib/components/voting/ShowOfHandsVotingPresentation.svelte

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,11 @@
8787
in:fly={{ duration: 500, delay: 500, easing: cubicOut, x: 10 }}
8888
out:fly={{ duration: 500, easing: cubicIn, x: -10 }}
8989
>
90-
<i class="fas fa-{getFaIcon(stage).replace('fa-', '')} text-7xl"></i>
90+
<i
91+
class="fas fa-{getFaIcon(stage).replace('fa-', '')} fa-beat text-7xl"
92+
style="--fa-animation-duration: 2s;"
93+
></i>
9194
<h3 class="text-5xl font-bold">{getText(stage)}</h3>
92-
<i class="fas fa-spinner fa-spin text-2xl"></i>
9395
</div>
9496
{/snippet}
9597

@@ -118,7 +120,6 @@
118120
<ResultChart
119121
votesPro={committeeSettings.showOfHandsVotingVotesPro}
120122
votesCon={committeeSettings.showOfHandsVotingVotesCon}
121-
votesAbstain={committeeSettings.showOfHandsVotingVotesAbstain}
122123
total={committeeSettings.showOfHandsVotingVotesTotal}
123124
majorityAmount={committeeSettings.votingMajorityAmount}
124125
/>

src/lib/components/voting/VoteClicker.svelte

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,15 @@
5555
</button>
5656
<!-- <div class="countdown font-mono text-5xl">
5757
<span style="--value:{value};" aria-live="polite" aria-label={value.toString()}>{value}</span>
58-
</div> -->
59-
<div class="font-mono text-5xl">
60-
<span aria-live="polite" aria-label={value.toString()}>{value}</span>
61-
</div>
58+
</div>-->
59+
<input
60+
class="input input-xl text-center font-mono text-2xl"
61+
type="text"
62+
inputmode="numeric"
63+
disabled={!active}
64+
bind:value
65+
oninput={(e) => (value = parseInt((e.target as HTMLInputElement).value) || 0)}
66+
/>
6267
<button
6368
class="btn btn-lg"
6469
aria-label="decrease-vote"

src/lib/components/voting/VotingSetup.svelte

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
label: string;
3535
}[] = [
3636
{ id: 'SIMPLE', label: m.simpleMajority() },
37+
{ id: 'ABSOLUTE', label: m.absoluteMajority() },
3738
{ id: 'TWO_THIRDS', label: m.twoThirdsMajority() }
3839
];
3940

src/lib/local-db/localDB.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import Dexie, { type EntityTable } from 'dexie';
33

44
export type VotingStage = 'PRO' | 'CON' | 'ABSTAIN' | 'EVALUATION';
55
export type VotingOptions = 'PRO' | 'CON' | 'ABSTAIN';
6-
export type VotingMajority = 'SIMPLE' | 'TWO_THIRDS';
6+
export type VotingMajority = 'SIMPLE' | 'ABSOLUTE' | 'TWO_THIRDS';
77
interface CommitteeSettings {
88
committeeId: string;
99
layout: PresentationLayoutPresetOptions;

0 commit comments

Comments
 (0)