Skip to content

Commit

Permalink
Merge pull request #42 from iluxonchik/feature/govbot-0.0.12
Browse files Browse the repository at this point in the history
govbot 0.0.12 - Vote Counting In #admin
  • Loading branch information
iluxonchik authored Sep 5, 2024
2 parents 6b3da38 + 74480ac commit c15c9b6
Show file tree
Hide file tree
Showing 8 changed files with 1,117 additions and 814 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mina-govbot",
"version": "0.0.11",
"version": "0.0.12",
"description": "Discord bot for collective decision making for Mina Protocol",
"main": "index.js",
"directories": {
Expand Down
93 changes: 93 additions & 0 deletions src/channels/admin/actions/CountVotesAction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { Action, TrackedInteraction, Screen } from '../../../core/BaseClasses';
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder, StringSelectMenuBuilder } from 'discord.js';
import { ArgumentOracle, CustomIDOracle } from '../../../CustomIDOracle';
import { AllFundingRoundsPaginator, FundingRoundPaginator } from '../../../components/FundingRoundPaginator';
import { VoteCountingLogic } from '../../../logic/VoteCountingLogic';
import { EndUserError } from '../../../Errors';
import { AnyModalMessageComponent } from '../../../types/common';
import { DiscordStatus } from '../../DiscordStatus';

export class CountVotesAction extends Action {
public allSubActions(): Action[] {
return [];
}
getComponent(...args: any[]): AnyModalMessageComponent {
throw new Error('Method not implemented.');
}
public static readonly ID = 'countVotes';

private fundingRoundPaginator: FundingRoundPaginator;

constructor(screen: Screen, id: string) {
super(screen, id);
this.fundingRoundPaginator = new AllFundingRoundsPaginator(screen, this, 'selectPhase', 'fundingRoundPaginator');
}

protected async handleOperation(interaction: TrackedInteraction, operationId: string): Promise<void> {
switch (operationId) {
case 'selectFundingRound':
await this.handleSelectFundingRound(interaction);
break;
case 'selectPhase':
await this.handleSelectPhase(interaction);
break;
case 'countVotes':
await this.handleCountVotes(interaction);
break;
default:
throw new EndUserError('Invalid operation');
}
}

private async handleSelectFundingRound(interaction: TrackedInteraction): Promise<void> {
await this.fundingRoundPaginator.handlePagination(interaction);
}

private async handleSelectPhase(interaction: TrackedInteraction): Promise<void> {
const fundingRoundId = ArgumentOracle.getNamedArgument(interaction, ArgumentOracle.COMMON_ARGS.FUNDING_ROUND_ID, 0);

const embed = new EmbedBuilder()
.setColor('#0099ff')
.setTitle('Select Funding Round Phase')
.setDescription('Choose the phase for which you want to count votes:');

const row = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
new StringSelectMenuBuilder()
.setCustomId(CustomIDOracle.addArgumentsToAction(this, 'countVotes', ArgumentOracle.COMMON_ARGS.FUNDING_ROUND_ID, fundingRoundId.toString()))
.setPlaceholder('Select a phase')
.addOptions([
{ label: 'Consideration Phase', value: 'consideration' },
{ label: 'Deliberation Phase', value: 'deliberation' },
{ label: 'Voting Phase', value: 'voting' },
]),
);

await interaction.update({ embeds: [embed], components: [row] });
}

private async handleCountVotes(interaction: TrackedInteraction): Promise<void> {
const fundingRoundId = ArgumentOracle.getNamedArgument(interaction, ArgumentOracle.COMMON_ARGS.FUNDING_ROUND_ID);
const phase = ArgumentOracle.getNamedArgument(interaction, ArgumentOracle.COMMON_ARGS.PHASE, 0);

const voteResults = await VoteCountingLogic.countVotes(parseInt(fundingRoundId), phase);

const embed = new EmbedBuilder()
.setColor('#0099ff')
.setTitle(`Vote Count Results - ${phase.charAt(0).toUpperCase() + phase.slice(1)} Phase`)
.setDescription('Here are the vote counts for each project:');

voteResults.forEach((result, index) => {
let voteInfo = `Yes Votes: ${result.yesVotes}\nNo Votes: ${result.noVotes}`;
if (phase === 'deliberation' && result.approvedModifiedVotes !== undefined) {
voteInfo += `\nApproved Modified Votes: ${result.approvedModifiedVotes}`;
}

embed.addFields({
name: `${index + 1}. ${result.projectName} (ID: ${result.projectId})`,
value: `Proposer: ${result.proposerDuid}\n${voteInfo}`,
});
});

await interaction.update({ embeds: [embed], components: [] });
}
}
63 changes: 29 additions & 34 deletions src/channels/admin/screens/AdminHomeScreen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,20 @@ import { ManageSMEGroupsScreen } from './ManageSMEGroupsScreen';
import { ManageTopicsScreen } from './ManageTopicLogicScreen';
import { ManageFundingRoundsScreen } from './ManageFundingRoundsScreen';
import { ManageProposalStatusesScreen } from './ManageProposalStatusesScreen';

import { CountVotesScreen } from './CountVotesScreen';

