Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat/upvote election flow #2037

Merged
merged 18 commits into from
Feb 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
72e7042
feat(upvote-delegate-widget): added new upvote-delegate-widget with t…
evgenibir Jan 24, 2023
006e59c
feat(upvote-delegate-widget): added user-card without icon and tag (#…
evgenibir Jan 24, 2023
a558add
feat(upvote-delegate-widget): added head delegate tag and address-car…
evgenibir Jan 25, 2023
72e610e
feat(upvote-delegate-widget): update component story file (#1943)
evgenibir Jan 25, 2023
e6daeab
feat(creation-stepper): added new prop title
evgenibir Jan 27, 2023
add1365
feat(upvote-election): added new upvote-election route with sign-up s…
evgenibir Jan 30, 2023
312cdac
feat(upvote-election): added new screen round-1 (#1940)
evgenibir Jan 31, 2023
d1436d1
feat(upvote-election): added new screen chief delegates round (#1940)
evgenibir Jan 31, 2023
2e5baf1
feat(upvote-election): added new screen head delegate (#1940)
evgenibir Jan 31, 2023
6abafb4
feat(upvote-election): added new screen results (#1940)
evgenibir Feb 1, 2023
bbaaab8
feat(upvote-election-banner): added upvote election banner(#1939)
evgenibir Feb 3, 2023
c71d670
fix(proposal-create): draft editing (#1989)
evgenibir Feb 21, 2023
7d93e22
fix(assets): assets grid after merge
evgenibir Feb 21, 2023
2e0aadd
Merge branch 'feat/upvote_election_banner' into feat/upvote_election_…
evgenibir Feb 21, 2023
9a0b58b
Merge branch 'feat/upvote_delegate_widget' into feat/upvote_election_…
evgenibir Feb 21, 2023
1e1d111
feat(upvote-election): integrate graphql api for election
evgenibir Feb 24, 2023
cf7d37e
feat(upvote-election): integrate voting logic (intermediate commit)
evgenibir Feb 28, 2023
f8f00fa
Merge branch 'develop' into feat/upvote_election_dashboard
arsenijesavic Feb 28, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions public/svg/check-to-slot-secondary.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/svg/check-to-slot.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 3 additions & 2 deletions src/components/common/base-banner.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ export default {
},

split: Boolean,
compact: Boolean
compact: Boolean,
contentFullWidth: Boolean
},

methods: {
Expand Down Expand Up @@ -83,7 +84,7 @@ export default {

slot(name="header")
section.row
div(v-if="!compact" :class="{'col-6': split || hasSlot('right')}")
div(v-if="!compact" :class="{'col-6': split || hasSlot('right'), 'full-width': contentFullWidth}")
h3.q-pa-none.q-ma-none.h-h2.text-white.text-weight-700 {{title}}
p.h-b1.text-white.q-my-lg.text-weight-500.leading-loose {{description}}
nav.q-mt-xl
Expand Down
38 changes: 38 additions & 0 deletions src/components/common/upvote-delegate-widget.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import UpvoteDelegateWidget from './upvote-delegate-widget.vue'

export default {
title: 'Common/ Upvote Deletage Widget',
component: UpvoteDelegateWidget,
argTypes: {}
}

const Template = (args, { argTypes }) => ({
props: Object.keys(argTypes),
components: { UpvoteDelegateWidget },
template: `
<upvote-delegate-widget v-bind="$props" />
`
})

export const Example = Template.bind({})
// These are the params for the example story. You can all the params you want.
Example.args = {
endDate: '2023-09-01',
users: [
{
headDelegate: true,
name: 'User'
},
{
name: 'User'
},
{
name: 'User'
},
{
name: 'User'
}
]
}

export const Base = Template.bind({})
186 changes: 186 additions & 0 deletions src/components/common/upvote-delegate-widget.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
<script>
/**
* Base component for any card-like element on screen
* Handles title styling, margins and content padding
*/
import { mapGetters } from 'vuex'

export default {
name: 'widget',
props: {
endDate: String,
users: {
type: Array,
default: () => []
}
},
components: {
ProfilePicture: () => import('~/components/profiles/profile-picture.vue')
},
apollo: {
upvoteElectionQuery: {
query: require('~/query/upvote-election-data.gql'),
update: data => {
return {
previousRounds: data.getDao.previouselct[0]?.round
}
},
variables () {
return {
daoName: this.selectedDao.name
}
},
result (data) {
this.upvoteElectionData = {
previousRounds: data.data.getDao.previouselct[0]?.round
}
}
}
},
data () {
return {
counterdown: undefined,
upvoteElectionData: {}
}
},
computed: {
...mapGetters('dao', ['selectedDao']),
headWinners () {
return this.upvoteElectionData.previousRounds[2]?.winner
},
chiefWinners () {
return this.upvoteElectionData.previousRounds[1]?.winner
}
},
mounted () {
this.counterdown = setInterval(() => {
this.formatTimeLeft()
this.$forceUpdate()
}, 1000)
},
activated () {
this.counterdown = setInterval(() => {
this.formatTimeLeft()
this.$forceUpdate()
}, 1000)
},
deactivated () {
clearInterval(this.counterdown)
},
methods: {
votingTimeLeft () {
const end = new Date(this.endDate)
const now = Date.now()
const t = end - now
return t
},
formatTimeLeft () {
const MS_PER_DAY = 1000 * 60 * 60 * 24
const MS_PER_HOUR = 1000 * 60 * 60
const MS_PER_MIN = 1000 * 60
const timeRemaining = this.votingTimeLeft()
if (timeRemaining > 0) {
const days = Math.floor(timeRemaining / MS_PER_DAY)
let lesstime = timeRemaining - (days * MS_PER_DAY)
const hours = Math.floor(lesstime / MS_PER_HOUR)
lesstime = lesstime - (hours * MS_PER_HOUR)
const min = Math.floor(lesstime / MS_PER_MIN)
lesstime = lesstime - (min * MS_PER_MIN)
return {
days: days,
hours: hours,
mins: min
}
}
return 0
}
}
}
</script>

<template lang="pug">
q-card.widget.full-width.q-pt-xl.q-pl-xl.q-pr-xs.q-pb-xs.relative-position.rounded(flat :class="{ 'q-pr-xl': $q.screen.md || $q.screen.lt.md }")
.col
.row.justify-between.items-center
.row.items-center
img(src="/svg/check-to-slot.svg" width="18px" height="14px")
.title.text-bold.q-ml-sm Upvote Delegates
.row(:class="{ 'q-mt-md': $q.screen.lt.md }")
.counter(:class="{ 'right-margin': !$q.screen.lt.md }")
.title Election validity expires in:
.time.row
.row.items-end
.days {{ formatTimeLeft().days }}
.subtext(v-if="formatTimeLeft().days > 1") days
.subtext(v-else) day
.row.items-end
.hours {{ formatTimeLeft().hours }}
.subtext(v-if="formatTimeLeft().hours > 1") hours
.subtext(v-else) hour
.row.items-end
.mins {{ formatTimeLeft().mins }}
.subtext(v-if="formatTimeLeft().mins > 1") mins
.subtext(v-else) min
.row.q-mt-md
.template.col(v-for="user in headWinners" :class="{ 'col-6 q-px-xs': $q.screen.md, 'q-mr-md q-mb-md': $q.screen.gt.md, 'q-mb-md': $q.screen.md || $q.screen.lt.md, 'col-12': $q.screen.lt.md }")
.user-card
.tag HEAD DELEGATE
.row.items-center.justify-between
ProfilePicture(:username="user.details_member_n" size="50px" showUsername showName noMargins boldName withoutItalic)
q-icon.card-icon(name="far fa-address-card" size="16px" color="white")
.template.col(v-for="user in chiefWinners" :class="{ 'col-6 q-px-xs': $q.screen.md, 'q-mr-md q-mb-md': $q.screen.gt.md, 'q-mb-md': $q.screen.md || $q.screen.lt.md, 'col-12': $q.screen.lt.md }")
.user-card
.row.items-center.justify-between
ProfilePicture(:username="user.details_member_n" size="50px" showUsername showName noMargins boldName withoutItalic)
q-icon.card-icon(name="far fa-address-card" size="16px" color="white")
</template>

<style lang="stylus" scoped>
.rounded
border-radius: 26px
.counter
display: flex
font-family: 'Lato', sans-serif
font-weight: 600
color: #3F64EE
font-size: 18px
.title
margin-right: 25px
.time
.subtext
font-size: 12px
padding-bottom: 2px
margin-right: 4px
.user-card
border-radius: 14px
border: 1px solid #C4C5C9
padding: 7.5px 16px
position: relative
.card-icon
width: 30px
height: 30px
display: flex
border-radius: 50%
justify-content: center
align-items: center
background: #242F5D
.right-margin
margin-right: 20px
.title
font-size: 22px
color: #3E3B46
.tag
display: flex
height: 16px
width: fit-content
border-radius: 8px
background: #3F64EE
padding: 1.5px 8px
color: #FFFFFF
font-family: 'Lato', sans-serif
font-weight: 600
font-size: 9px
position: absolute
top: 0
right: 0
</style>
42 changes: 37 additions & 5 deletions src/components/organization-asset/asset-card.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ export default {
* Asset object {icon, docId, assignmentAggregate, assignment, title, description }
*/
asset: Object,
isMobile: Boolean
isMobile: Boolean,
bordered: Boolean,
ownerStyles: Boolean,
memberBadges: Array,
currentElectionIndex: Number
},
data () {
return {
Expand Down Expand Up @@ -71,6 +75,7 @@ export default {

computed: {
...mapGetters('dao', ['selectedDao']),
...mapGetters('accounts', ['account']),
othersText () {
return `and ${this.asset.assignment.length > 3 ? 'others' : 'other'} ${this.asset.assignment.length - 3}`
},
Expand All @@ -83,6 +88,13 @@ export default {
badgeHolders () {
const uniqueHolders = lodash.uniqBy(this.asset.assignment, 'username')
return uniqueHolders.filter(holder => holder.daoName === this.selectedDao.name)
},
stylesForOwner () {
const existingBadge = this.memberBadges?.find((badge) => badge.title === this.asset.title)
return this.ownerStyles && existingBadge
},
buttonText () {
return this.stylesForOwner ? 'Applied' : 'Apply'
}
},

Expand Down Expand Up @@ -136,14 +148,24 @@ export default {
name,
cid
}
},
revokeBadge () {
const actions = [{
account: this.$config.contracts.dao,
name: 'withdraw',
data: {
owner: this.account,
document_id: this.asset.docId
}
}]
return this.$store.$api.signTransaction(actions)
}

}
}
</script>

<template lang="pug">
widget.item(:class="{'mobile-item': isMobile, 'desktop-item': !isMobile, 'cursor-pointer': !isBadge }")
widget.item.full-width(:class="{'mobile-item': isMobile, 'desktop-item': !isMobile, 'cursor-pointer': !isBadge, 'bordered': bordered, 'owner-border': stylesForOwner }")
.clickable.flex.column.justify-between.full-height(@click="sendToPage")
.col.top-section
.row.justify-between
Expand All @@ -154,6 +176,7 @@ widget.item(:class="{'mobile-item': isMobile, 'desktop-item': !isMobile, 'cursor
q-avatar(size="30px" v-else-if="iconDetails && iconDetails.type === 'img'")
img.icon-img(:src="iconDetails.name")
ipfs-image-viewer(size="30px", :ipfsCid="iconDetails.cid" v-else-if="iconDetails && iconDetails.type === 'ipfs'")
.h-b2.text-underline(v-if="isBadge && stylesForOwner" @click="revokeBadge" :class="{ 'disable-revoke-button': currentElectionIndex !== 0 && (this.asset.title === 'Voter' || this.asset.title === 'Delegate') }") Revoke
.row.q-my-xs
.h-h5.text-weight-bold {{asset.title}}
.row.q-my-xs
Expand All @@ -168,13 +191,12 @@ widget.item(:class="{'mobile-item': isMobile, 'desktop-item': !isMobile, 'cursor
q-tooltip @{{ user.username }}
.profile-counter.bg-internal-bg(v-if="badgeHolders.length > 3") +{{ badgeHolders.length - 3 }}
.profile-counter.bg-internal-bg(v-else-if="!badgeHolders.length") n/a
q-btn.q-mt-md.text-white(v-if="isBadge" noCaps unelevated rounded color="primary" @click="onApply") Apply
q-btn.q-mt-md.text-white(v-if="isBadge" :disable="currentElectionIndex !== 0 && (this.asset.title === 'Voter' || this.asset.title === 'Delegate')" noCaps unelevated rounded color="primary" @click="onApply" :class="{ 'owner-button': stylesForOwner }") {{ buttonText }}
</template>

<style lang="stylus" scoped>

.item

.description
height: 95px
overflow hidden
Expand Down Expand Up @@ -206,4 +228,14 @@ widget.item(:class="{'mobile-item': isMobile, 'desktop-item': !isMobile, 'cursor
color: #242F5D
margin-left: -10px
z-index: 100
.bordered
border: 1px solid #84878E
.owner-border
border: 1px solid #1CB59B
.owner-button
background: #1CB59B !important
pointer-events: none
.disable-revoke-button
opacity: 0.6
pointer-events: none
</style>
14 changes: 11 additions & 3 deletions src/components/organization-asset/asset-list.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ export default {
* A list of { icon, docId, assignmentAggregate, assignment, title, description } objects
*/
assetList: Array,
isMobile: Boolean
isMobile: Boolean,
bordered: Boolean,
ownerStyles: Boolean,
memberBadges: Array,
currentElectionIndex: Number
},
data () {
return {
Expand Down Expand Up @@ -46,11 +50,11 @@ export default {
<template lang="pug">
.list(ref="scrollContainer")
q-infinite-scroll(
@load="onLoad"
:offset="250"
:scroll-target="$refs.scrollContainer"
@load="onLoad"
ref="scroll"
)
).full-width
.row.q-col-gutter-md.q-mr-md
.template.col-4(
v-for="(asset,index) in assetList"
Expand All @@ -60,6 +64,10 @@ export default {
:key="asset.docId"
:asset="asset"
:isMobile="isMobile"
:ownerStyles="ownerStyles"
:bordered="bordered",
:memberBadges="memberBadges"
:currentElectionIndex="currentElectionIndex"
)
.col-4(:class="{ 'col-6': $q.screen.md, 'full-width': $q.screen.sm }")
create-badge-widget(v-if="assetList && this.$route.params.type === 'badge'")
Expand Down
Loading