feat: timeline
This commit is contained in:
parent
1e1472e0d5
commit
ba4ec2abf2
@ -1,318 +1,355 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import ObjectElement from '@/components/dynamic/ObjectElement.vue';
|
import ObjectElement from '@/components/dynamic/ObjectElement.vue';
|
||||||
import { useBaseStore, useFormatter, useGovStore, useStakingStore, useTxDialog } from '@/stores';
|
import {
|
||||||
import type { GovProposal, GovVote, PaginabledAccounts, PaginatedProposalDeposit, PaginatedProposalVotes, Pagination } from '@/types';
|
useBaseStore,
|
||||||
import { ref , reactive} from 'vue';
|
useFormatter,
|
||||||
|
useGovStore,
|
||||||
|
useStakingStore,
|
||||||
|
useTxDialog,
|
||||||
|
} from '@/stores';
|
||||||
|
import type {
|
||||||
|
GovProposal,
|
||||||
|
GovVote,
|
||||||
|
PaginabledAccounts,
|
||||||
|
PaginatedProposalDeposit,
|
||||||
|
PaginatedProposalVotes,
|
||||||
|
Pagination,
|
||||||
|
} from '@/types';
|
||||||
|
import { ref, reactive } from 'vue';
|
||||||
import Countdown from '@/components/Countdown.vue';
|
import Countdown from '@/components/Countdown.vue';
|
||||||
import { computed } from '@vue/reactivity';
|
import { computed } from '@vue/reactivity';
|
||||||
|
|
||||||
const props = defineProps(["proposal_id", "chain"]);
|
const props = defineProps(['proposal_id', 'chain']);
|
||||||
const proposal = ref({} as GovProposal)
|
const proposal = ref({} as GovProposal);
|
||||||
const format = useFormatter()
|
const format = useFormatter();
|
||||||
const store = useGovStore()
|
const store = useGovStore();
|
||||||
const dialog = useTxDialog()
|
const dialog = useTxDialog();
|
||||||
|
|
||||||
store.fetchProposal(props.proposal_id).then((res) => {
|
store.fetchProposal(props.proposal_id).then((res) => {
|
||||||
const proposalDetail = reactive(res.proposal)
|
const proposalDetail = reactive(res.proposal);
|
||||||
// when status under the voting, final_tally_result are no data, should request fetchTally
|
// when status under the voting, final_tally_result are no data, should request fetchTally
|
||||||
if (res.proposal?.status === 'PROPOSAL_STATUS_VOTING_PERIOD'){
|
if (res.proposal?.status === 'PROPOSAL_STATUS_VOTING_PERIOD') {
|
||||||
store.fetchTally(props.proposal_id).then((tallRes)=>{
|
store.fetchTally(props.proposal_id).then((tallRes) => {
|
||||||
proposalDetail.final_tally_result = tallRes?.tally
|
proposalDetail.final_tally_result = tallRes?.tally;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
proposal.value = proposalDetail
|
proposal.value = proposalDetail;
|
||||||
})
|
});
|
||||||
|
|
||||||
const color = computed(() => {
|
const color = computed(() => {
|
||||||
if (proposal.value.status==='PROPOSAL_STATUS_PASSED') {
|
if (proposal.value.status === 'PROPOSAL_STATUS_PASSED') {
|
||||||
return "success"
|
return 'success';
|
||||||
}else if (proposal.value.status==='PROPOSAL_STATUS_REJECTED') {
|
} else if (proposal.value.status === 'PROPOSAL_STATUS_REJECTED') {
|
||||||
return "error"
|
return 'error';
|
||||||
}
|
}
|
||||||
return ""
|
return '';
|
||||||
})
|
});
|
||||||
const status = computed(() => {
|
const status = computed(() => {
|
||||||
if(proposal.value.status) {
|
if (proposal.value.status) {
|
||||||
return proposal.value.status.replace("PROPOSAL_STATUS_", "")
|
return proposal.value.status.replace('PROPOSAL_STATUS_', '');
|
||||||
}
|
}
|
||||||
return ""
|
return '';
|
||||||
})
|
});
|
||||||
|
|
||||||
const deposit = ref({} as PaginatedProposalDeposit)
|
const deposit = ref({} as PaginatedProposalDeposit);
|
||||||
store.fetchProposalDeposits(props.proposal_id).then(x => deposit.value = x)
|
store.fetchProposalDeposits(props.proposal_id).then((x) => (deposit.value = x));
|
||||||
|
|
||||||
const votes = ref({} as GovVote[])
|
const votes = ref({} as GovVote[]);
|
||||||
const votePage = ref({} as Pagination)
|
const votePage = ref({} as Pagination);
|
||||||
const loading = ref(false)
|
const loading = ref(false);
|
||||||
|
|
||||||
store.fetchProposalVotes(props.proposal_id).then(x => {
|
store.fetchProposalVotes(props.proposal_id).then((x) => {
|
||||||
votes.value = x.votes
|
votes.value = x.votes;
|
||||||
votePage.value = x.pagination
|
votePage.value = x.pagination;
|
||||||
})
|
});
|
||||||
|
|
||||||
function loadMore() {
|
function loadMore() {
|
||||||
if(votePage.value.next_key) {
|
if (votePage.value.next_key) {
|
||||||
loading.value = true
|
loading.value = true;
|
||||||
store.fetchProposalVotes(props.proposal_id, votePage.value.next_key).then(x => {
|
store
|
||||||
votes.value = votes.value.concat(x.votes)
|
.fetchProposalVotes(props.proposal_id, votePage.value.next_key)
|
||||||
votePage.value = x.pagination
|
.then((x) => {
|
||||||
loading.value = false
|
votes.value = votes.value.concat(x.votes);
|
||||||
})
|
votePage.value = x.pagination;
|
||||||
}
|
loading.value = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function shortTime(v: string) {
|
function shortTime(v: string) {
|
||||||
if(v) {
|
if (v) {
|
||||||
return format.toDay(v, "from")
|
return format.toDay(v, 'from');
|
||||||
}
|
}
|
||||||
return ""
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
const votingCountdown = computed((): number => {
|
const votingCountdown = computed((): number => {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const end = new Date(proposal.value.voting_end_time)
|
const end = new Date(proposal.value.voting_end_time);
|
||||||
return end.getTime() - now.getTime()
|
return end.getTime() - now.getTime();
|
||||||
})
|
});
|
||||||
|
|
||||||
const upgradeCountdown = computed((): number => {
|
const upgradeCountdown = computed((): number => {
|
||||||
const height = Number(proposal.value.content?.plan?.height || 0)
|
const height = Number(proposal.value.content?.plan?.height || 0);
|
||||||
if(height > 0) {
|
if (height > 0) {
|
||||||
const base = useBaseStore()
|
const base = useBaseStore();
|
||||||
const current = Number(base.latest?.block?.header?.height || 0)
|
const current = Number(base.latest?.block?.header?.height || 0);
|
||||||
return (height - current) * 6 * 1000
|
return (height - current) * 6 * 1000;
|
||||||
}
|
}
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const end = new Date(proposal.value.content?.plan?.time || "")
|
const end = new Date(proposal.value.content?.plan?.time || '');
|
||||||
return end.getTime() - now.getTime()
|
return end.getTime() - now.getTime();
|
||||||
})
|
});
|
||||||
|
|
||||||
const total = computed(()=> {
|
const total = computed(() => {
|
||||||
const tally = proposal.value.final_tally_result
|
const tally = proposal.value.final_tally_result;
|
||||||
let sum = 0
|
let sum = 0;
|
||||||
if(tally) {
|
if (tally) {
|
||||||
sum += Number(tally.abstain || 0)
|
sum += Number(tally.abstain || 0);
|
||||||
sum += Number(tally.yes || 0)
|
sum += Number(tally.yes || 0);
|
||||||
sum += Number(tally.no || 0)
|
sum += Number(tally.no || 0);
|
||||||
sum += Number(tally.no_with_veto || 0)
|
sum += Number(tally.no_with_veto || 0);
|
||||||
|
}
|
||||||
}
|
return sum;
|
||||||
return sum
|
});
|
||||||
})
|
|
||||||
|
|
||||||
const turnout = computed(() => {
|
const turnout = computed(() => {
|
||||||
if (total.value > 0) {
|
if (total.value > 0) {
|
||||||
const bonded = useStakingStore().pool?.bonded_tokens || "1"
|
const bonded = useStakingStore().pool?.bonded_tokens || '1';
|
||||||
return format.percent(total.value / Number(bonded))
|
return format.percent(total.value / Number(bonded));
|
||||||
}
|
}
|
||||||
return 0
|
return 0;
|
||||||
})
|
});
|
||||||
|
|
||||||
const yes = computed(()=> {
|
const yes = computed(() => {
|
||||||
if(total.value > 0) {
|
if (total.value > 0) {
|
||||||
const yes = proposal.value?.final_tally_result?.yes || 0
|
const yes = proposal.value?.final_tally_result?.yes || 0;
|
||||||
return format.percent(Number(yes) / total.value )
|
return format.percent(Number(yes) / total.value);
|
||||||
}
|
}
|
||||||
return 0
|
return 0;
|
||||||
})
|
});
|
||||||
|
|
||||||
const no = computed(()=> {
|
const no = computed(() => {
|
||||||
if(total.value > 0) {
|
if (total.value > 0) {
|
||||||
const value = proposal.value?.final_tally_result?.no || 0
|
const value = proposal.value?.final_tally_result?.no || 0;
|
||||||
return format.percent(Number(value) / total.value)
|
return format.percent(Number(value) / total.value);
|
||||||
}
|
}
|
||||||
return 0
|
return 0;
|
||||||
})
|
});
|
||||||
|
|
||||||
const veto = computed(()=> {
|
const veto = computed(() => {
|
||||||
if(total.value > 0) {
|
if (total.value > 0) {
|
||||||
const value = proposal.value?.final_tally_result?.no_with_veto || 0
|
const value = proposal.value?.final_tally_result?.no_with_veto || 0;
|
||||||
return format.percent(Number(value) / total.value)
|
return format.percent(Number(value) / total.value);
|
||||||
}
|
}
|
||||||
return 0
|
return 0;
|
||||||
})
|
});
|
||||||
|
|
||||||
const abstain = computed(()=> {
|
const abstain = computed(() => {
|
||||||
if(total.value > 0) {
|
if (total.value > 0) {
|
||||||
const value = proposal.value?.final_tally_result?.abstain || 0
|
const value = proposal.value?.final_tally_result?.abstain || 0;
|
||||||
return format.percent(Number(value) / total.value)
|
return format.percent(Number(value) / total.value);
|
||||||
}
|
}
|
||||||
return 0
|
return 0;
|
||||||
})
|
});
|
||||||
const processList = computed(()=>{
|
const processList = computed(() => {
|
||||||
return [
|
return [
|
||||||
{name: 'Turnout', value : turnout.value, class: 'bg-info' },
|
{ name: 'Turnout', value: turnout.value, class: 'bg-info' },
|
||||||
{name: 'Yes', value : yes.value, class: 'bg-success' },
|
{ name: 'Yes', value: yes.value, class: 'bg-success' },
|
||||||
{name: 'No', value : no.value, class: 'bg-error' },
|
{ name: 'No', value: no.value, class: 'bg-error' },
|
||||||
{name: 'No With Veto', value : veto.value, class: 'bg-primary' },
|
{ name: 'No With Veto', value: veto.value, class: 'bg-primary' },
|
||||||
{name: 'Abstain', value : abstain.value, class: 'bg-warning' }
|
{ name: 'Abstain', value: abstain.value, class: 'bg-warning' },
|
||||||
]
|
];
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
||||||
<h2 class="card-title flex flex-col md:justify-between md:flex-row">
|
<h2 class="card-title flex flex-col md:justify-between md:flex-row">
|
||||||
<p class="truncate w-full">{{ proposal_id }}. {{ proposal.content?.title }} </p>
|
<p class="truncate w-full">
|
||||||
<div
|
{{ proposal_id }}. {{ proposal.content?.title }}
|
||||||
class="badge badge-ghost"
|
</p>
|
||||||
:class="
|
<div
|
||||||
color === 'success'
|
class="badge badge-ghost"
|
||||||
? 'text-yes'
|
:class="
|
||||||
: color === 'error'
|
color === 'success'
|
||||||
? 'text-no'
|
? 'text-yes'
|
||||||
: 'text-info'
|
: color === 'error'
|
||||||
"
|
? 'text-no'
|
||||||
>{{ status }}</div>
|
: 'text-info'
|
||||||
</h2>
|
"
|
||||||
<div class="">
|
>
|
||||||
<ObjectElement :value="proposal.content"/>
|
{{ status }}
|
||||||
</div>
|
</div>
|
||||||
|
</h2>
|
||||||
|
<div class="">
|
||||||
|
<ObjectElement :value="proposal.content" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- grid lg:grid-cols-3 auto-rows-max-->
|
<!-- grid lg:grid-cols-3 auto-rows-max-->
|
||||||
<!-- flex-col lg:flex-row flex -->
|
<!-- flex-col lg:flex-row flex -->
|
||||||
<div class="gap-4 mb-4 grid lg:grid-cols-3 auto-rows-max ">
|
<div class="gap-4 mb-4 grid lg:grid-cols-3 auto-rows-max">
|
||||||
<!-- flex-1 -->
|
<!-- flex-1 -->
|
||||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded shadow ">
|
<div class="bg-base-100 px-4 pt-3 pb-4 rounded shadow">
|
||||||
<h2 class="card-title">Tally</h2>
|
<h2 class="card-title mb-1">Tally</h2>
|
||||||
<div v-for="(item,index) of processList" :key="index">
|
<div class="mb-1" v-for="(item, index) of processList" :key="index">
|
||||||
<label class="block">{{item.name }}</label>
|
<label class="block text-sm mb-1">{{ item.name }}</label>
|
||||||
<div class="h-6 w-full relative">
|
<div class="h-5 w-full relative">
|
||||||
<div class="absolute inset-x-0 inset-y-0 w-full opacity-10 rounded-sm" :class="`${item.class}`"></div>
|
<div
|
||||||
<div class="absolute inset-x-0 inset-y-0 rounded-sm" :class="`${item.class}`" :style="`width: ${item.value}`"></div>
|
class="absolute inset-x-0 inset-y-0 w-full opacity-10 rounded-sm"
|
||||||
<p class="absolute inset-x-0 inset-y-0 text-center text-sm text-[#666] dark:text-[#eee] flex items-center justify-center">{{ item.value }}</p>
|
:class="`${item.class}`"
|
||||||
</div>
|
></div>
|
||||||
</div>
|
<div
|
||||||
<div>
|
class="absolute inset-x-0 inset-y-0 rounded-sm"
|
||||||
<label for="vote" class="btn btn-primary float-right btn-sm mx-1" @click="dialog.open('vote', {proposal_id})">Vote</label>
|
:class="`${item.class}`"
|
||||||
<label for="deposit" class="btn btn-primary float-right btn-sm mx-1" @click="dialog.open('deposit', {proposal_id})">Deposit</label>
|
:style="`width: ${item.value}`"
|
||||||
</div>
|
></div>
|
||||||
</div>
|
<p
|
||||||
<!-- lg:col-span-2 -->
|
class="absolute inset-x-0 inset-y-0 text-center text-sm text-[#666] dark:text-[#eee] flex items-center justify-center"
|
||||||
<!-- lg:flex-[2_2_0%] -->
|
|
||||||
<div class="h-max bg-base-100 px-4 pt-3 pb-4 rounded shadow lg:col-span-2">
|
|
||||||
<h2 class="card-title">Timeline</h2>
|
|
||||||
<VTimeline
|
|
||||||
class="mt-2"
|
|
||||||
side="end"
|
|
||||||
align="start"
|
|
||||||
line-inset="8"
|
|
||||||
truncate-line="both"
|
|
||||||
density="compact"
|
|
||||||
>
|
>
|
||||||
<VTimelineItem
|
{{ item.value }}
|
||||||
dot-color="error"
|
</p>
|
||||||
size="x-small"
|
</div>
|
||||||
>
|
|
||||||
<!-- 👉 Header -->
|
|
||||||
<div class="d-flex justify-space-between flex-wrap mb-3">
|
|
||||||
<h6 class="text-base font-weight-medium me-3">
|
|
||||||
Submited at: {{ format.toDay(proposal.submit_time) }}
|
|
||||||
</h6>
|
|
||||||
<small class="text-xs text-disabled my-1">{{ shortTime(proposal.submit_time) }}</small>
|
|
||||||
</div>
|
|
||||||
</VTimelineItem>
|
|
||||||
|
|
||||||
<VTimelineItem
|
|
||||||
size="x-small"
|
|
||||||
dot-color="primary"
|
|
||||||
>
|
|
||||||
<!-- 👉 Header -->
|
|
||||||
<div class="d-flex justify-space-between flex-wrap mb-3">
|
|
||||||
<h6 class="text-base font-weight-medium me-3">
|
|
||||||
Deposited at: {{ format.toDay(proposal.status==="PROPOSAL_STATUS_DEPOSIT_PERIOD"?proposal.deposit_end_time: proposal.voting_start_time) }}
|
|
||||||
</h6>
|
|
||||||
<small class="text-xs text-disabled text-no-wrap my-1">{{ shortTime(proposal.status==="PROPOSAL_STATUS_DEPOSIT_PERIOD"?proposal.deposit_end_time: proposal.voting_start_time) }}</small>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p class="mb-0">
|
|
||||||
<div v-for="x of deposit.deposits">
|
|
||||||
{{ x.depositor }} {{ format.formatTokens(x.amount) }}
|
|
||||||
</div>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
|
|
||||||
</VTimelineItem>
|
|
||||||
|
|
||||||
<VTimelineItem
|
|
||||||
size="x-small"
|
|
||||||
dot-color="success"
|
|
||||||
>
|
|
||||||
<!-- 👉 Header -->
|
|
||||||
<div class="d-flex justify-space-between flex-wrap mb-3">
|
|
||||||
<h6 class="text-base font-weight-medium me-3">
|
|
||||||
Voting start from {{ format.toDay(proposal.voting_start_time) }}
|
|
||||||
</h6>
|
|
||||||
<small class="text-xs text-disabled text-no-wrap my-1">{{ shortTime(proposal.voting_start_time) }}</small>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 👉 Content -->
|
|
||||||
<p class="mb-0">
|
|
||||||
<Countdown :time="votingCountdown"/>
|
|
||||||
</p>
|
|
||||||
</VTimelineItem>
|
|
||||||
|
|
||||||
<VTimelineItem
|
|
||||||
size="x-small"
|
|
||||||
dot-color="success"
|
|
||||||
>
|
|
||||||
<!-- 👉 Header -->
|
|
||||||
<div class="d-flex justify-space-between flex-wrap mb-3">
|
|
||||||
<h6 class="text-base font-weight-medium me-3">
|
|
||||||
Voting end {{ format.toDay(proposal.voting_end_time) }}
|
|
||||||
</h6>
|
|
||||||
<small class="text-xs text-disabled text-no-wrap my-1">{{ shortTime(proposal.voting_end_time) }}</small>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 👉 Content -->
|
|
||||||
<p class="mb-0">
|
|
||||||
Current Status: {{ proposal.status }}
|
|
||||||
</p>
|
|
||||||
</VTimelineItem>
|
|
||||||
<VTimelineItem
|
|
||||||
v-if="proposal.content && proposal.content['@type'].endsWith('SoftwareUpgradeProposal')"
|
|
||||||
size="x-small"
|
|
||||||
dot-color="success"
|
|
||||||
>
|
|
||||||
<!-- 👉 Header -->
|
|
||||||
<div class="d-flex justify-space-between flex-wrap mb-3">
|
|
||||||
<h6 class="text-base font-weight-medium me-3">
|
|
||||||
Upgrade Plan:
|
|
||||||
<span v-if="Number(proposal.content?.plan?.height||'0') > 0"> (EST)</span>
|
|
||||||
<span v-else>{{ format.toDay(proposal.content?.plan?.time) }}</span>
|
|
||||||
</h6>
|
|
||||||
<small class="text-xs text-disabled text-no-wrap my-1">{{ shortTime(proposal.voting_end_time) }}</small>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 👉 Content -->
|
|
||||||
<p class="mb-0">
|
|
||||||
<Countdown :time="upgradeCountdown"/>
|
|
||||||
</p>
|
|
||||||
</VTimelineItem>
|
|
||||||
</VTimeline>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mt-6 grid grid-cols-2">
|
||||||
|
<label
|
||||||
|
for="vote"
|
||||||
|
class="btn btn-primary float-right btn-sm mx-1"
|
||||||
|
@click="dialog.open('vote', { proposal_id })"
|
||||||
|
>Vote</label
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
for="deposit"
|
||||||
|
class="btn btn-primary float-right btn-sm mx-1"
|
||||||
|
@click="dialog.open('deposit', { proposal_id })"
|
||||||
|
>Deposit</label
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="bg-base-100 px-4 pt-3 pb-5 rounded shadow lg:col-span-2"
|
||||||
|
>
|
||||||
|
<h2 class="card-title">Timeline</h2>
|
||||||
|
|
||||||
|
<div class="px-1">
|
||||||
|
<div class="flex items-center mb-4 mt-2">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-error mr-3"></div>
|
||||||
|
<div class="text-base flex-1 text-main">
|
||||||
|
Submited at: {{ format.toDay(proposal.submit_time) }}
|
||||||
|
</div>
|
||||||
|
<div class="text-sm">{{ shortTime(proposal.submit_time) }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center mb-4">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-primary mr-3"></div>
|
||||||
|
<div class="text-base flex-1 text-main">
|
||||||
|
Deposited at:
|
||||||
|
{{
|
||||||
|
format.toDay(
|
||||||
|
proposal.status === 'PROPOSAL_STATUS_DEPOSIT_PERIOD'
|
||||||
|
? proposal.deposit_end_time
|
||||||
|
: proposal.voting_start_time
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
<div class="text-sm">
|
||||||
|
{{
|
||||||
|
shortTime(
|
||||||
|
proposal.status === 'PROPOSAL_STATUS_DEPOSIT_PERIOD'
|
||||||
|
? proposal.deposit_end_time
|
||||||
|
: proposal.voting_start_time
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-yes mr-3"></div>
|
||||||
|
<div class="text-base flex-1 text-main">
|
||||||
|
Voting start from {{ format.toDay(proposal.voting_start_time) }}
|
||||||
|
</div>
|
||||||
|
<div class="text-sm">
|
||||||
|
{{ shortTime(proposal.voting_start_time) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pl-5 text-sm mt-2">
|
||||||
|
<Countdown :time="votingCountdown" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="flex items-center mb-1">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-success mr-3"></div>
|
||||||
|
<div class="text-base flex-1 text-main">
|
||||||
|
Voting end {{ format.toDay(proposal.voting_end_time) }}
|
||||||
|
</div>
|
||||||
|
<div class="text-sm">
|
||||||
|
{{ shortTime(proposal.voting_end_time) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pl-5 text-sm">
|
||||||
|
Current Status: {{ proposal.status }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="mt-4"
|
||||||
|
v-if="
|
||||||
|
proposal?.content?.['@type']?.endsWith('SoftwareUpgradeProposal')
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<div class="flex items-center">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-warning mr-3"></div>
|
||||||
|
<div class="text-base flex-1 text-main">
|
||||||
|
Upgrade Plan:
|
||||||
|
<span v-if="Number(proposal.content?.plan?.height || '0') > 0">
|
||||||
|
(EST)</span
|
||||||
|
>
|
||||||
|
<span v-else>{{
|
||||||
|
format.toDay(proposal.content?.plan?.time)
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="text-sm">
|
||||||
|
{{ shortTime(proposal.voting_end_time) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pl-5 text-sm mt-2">
|
||||||
|
<Countdown :time="upgradeCountdown" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
||||||
<h2 class="card-title">Votes</h2>
|
<h2 class="card-title">Votes</h2>
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table w-full">
|
<table class="table w-full table-zebra">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(item,index) of votes" :key="index">
|
<tr v-for="(item, index) of votes" :key="index">
|
||||||
<td>{{ item.voter }}</td>
|
<td class="py-2 text-sm">{{ item.voter }}</td>
|
||||||
<td>{{ item.option }}</td>
|
<td
|
||||||
</tr>
|
class="py-2 text-sm"
|
||||||
</tbody>
|
:class="{
|
||||||
</table>
|
'text-yes': item.option === 'VOTE_OPTION_YES',
|
||||||
|
'text-gray-400': item.option === 'VOTE_OPTION_ABSTAIN',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ item.option }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
v-if="votePage.next_key"
|
@click="loadMore()"
|
||||||
@click="loadMore()"
|
v-if="votePage.next_key"
|
||||||
:disabled="loading"
|
:disabled="loading"
|
||||||
class="btn btn-outline btn-primary w-full"
|
class="btn btn-outline btn-primary w-full mt-4"
|
||||||
style="border: 1px solid hsl(var(--p));"
|
>
|
||||||
>Load more</button>
|
Load more
|
||||||
</div>
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
Loading…
Reference in New Issue
Block a user