export class AdminHomeScreen extends Screen implements IHomeScreen {
public static readonly ID = 'home';

protected permissions: Permission[] = []; // access allowed for all
protected manageSMEGroupsScreen: ManageSMEGroupsScreen = new ManageSMEGroupsScreen(this.dashboard, ManageSMEGroupsScreen.ID);
protected manageSMEGroupsScreen: ManageSMEGroupsScreen = new ManageSMEGroupsScreen(this.dashboard, ManageSMEGroupsScreen.ID);
protected manageTopicsScreen: ManageTopicsScreen = new ManageTopicsScreen(this.dashboard, ManageTopicsScreen.ID);
protected manageFundingRoundsScreen: ManageFundingRoundsScreen = new ManageFundingRoundsScreen(this.dashboard, ManageFundingRoundsScreen.ID);
protected manageProposalStatusesScreen: ManageProposalStatusesScreen = new ManageProposalStatusesScreen(this.dashboard, ManageProposalStatusesScreen.ID);

protected manageProposalStatusesScreen: ManageProposalStatusesScreen = new ManageProposalStatusesScreen(
this.dashboard,
ManageProposalStatusesScreen.ID,
);
protected countVotesScreen: CountVotesScreen = new CountVotesScreen(this.dashboard, CountVotesScreen.ID);

async renderToTextChannel(channel: TextChannel): Promise<void> {
const embed = this.createEmbed();
Expand All @@ -38,16 +41,12 @@ export class AdminHomeScreen extends Screen implements IHomeScreen {
return {
embeds: [embed],
components: [row],
ephemeral: true
ephemeral: true,
};
}

protected allSubScreens(): Screen[] {
return [
this.manageSMEGroupsScreen,
this.manageTopicsScreen,
this.manageFundingRoundsScreen,
]
return [this.manageSMEGroupsScreen, this.manageTopicsScreen, this.manageFundingRoundsScreen, this.countVotesScreen];
}
protected allActions(): Action[] {
return [];
Expand All @@ -61,33 +60,29 @@ export class AdminHomeScreen extends Screen implements IHomeScreen {
.addFields(
{ name: '👥 SME Management', value: 'Manage SME Groups and Users' },
{ name: '📋 Topic Management', value: 'Manage Topics and Committees' },
{ name: '💰 Funding Round Management', value: 'Manage Funding Rounds and Phases' }
{ name: '💰 Funding Round Management', value: 'Manage Funding Rounds and Phases' },
);
}

private createActionRow(): ActionRowBuilder<ButtonBuilder> {
return new ActionRowBuilder<ButtonBuilder>()
.addComponents(
new ButtonBuilder()
.setCustomId(this.manageSMEGroupsScreen.fullCustomId)
.setLabel('SME Management')
.setStyle(ButtonStyle.Primary)
.setEmoji('👥'),
new ButtonBuilder()
.setCustomId(this.manageTopicsScreen.fullCustomId)
.setLabel('Topic Management')
.setStyle(ButtonStyle.Primary)
.setEmoji('📋'),
new ButtonBuilder()
.setCustomId(this.manageFundingRoundsScreen.fullCustomId)
.setLabel('Funding Round Management')
.setStyle(ButtonStyle.Primary)
.setEmoji('💰'),
new ButtonBuilder()
.setCustomId(this.manageProposalStatusesScreen.fullCustomId)
.setLabel('Proposal Status Management')
.setStyle(ButtonStyle.Primary)
.setEmoji('📊')
);
return new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder()
.setCustomId(this.manageSMEGroupsScreen.fullCustomId)
.setLabel('SME Management')
.setStyle(ButtonStyle.Primary)
.setEmoji('👥'),
new ButtonBuilder().setCustomId(this.manageTopicsScreen.fullCustomId).setLabel('Topic Management').setStyle(ButtonStyle.Primary).setEmoji('📋'),
new ButtonBuilder()
.setCustomId(this.manageFundingRoundsScreen.fullCustomId)
.setLabel('Funding Round Management')
.setStyle(ButtonStyle.Primary)
.setEmoji('💰'),
new ButtonBuilder()
.setCustomId(this.manageProposalStatusesScreen.fullCustomId)
.setLabel('Proposal Status Management')
.setStyle(ButtonStyle.Primary)
.setEmoji('📊'),
new ButtonBuilder().setCustomId(this.countVotesScreen.fullCustomId).setLabel('Count Votes').setStyle(ButtonStyle.Primary).setEmoji('🗳️'),
);
}
}
40 changes: 40 additions & 0 deletions src/channels/admin/screens/CountVotesScreen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Screen, Dashboard, Permission, Action, TrackedInteraction } from '../../../core/BaseClasses';
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from 'discord.js';
import { CountVotesAction } from '../actions/CountVotesAction';
import { CustomIDOracle } from '../../../CustomIDOracle';

export class CountVotesScreen extends Screen {
public static readonly ID = 'countVotes';
protected permissions: Permission[] = [];
private countVotesAction: CountVotesAction;

constructor(dashboard: Dashboard, id: string) {
super(dashboard, id);
this.countVotesAction = new CountVotesAction(this, CountVotesAction.ID);
}

async getResponse(interaction: TrackedInteraction): Promise<any> {
const embed = new EmbedBuilder().setColor('#0099ff').setTitle('Count Votes').setDescription('Select a funding round to count votes for:');

const row = new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder()
.setCustomId(CustomIDOracle.addArgumentsToAction(this.countVotesAction, 'selectFundingRound'))
.setLabel('Select Funding Round')
.setStyle(ButtonStyle.Primary),
);

return {
embeds: [embed],
components: [row],
ephemeral: true,
};
}

protected allSubScreens(): Screen[] {
return [];
}

protected allActions(): Action[] {
return [this.countVotesAction];
}
}
Loading

0 comments on commit c15c9b6

Please sign in to comment.