diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000..f79f3c7 Binary files /dev/null and b/bun.lockb differ diff --git a/package.json b/package.json index 1039c00..a20c115 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "phantasma-hub", - "version": "1.0.6", + "version": "1.0.10", "private": true, "scripts": { "dev": "npm run version:update && vite dev --cors true", @@ -11,7 +11,8 @@ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "lint": "prettier --plugin-search-dir . --check . && eslint .", "format": "prettier --plugin-search-dir . --write .", - "prod": "npm run version:update && vite dev --host --port 4000" + "prod": "npm run version:update && vite dev --host --port 4000", + "bun": "bun build" }, "devDependencies": { "@iconify/svelte": "3.0.1", diff --git a/src/lib/Commands/Commands.ts b/src/lib/Commands/Commands.ts index 379b9e3..d281280 100644 --- a/src/lib/Commands/Commands.ts +++ b/src/lib/Commands/Commands.ts @@ -12,7 +12,8 @@ import type { PhantasmaLink } from 'phantasma-ts'; import { Base16, PBinaryReader, VMObject } from 'phantasma-ts/src'; import { NotificationError, - NotificationSuccess + NotificationSuccess, + NotificationWarning } from '$lib/Components/Notification/NotificationsBuilder'; import { ethers } from 'ethers'; @@ -343,3 +344,59 @@ export async function CheckURLStatus(url: string): Promise { return false; } } + +/** + * Get the Wallet Nexus + */ +export async function GetWalletNexus(connectedNexus: string) { + await Link.getNexus( + (result) => { + console.log({ result }); + if (result.nexus != connectedNexus) { + NotificationWarning( + `Wallet connected to ${result.nexus}!`, + `Wallet is connected to ${result.nexus} and the Phantasma Hub is using the ${connectedNexus} API.`, + 6000 + ); + } else { + NotificationSuccess( + `Wallet connected to ${result.nexus}!`, + `Phantasma Hub and the wallet are using the ${result.nexus} API.` + ); + } + }, + (error) => { + console.log(error); + } + ); +} + +export async function GetWalletPeer(connectedPeer: string) { + await Link.getPeer( + (result) => { + console.log('peer:', { result }); + if (result.peer != connectedPeer) { + NotificationWarning( + `Wallet connected to ${result.peer}!`, + `Wallet is connected to Peer ${result.peer} and the Phantasma Hub is using the ${connectedPeer} API.`, + 6000 + ); + } else { + NotificationSuccess( + `Wallet connected to ${result.peer}!`, + `Phantasma Hub and the wallet are using the ${result.peer} API.` + ); + } + }, + (error) => { + NotificationError('Wallet Error!', 'Please connect your wallet first.'); + console.log(error); + } + ); +} + +export function GetNexusPhantasmaLink(connectedNexus: string) { + let sb = new ScriptBuilder(); + //sb.CallRPC('interop', 'GetNexusName', []); + return sb; +} diff --git a/src/lib/Components/Airdrop/AirdropCommands.ts b/src/lib/Components/Airdrop/AirdropCommands.ts index 55a1081..7d66e10 100644 --- a/src/lib/Components/Airdrop/AirdropCommands.ts +++ b/src/lib/Components/Airdrop/AirdropCommands.ts @@ -1,10 +1,4 @@ -import { - Address, - PhantasmaAPI, - ScriptBuilder, - Token, - Base16, -} from 'phantasma-ts/src'; +import { Address, PhantasmaAPI, ScriptBuilder, Token, Base16 } from 'phantasma-ts/src'; import { AirdropFee, GasLimit, @@ -96,8 +90,8 @@ export function AirdropFT( return; } - const numberOfDistributions = userList.length / 100; - let comulativeFee = (userList.length / 100) * AirdropFee; + const numberOfDistributions = userList.length / 50; + let comulativeFee = (userList.length / 50) * AirdropFee; if (numberOfDistributions < 1) comulativeFee = AirdropFee; const from = Address.FromText(String(Link.account.address)); const payload = Base16.encode('Tools.AirdropFT'); @@ -105,14 +99,18 @@ export function AirdropFT( sb.AllowGas(from, Address.Null, gasPrice, gasLimit); if (tipActive) { - sb.CallInterop('Runtime.TransferTokens', [from, TipAddress, 'KCAL', String(comulativeFee)]); - //sb.CallInterop('Runtime.TransferTokens', [from, TipAddress, 'KCAL', comulativeFee]); + sb.CallInterop('Runtime.TransferTokens', [ + from.Text, + TipAddress, + 'KCAL', + String(comulativeFee) + ]); } for (const user of userList) { const toAddress = Address.FromText(user.user); const amount = String(user.amount); - sb.CallInterop('Runtime.TransferTokens', [from, toAddress, symbol, amount]); + sb.CallInterop('Runtime.TransferTokens', [from.Text, toAddress.Text, symbol, String(amount)]); } const myScript = sb.SpendGas(from).EndScript(); @@ -130,7 +128,7 @@ export function AirdropFT( ); }, function () { - NotificationError('Airdrop Error!', 'Error doing the Airdrop!'); + NotificationError('Airdrop Error!', 'User canceled the Airdrop!'); } ); } @@ -156,19 +154,24 @@ export function AirdropNFT(symbol: string, userList: Array<{ user; id }>, totalA const from = Address.FromText(String(Link.account.address)); const payload = Base16.encode('Tools.AirdropNFT'); - const numberOfDistributions = userList.length / 100; - let comulativeFee = (userList.length / 100) * AirdropFee; + const numberOfDistributions = userList.length / 50; + let comulativeFee = (userList.length / 50) * AirdropFee; if (numberOfDistributions < 1) comulativeFee = AirdropFee; const sb = new ScriptBuilder(); sb.AllowGas(from, Address.Null, gasPrice, gasLimit); if (tipActive) { - //sb.CallInterop('Runtime.TransferTokens', [from, TipAddress, 'KCAL', comulativeFee]); + sb.CallInterop('Runtime.TransferTokens', [ + from.Text, + TipAddress, + 'KCAL', + String(comulativeFee) + ]); } for (const user of userList) { const toAddress = Address.FromText(user.user); const id = String(user.id); - sb.CallInterop('Runtime.TransferToken', [from, toAddress, symbol, id]); + sb.CallInterop('Runtime.TransferToken', [from.Text, toAddress.Text, symbol, String(id)]); } const myScript = sb.SpendGas(from).EndScript(); @@ -183,7 +186,7 @@ export function AirdropNFT(symbol: string, userList: Array<{ user; id }>, totalA ); }, function () { - NotificationError('Airdrop Error!', 'Error doing the Airdrop!'); + NotificationError('Airdrop Error!', 'User canceled the Airdrop!'); } ); } diff --git a/src/lib/Components/Airdrop/AirdropFT.svelte b/src/lib/Components/Airdrop/AirdropFT.svelte index 673af3f..532909c 100644 --- a/src/lib/Components/Airdrop/AirdropFT.svelte +++ b/src/lib/Components/Airdrop/AirdropFT.svelte @@ -164,6 +164,17 @@ continue; } + if (userDistribution == 0) { + if (userAddressess.length >= numberOfUsers) { + numberOfInvalidAddresses++; + userAddressessRAWEdited = userAddressessRAWEdited.replace( + addr, + `${addr}` + ); + continue; + } + } + if (userAddressess.includes(addrTrimmed)) { numberOfRepeatedAddresses++; userAddressessRAWEdited = userAddressessRAWEdited.replaceAll( @@ -196,7 +207,43 @@ } function onChangeNumberOfUsers() { - console.log(numberOfUsers); + let listBefore; + listBefore = userAddressessRAW.split(/[\n ,]+/); + userAddressessRAW = listBefore.join('\n'); + userAddressessRAWEdited = listBefore.join('
'); + + numberOfInvalidAddresses = 0; + numberOfRepeatedAddresses = 0; + userAddressess = []; + for (let addr of listBefore) { + let addrTrimmed = addr.trim(); + if (!Address.IsValidAddress(addrTrimmed)) { + numberOfInvalidAddresses++; + //userAddressessRAW = userAddressessRAW.replace(addr, `${addr}`); + continue; + } + + if (userDistribution == 0) { + if (userAddressess.length >= numberOfUsers) { + numberOfInvalidAddresses++; + userAddressessRAWEdited = userAddressessRAWEdited.replace( + addr, + `${addr}` + ); + continue; + } + } + + if (userAddressess.includes(addrTrimmed)) { + numberOfRepeatedAddresses++; + userAddressessRAWEdited = userAddressessRAWEdited.replaceAll( + addr, + `${addr}` + ); + } + + userAddressess.push(addr); + } } @@ -330,6 +377,9 @@ id="numberOfUsers" bind:value={numberOfUsers} on:change={onChangeNumberOfUsers} + on:keypress={onChangeNumberOfUsers} + on:keydown={onChangeNumberOfUsers} + on:keyup={onChangeNumberOfUsers} class="block py-2.5 px-0 w-full text-sm text-gray-900 bg-transparent border-solid border-b-2 border-gray-300 appearance-none dark:text-white dark:border-gray-600 dark:focus:border-blue-500 focus:outline-none focus:ring-0 focus:border-blue-600 peer" placeholder=" " required diff --git a/src/lib/Components/Airdrop/AirdropNFT.svelte b/src/lib/Components/Airdrop/AirdropNFT.svelte index 6d8ebe4..a00471c 100644 --- a/src/lib/Components/Airdrop/AirdropNFT.svelte +++ b/src/lib/Components/Airdrop/AirdropNFT.svelte @@ -161,6 +161,17 @@ continue; } + if (userDistribution == 0) { + if (userAddressess.length >= numberOfUsers) { + numberOfInvalidAddresses++; + userAddressessRAWEdited = userAddressessRAWEdited.replace( + addr, + `${addr}` + ); + continue; + } + } + if (userAddressess.includes(addrTrimmed)) { numberOfRepeatedAddresses++; userAddressessRAWEdited = userAddressessRAWEdited.replaceAll( @@ -188,6 +199,46 @@ console.log(selectedToken); listOfNFTs = await GetNFTList(selectedToken); } + + function onChangeNumberOfUsers() { + let listBefore; + listBefore = userAddressessRAW.split(/[\n ,]+/); + userAddressessRAW = listBefore.join('\n'); + userAddressessRAWEdited = listBefore.join('
'); + + numberOfInvalidAddresses = 0; + numberOfRepeatedAddresses = 0; + userAddressess = []; + for (let addr of listBefore) { + let addrTrimmed = addr.trim(); + if (!Address.IsValidAddress(addrTrimmed)) { + numberOfInvalidAddresses++; + //userAddressessRAWEdited = userAddressessRAWEdited.replace(addr, `${addr}`); + continue; + } + + if (userDistribution == 0) { + if (userAddressess.length >= numberOfUsers) { + numberOfInvalidAddresses++; + userAddressessRAWEdited = userAddressessRAWEdited.replace( + addr, + `${addr}` + ); + continue; + } + } + + if (userAddressess.includes(addrTrimmed)) { + numberOfRepeatedAddresses++; + userAddressessRAWEdited = userAddressessRAWEdited.replaceAll( + addr, + `${addr}` + ); + } + + userAddressess.push(addr); + } + } ${nexusName} network.`); diff --git a/src/lib/Components/Card/Card.svelte b/src/lib/Components/Card/Card.svelte index df1ab9b..f09bd0e 100644 --- a/src/lib/Components/Card/Card.svelte +++ b/src/lib/Components/Card/Card.svelte @@ -15,8 +15,8 @@ {#if size == 'xs'}
@@ -46,8 +46,8 @@ {#if size == 'xs-c'}
@@ -61,8 +61,8 @@ {#if size == 'sm'}
@@ -95,8 +95,8 @@ {#if size == 'md'}
@@ -132,8 +132,8 @@ class="w-full max-w-full px-3 mt-0 mb-6 md:mb-0 md:w-1/2 md:flex-none lg:w-2/3 lg:flex-none" >
@@ -159,8 +159,8 @@ {#if size == 'xl'}
diff --git a/src/lib/Components/Footer/Footer.svelte b/src/lib/Components/Footer/Footer.svelte index be98e40..fb0c701 100644 --- a/src/lib/Components/Footer/Footer.svelte +++ b/src/lib/Components/Footer/Footer.svelte @@ -28,6 +28,7 @@ rel="noreferrer">Phantasma Contributors. All Rights Reserved. +
Developed with by diff --git a/src/lib/Components/Notification/NotificationsBuilder.ts b/src/lib/Components/Notification/NotificationsBuilder.ts index 855a607..244ec6d 100644 --- a/src/lib/Components/Notification/NotificationsBuilder.ts +++ b/src/lib/Components/Notification/NotificationsBuilder.ts @@ -38,10 +38,14 @@ export function NotificationError(title: string, message: string) { }); } -export function NotificationWarning(title: string = "Warning!", message: string) { +export function NotificationWarning( + title: string = 'Warning!', + message: string, + duration: number = 3000 +) { const finalMessage = `
${title}
${message}`; toast.push(finalMessage, { - duration: 3000, + duration: duration, theme: { '--toastColor': 'mintcream', '--toastBackground': 'rgb(251 146 60)', @@ -50,6 +54,22 @@ export function NotificationWarning(title: string = "Warning!", message: string) }); } +export function NotificationInformation( + title: string = 'Information!', + message: string, + duration: number = 3000 +) { + const finalMessage = `
${title}
${message}`; + toast.push(finalMessage, { + duration: duration, + theme: { + '--toastColor': 'mintcream', + '--toastBackground': '#4299e1', + '--toastBarBackground': '#2a4365' + } + }); +} + export function ClearNotifications() { toast.pop(0); } diff --git a/src/lib/Components/Sidebar/Sidebar.svelte b/src/lib/Components/Sidebar/Sidebar.svelte index 6682e34..32a275a 100644 --- a/src/lib/Components/Sidebar/Sidebar.svelte +++ b/src/lib/Components/Sidebar/Sidebar.svelte @@ -19,7 +19,8 @@ DefaultAPIURL, ExplorerURL, ExplorerURLMainnet, - ExplorerURLTestnet + ExplorerURLTestnet, + SelectedNexus } from '$lib/store'; import { PhantasmaLink, PhantasmaAPI } from 'phantasma-ts'; import { ScriptBuilder, PBinaryReader, Base16, VMObject } from 'phantasma-ts/src'; @@ -102,6 +103,7 @@ nexusName = e.target.selectedOptions[0].dataset.net; PhantasmaAPIClient.set(new PhantasmaAPI(selectedAPI, null, nexusName)); API_URL.set(selectedAPI); + SelectedNexus.set(nexusName); ExplorerURL.set(nexusName == 'mainnet' ? ExplorerURLMainnet : ExplorerURLTestnet); connectToAPI(); } diff --git a/src/lib/Components/Votes/CreatePoll.svelte b/src/lib/Components/Votes/CreatePoll.svelte index 5e969f6..e7b65b2 100644 --- a/src/lib/Components/Votes/CreatePoll.svelte +++ b/src/lib/Components/Votes/CreatePoll.svelte @@ -42,11 +42,12 @@ let endTime: Date = new Date(Date.now()); let endTimeStr: string = ''; let choicesPerUser: BigInt = BigInt(1); + let isPollCreated = false; export let organizations: Organization[] = []; function createPoll() { - console.log(choices); + validateSubject(); initPoll( subject, organization.name, @@ -62,13 +63,23 @@ function addChoice() { numberOfChoices++; + validateSubject(); + } + + function validateSubject() { + subject = subject.replace(/[^a-zA-Z0-9 _?!.,]/g, ''); + subject = subject.trimStart(); + subject = subject.trimEnd(); } function handleStartTimeChange() { let startDate = new Date(startTimeStr); - let formattedDate = moment(startDate.getTime() + 1000 * 60 * 60 * 24).format(DateTimeFormat); + let formattedDate = moment(startDate.getTime() + 1000 * 60 * 60 * 24 * 7).format( + DateTimeFormat + ); endTimeStr = formattedDate; + validateSubject(); } function initDates() { @@ -77,7 +88,13 @@ startTimeStr = moment(startTime.getTime()).format(DateTimeFormat); let startDate = new Date(startTimeStr); //endTime = moment(startDate.getTime() + 1000 * 60 * 60 * 24).format('yyyy-MM-DDThh:mm'); - endTimeStr = moment(startDate.getTime() + 1000 * 60 * 60 * 24).format(DateTimeFormat); + endTimeStr = moment(startDate.getTime() + 1000 * 60 * 60 * 24 * 7).format(DateTimeFormat); + } + + function onSubjectChange() { + // On don't remove _, ? and ! from the subject and allow upper and lower case letters and numbers and . and , + subject = subject.replace(/[^a-zA-Z0-9 _?!.,]/g, ''); + subject = subject.trimStart(); } initDates(); @@ -98,6 +115,9 @@ name="subject" id="subject" bind:value={subject} + on:change={onSubjectChange} + on:keydown={onSubjectChange} + on:keypress={onSubjectChange} class="block py-2.5 px-0 w-full text-sm text-gray-900 bg-transparent border-solid border-b-2 border-gray-300 appearance-none dark:text-white dark:border-gray-600 dark:focus:border-blue-500 focus:outline-none focus:ring-0 focus:border-blue-600 peer" placeholder=" " required diff --git a/src/lib/Components/Votes/PollDetails.svelte b/src/lib/Components/Votes/PollDetails.svelte index 8a2d6ff..e082c20 100644 --- a/src/lib/Components/Votes/PollDetails.svelte +++ b/src/lib/Components/Votes/PollDetails.svelte @@ -7,18 +7,14 @@ import { ConsensusMode, ConsensusPoll, - Organization, PhantasmaLink, PollChoice, PollState, PollValue, Timestamp } from 'phantasma-ts/src'; - //import { e } from 'vitest/dist/index-5aad25c1'; + import { Organization } from 'phantasma-ts'; - /** - * @type {{ text: any; subject: any; description: any; options: any; votes: any; voters: any; status: any; created: any; expires: any; }} - */ export let id: string; export let poll: ConsensusPoll; export let organizations: Organization[]; @@ -38,6 +34,7 @@ let choices: PollChoice[] = new Array(); let entries: PollValue[] = new Array(); let selected; + let pollStateColor: string; afterUpdate(async () => { Init(); @@ -53,31 +50,8 @@ console.log('Init choices'); choices = new Array(); entries = new Array(); - + choices = poll.entries.map((entry) => new PollChoice(entry.value)); entries = poll.entries; - - /*for (let i = 0; i < poll.entries.length; i++) { - let choice: PollChoice = new PollChoice(''); - let entry = poll.entries[i] as unknown as string; - //let bytes = Base16.decodeUint8Array(entry); - //let reader = new PBinaryReader(bytes); - //let pollValue = new PollValue(); - //pollValue.UnserializeData(reader); - choice.value = poll.entries[i].value; // Base16.decode(uint8ArrayToStringDefault()); - choices.push(choice); - }*/ - - for (let entry in poll.entries) { - /*let reader: PBinaryReader = new PBinaryReader( - Base16.decodeUint8Array(poll.entries[entry] as unknown as string) - ); - let pollValue: PollValue = new PollValue(); - pollValue.UnserializeData(reader);*/ - //entries.push(entry); - } - //VMObject.FromBytes(Base16.decodeUint8Array(poll.entries as unknown as string)); - - //entries = VMObject.FromBytes(Base16.decodeUint8Array(poll.entries as unknown as string)); } function vote() { @@ -91,19 +65,21 @@ function initPollState() { console.log('Init Poll State'); - if (PollState.Inactive == poll.state) { - console.log( - poll.startTime.value <= timeNow, - poll.endTime.value >= timeNow, - poll.startTime.value, - poll.endTime.value, - timeNow - ); - if (poll.startTime.value <= timeNow && poll.endTime.value >= timeNow) { - poll.state = PollState.Active; - } else if (timeNow >= poll.endTime.value) { + if (timeNow >= poll.startTime.value && poll.endTime.value >= timeNow) { + poll.state = PollState.Active; + pollStateColor = 'bg-blue-300'; + if (poll.endTime.value - timeNow <= 60 * 12) { + pollStateColor = 'bg-yellow-300'; + } + } else if (timeNow >= poll.endTime.value) { + if (poll.state == PollState.Consensus) { + pollStateColor = 'bg-green-300'; + } else { poll.state = PollState.Failure; + pollStateColor = 'bg-red-300'; } + } else { + pollStateColor = 'bg-blue-300'; } } @@ -122,6 +98,7 @@ description="Consensus Poll details for {poll.subject}{poll.endTime.value * 1000 >= Date.now() ? ` (Finish ${moment(poll.endTime.value * 1000).fromNow()})` : ''}." + class={pollStateColor} >
null}> diff --git a/src/lib/Components/Votes/PollList.svelte b/src/lib/Components/Votes/PollList.svelte index 2eb8e2d..a6c7841 100644 --- a/src/lib/Components/Votes/PollList.svelte +++ b/src/lib/Components/Votes/PollList.svelte @@ -1,10 +1,29 @@ +
+
Filters
+ +
- {#each polls as poll} + {#each filteredPolls as poll}
diff --git a/src/lib/Components/Votes/PollListItem.svelte b/src/lib/Components/Votes/PollListItem.svelte index 4bc6be5..081aa42 100644 --- a/src/lib/Components/Votes/PollListItem.svelte +++ b/src/lib/Components/Votes/PollListItem.svelte @@ -39,6 +39,7 @@ let choices: PollChoice[] = new Array(); let entries: PollValue[] = new Array(); let selected; + let pollStateColor: string = 'bg-red-300'; beforeUpdate(async () => { initDates(); @@ -91,19 +92,29 @@ } function initPollState() { - if (PollState.Inactive == poll.state) { - console.log( - poll.startTime.value <= timeNow, - poll.endTime.value >= timeNow, - poll.startTime.value, - poll.endTime.value, - timeNow - ); - if (poll.startTime.value <= timeNow && poll.endTime.value >= timeNow) { - poll.state = PollState.Active; - } else if (timeNow >= poll.endTime.value) { + /*console.log( + poll.startTime.value <= timeNow, + poll.endTime.value >= timeNow, + poll.startTime.value, + poll.endTime.value, + timeNow + );*/ + + if (timeNow >= poll.startTime.value && poll.endTime.value >= timeNow) { + poll.state = PollState.Active; + pollStateColor = 'bg-blue-300'; + if (poll.endTime.value - timeNow <= 60 * 12) { + pollStateColor = 'bg-yellow-300'; + } + } else if (timeNow >= poll.endTime.value) { + if (poll.state == PollState.Consensus) { + pollStateColor = 'bg-green-300'; + } else { poll.state = PollState.Failure; + pollStateColor = 'bg-red-300'; } + } else { + pollStateColor = 'bg-blue-300'; } } @@ -115,6 +126,11 @@ initDates(); initChoices(); initPollState(); + + // red -> Ended + // green -> Consensus + // blue -> Pending / Voting + // yellow -> Close to end / Voting /* Poll ends in {poll.endTime.value * 1000 >= Timestamp.now ? ` (Finish ${moment(poll.endTime.value * 1000).fromNow()}) @@ -128,6 +144,7 @@ description={poll.endTime.value * 1000 <= Timestamp.now ? `Poll ended.` : `Poll will end in ${moment(poll.endTime.value * 1000).fromNow()}`} + class="{pollStateColor} " >
-
+
diff --git a/src/routes/votes/+page.svelte b/src/routes/votes/+page.svelte index 6fb2f5e..c5e40df 100644 --- a/src/routes/votes/+page.svelte +++ b/src/routes/votes/+page.svelte @@ -5,7 +5,8 @@ import PollDetails from '$lib/Components/Votes/PollDetails.svelte'; import { getConsensusPoll, getConsensusPolls } from '$lib/Components/Wallet/VoteCommands'; import { IsPollCreated, PhantasmaAPIClient } from '$lib/store'; - import type { ConsensusPoll, Organization, PhantasmaAPI } from 'phantasma-ts/src'; + import { type ConsensusPoll, type Organization, PhantasmaAPI } from 'phantasma-ts/src'; + import { PollState, Timestamp } from 'phantasma-ts'; let api: PhantasmaAPI; PhantasmaAPIClient.subscribe(async (value) => { @@ -26,10 +27,89 @@ let createPoll = false; - let pollSelected: ConsensusPoll | null; + let pollSelected: ConsensusPoll | null = null; + //let nullPoll: ConsensusPoll | null | undefined = null; + + function fixPollsData() { + const timeNow = Timestamp.now; + + for (let i = 0; i < polls.length; i++) { + if (polls[i].state == PollState.Consensus || polls[i].state == PollState.Failure) { + continue; + } + + if (polls[i].startTime.value <= timeNow && polls[i].endTime.value >= timeNow) { + polls[i].state = PollState.Active; + } else if (timeNow >= polls[i].endTime.value) { + if (polls[i].state == PollState.Consensus) { + polls[i].state = PollState.Consensus; + } else { + polls[i].state = PollState.Failure; + } + } + } + } async function getPolls() { polls = await getConsensusPolls(); + + // Fix polls + if (polls.length > 0) fixPollsData(); + + const timeNow = Timestamp.now; + + // sort polls + polls = polls.sort((a, b) => { + // Rule 1: Active polls should be at the top + if (a.state === PollState.Active && b.state !== PollState.Active) { + return -1; + } + if (b.state === PollState.Active && a.state !== PollState.Active) { + return 1; + } + + // Rule 5: Inactive polls within startTime and endTime should be above Consensus but below Active + const now = new Date(); + const aInactiveValid = + a.state === PollState.Inactive && + timeNow >= a.startTime.value && + timeNow <= a.endTime.value; + const bInactiveValid = + b.state === PollState.Inactive && + timeNow >= b.startTime.value && + timeNow <= b.endTime.value; + + if (aInactiveValid && !bInactiveValid) { + return -1; + } + if (bInactiveValid && !aInactiveValid) { + return 1; + } + + // Rule 2: Consensus polls should be below Active but above others + if (a.state === PollState.Consensus && b.state !== PollState.Consensus) { + return -1; + } + if (b.state === PollState.Consensus && a.state !== PollState.Consensus) { + return 1; + } + + // Rule 3 and 4: Failure polls and inactive polls with a past endTime should go down + if ( + a.state === PollState.Failure || + (a.state === PollState.Inactive && timeNow > a.endTime.value) + ) { + return 1; + } + if ( + b.state === PollState.Failure || + (b.state === PollState.Inactive && timeNow > b.endTime.value) + ) { + return -1; + } + + return 0; // No change for equal states or other conditions + }); } async function getPoll(subject: string) { @@ -44,7 +124,15 @@ }); } - function onPollChange(e) {} + function onPollChange(e) { + console.log('poll change', e.target.value); + createPoll = false; + } + + function onCreatePollBtn() { + createPoll = !createPoll; + pollSelected = null; + } //getPoll('system.nexus.protocol.version'); getOrganizations(); @@ -63,7 +151,7 @@