diff --git a/src/components/common/payout-amounts.vue b/src/components/common/payout-amounts.vue index f72d46680..26c9dd02b 100644 --- a/src/components/common/payout-amounts.vue +++ b/src/components/common/payout-amounts.vue @@ -36,9 +36,12 @@ export default defineComponent({ methods: { settingsHasToken(token) { - if (token !== TOKEN_TYPES.VOICE_TOKEN) { - const cleanTokenName = token.split(' ')?.[2]?.replace('(', '').replace(')', '') - return cleanTokenName === this.$store.state.dao.settings.pegToken || cleanTokenName === this.$store.state.dao.settings.rewardToken + if (token !== 'VOICE') { + if (this.$store.state.dao.settings.pegToken && this.$store.state.dao.settings.rewardToken) { + return token === this.$store.state.dao.settings.pegToken || token === this.$store.state.dao.settings.rewardToken + } else { + return false + } } else { return true } @@ -62,5 +65,5 @@ export default defineComponent({ .full-width(:class="{row: $q.platform.is.desktop}") template(v-for="token in tokens") .col(v-if="token.value" :class="{'col-12': stacked, 'q-mb-md': $q.platform.is.mobile}") - token-value(:daoLogo="daoLogo" :multiplier="settingsMultiplier(token.label)" v-bind="token") + token-value(v-if="settingsHasToken(token.symbol)" :daoLogo="daoLogo" :multiplier="settingsMultiplier(token.label)" v-bind="token") diff --git a/src/components/dao/settings-tokens.vue b/src/components/dao/settings-tokens.vue index ea3e6a1f4..73dfe210a 100644 --- a/src/components/dao/settings-tokens.vue +++ b/src/components/dao/settings-tokens.vue @@ -3,6 +3,7 @@ import { mapActions, mapGetters } from 'vuex' import { validation } from '~/mixins/validation' import currency from 'src/data/currency.json' import map from '~/utils/map' +import { MIN_TOKEN_MULTIPLIER, MAX_TOKEN_MULTIPLIER } from '~/const' const mapCurrency = (currency) => (_) => ({ label: `${currency[_]?.symbol} - ${currency[_]?.name}`, @@ -85,6 +86,11 @@ export default { if (isValid) { await this.createTokens({ ...this.tokens, + + utilityTokenMultiplier: map(this.tokens.utilityTokenMultiplier, 0, 100, MIN_TOKEN_MULTIPLIER, MAX_TOKEN_MULTIPLIER), + voiceTokenMultiplier: map(this.tokens.voiceTokenMultiplier, 0, 100, MIN_TOKEN_MULTIPLIER, MAX_TOKEN_MULTIPLIER), + treasuryTokenMultiplier: map(this.tokens.treasuryTokenMultiplier, 0, 100, MIN_TOKEN_MULTIPLIER, MAX_TOKEN_MULTIPLIER), + voiceDecayPercent: map(this.tokens.voiceDecayPercent, 0, 100, MIN_DECAY, MAX_DECAY) }) } @@ -236,8 +242,10 @@ export default { q-input.q-my-xs( :debounce="200" :disable="!selectedDao.hasCustomToken" + :max="100" + :min="0" :placeholder="$t('configuration.settings-tokens.tresury.form.value.placeholder')" - :rules="[rules.required]" + :rules="[rules.required, rules.greaterThan(0), rules.lessOrEqualThan(100)]" bg-color="white" color="accent" dense @@ -331,7 +339,9 @@ export default { :debounce="200" :disable="selectedDao.hasCustomToken || !isAdmin" :filled="selectedDao.hasCustomToken || !isAdmin" - :rules="[rules.required]" + :max="100" + :min="0" + :rules="[rules.required, rules.greaterThan(0), rules.lessOrEqualThan(100)]" color="accent" dense lazy-rules @@ -427,7 +437,9 @@ export default { :debounce="200" :disable="selectedDao.hasCustomToken || !isAdmin" :filled="selectedDao.hasCustomToken || !isAdmin" - :rules="[rules.required]" + :max="100" + :min="0" + :rules="[rules.required, rules.greaterThan(0), rules.lessOrEqualThan(100)]" color="accent" dense lazy-rules diff --git a/src/components/login/register-user-with-captcha-view.vue b/src/components/login/register-user-with-captcha-view.vue index 5f9750174..320ab8107 100644 --- a/src/components/login/register-user-with-captcha-view.vue +++ b/src/components/login/register-user-with-captcha-view.vue @@ -5,6 +5,8 @@ import QrcodeVue from 'qrcode.vue' import ipfsy from '~/utils/ipfsy' import { Notify } from 'quasar' import slugify from '~/utils/slugify' +import map from '~/utils/map' +import { MIN_TOKEN_MULTIPLIER, MAX_TOKEN_MULTIPLIER } from '~/const' const HELP_LINK = 'https://help.hypha.earth/hc/2431449449' @@ -171,10 +173,14 @@ export default { await this.createDAO({ data: { ...this.form, + + daoUrl, onboarder_account: this.account, parentId: this.$route.query.parentId, skipTokens: true, - daoUrl: daoUrl + utilityTokenMultiplier: map(this.form.utilityTokenMultiplier, 0, 100, MIN_TOKEN_MULTIPLIER, MAX_TOKEN_MULTIPLIER), + voiceTokenMultiplier: map(this.form.voiceTokenMultiplier, 0, 100, MIN_TOKEN_MULTIPLIER, MAX_TOKEN_MULTIPLIER), + treasuryTokenMultiplier: map(this.form.treasuryTokenMultiplier, 0, 100, MIN_TOKEN_MULTIPLIER, MAX_TOKEN_MULTIPLIER) }, isDraft }) diff --git a/src/const.js b/src/const.js index 18ba1602f..4f1ac429e 100644 --- a/src/const.js +++ b/src/const.js @@ -96,3 +96,6 @@ export const TOKEN_TYPES = Object.freeze({ UTILITY_TOKEN: 'Utility Token', VOICE_TOKEN: 'Voice Token' }) + +export const MIN_TOKEN_MULTIPLIER = 0 +export const MAX_TOKEN_MULTIPLIER = 1 diff --git a/src/locales/en.json b/src/locales/en.json index 7997dbcc3..6d4571091 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -1735,8 +1735,8 @@ "typeTheAmountOfUsd":"Type the USD equivalent", "commitmentMustBeGreater":"Commitment must be greater than or equal to the role configuration. Role value for min commitment is", "defferedMustBeGreater":"Due to the role setup you’ll have to choose a greater percentage to continue", - "salaryCompensationForOneYear":"Reward for one year ( ${value} )", - "salaryCompensationForOneYearUsd":"Reward for one year ( ${value} ) USD", + "salaryCompensationForOneYear":"Reward for one year ( ${value} equivalent)", + "salaryCompensationForOneYearUsd":"Reward for one year ( ${value} ) USD equivalent", "compensation":"Reward Calculation", "compensation1":"Reward", "pleaseEnterTheUSD":"Please enter the USD equivalent for your reward. Moving the second slider will let you select your token percentage (utility vs payout).", diff --git a/src/pages/profiles/Profile.vue b/src/pages/profiles/Profile.vue index 0d8d4d13a..53ed42fe8 100644 --- a/src/pages/profiles/Profile.vue +++ b/src/pages/profiles/Profile.vue @@ -266,7 +266,8 @@ export default { ...mapGetters('dao', ['selectedDao', 'daoSettings', 'votingPercentages']), ...mapGetters('ballots', ['supply']), - isOwner () { return this?.username === this?.account } + isOwner () { return this?.username === this?.account }, + isMember () { return this.organizations.length > 0 } }, async mounted () { @@ -565,9 +566,16 @@ q-page.full-width.page-profile profile-card.profile(v-if="tab === Tabs.INFO || isTabletOrGreater" :style="{'grid-area': 'profile'}" :clickable="false" :username="username" :joinedDate="member && member.createdDate" view="card" :editButton="isOwner" @onSave="onSaveProfileCard" :compact="!$q.screen.gt.md" :tablet="$q.screen.md") organizations.org(v-if="tab === Tabs.INFO || isTabletOrGreater && organizationsList.length" :organizations="organizationsList" @onSeeMore="loadMoreOrganizations" :hasMore="organizationsPagination.fetchMore" :tablet="$q.screen.md" :style="$q.screen.md? {'grid-area': 'org', 'height': '100px'} : {'grid-area': 'org'}") .badges(v-if="tab === Tabs.INFO || isTabletOrGreater" :style="{'grid-area': 'badges'}") - base-placeholder(compact v-if="!memberBadges && isOwner" :title="$t('pages.profiles.profile.badges')" :subtitle=" isOwner ? $t('pages.profiles.profile.noBadgesYesApplyFor') : $t('pages.profiles.profile.noBadgesToSeeHere')" icon="fas fa-id-badge" :actionButtons="isOwner ? [{label: $t('pages.profiles.profile.apply'), color: 'primary', onClick: () => routeTo('proposals/create')}] : []") + base-placeholder( + :actionButtons="isOwner ? [{label: $t('pages.profiles.profile.apply'), disable: !isMember, color: 'primary', onClick: () => routeTo('proposals/create')}] : []" + :subtitle=" isOwner ? $t('pages.profiles.profile.noBadgesYesApplyFor') : $t('pages.profiles.profile.noBadgesToSeeHere')" + :title="$t('pages.profiles.profile.badges')" + compact + icon="fas fa-id-badge" + v-if="!memberBadges && isOwner" + ) badges-widget(:badges="memberBadges" compact v-if="memberBadges" fromProfile) - wallet.wallet(v-if="tab === Tabs.INFO || isTabletOrGreater" :style="{'grid-area': 'wallet'}" ref="wallet" :more="isOwner" :username="username") + wallet.wallet(v-if="isMember && (tab === Tabs.INFO || isTabletOrGreater)" :style="{'grid-area': 'wallet'}" ref="wallet" :more="isOwner" :username="username") wallet-adresses.walletadd(:style="{'grid-area': 'walletadd'}" :walletAdresses="walletAddressForm" @onSave="onSaveWalletAddresses" v-if="isOwner && (tab==='INFO' || isTabletOrGreater)" :isHypha="daoSettings.isHypha") multi-sig.msig(v-if="tab==='INFO' || isTabletOrGreater" :style="{'grid-area': 'msig'}" v-show="isHyphaOwner" :numberOfPRToSign="numberOfPRToSign") .right.q-gutter-md(:style="$q.screen.gt.md && {'grid-area': 'right'}") @@ -577,19 +585,54 @@ q-page.full-width.page-profile q-tab.full-width(:name="Tabs.CONTRIBUTIONS" :label="$t('pages.profiles.profile.contributions')" :ripple="false") q-tab.full-width(:name="Tabs.QUESTS" :label="$t('pages.profiles.profile.quests')" :ripple="false") .assignments(v-if="tab === Tabs.ASSIGNMENTS || tab === Tabs.PROJECTS" :style="{'grid-area': 'assignments'}") - base-placeholder(v-if="!(assignments && assignments.length)" :compact="isMobile" :title="isTabletOrGreater ? '' : $t('pages.profiles.profile.assignments')" :subtitle=" isOwner ? $t('pages.profiles.profile.looksLikeYouDontHaveAnyActiveAssignments') : $t('pages.profiles.profile.noActiveOrArchivedAssignments')" icon="fas fa-file-medical" :actionButtons="isOwner ? [{label: $t('pages.profiles.profile.createAssignment'), color: 'primary', onClick: () => routeTo('proposals/create')}] : [] ") + base-placeholder( + :actionButtons="isOwner ? [{label: $t('pages.profiles.profile.createAssignment'), color: 'primary', disable: !isMember, onClick: () => routeTo('proposals/create')}] : [] " + :compact="isMobile" + :subtitle=" isOwner ? $t('pages.profiles.profile.looksLikeYouDontHaveAnyActiveAssignments') : $t('pages.profiles.profile.noActiveOrArchivedAssignments')" + :title="isTabletOrGreater ? '' : $t('pages.profiles.profile.assignments')" + icon="fas fa-file-medical" + v-if="!(assignments && assignments.length)" + ) active-assignments(v-if="assignments && assignments.length" :assignments="assignments" :owner="isOwner" :hasMore="assignmentsPagination.fetchMore" @claim-all="$refs.wallet.fetchTokens()" @change-deferred="refresh" @onMore="loadMoreAssingments" :daoSettings="daoSettings" :selectedDao="selectedDao" :supply="supply" :votingPercentages="votingPercentages" :compact="isMobile") .contributions(v-if="tab === Tabs.CONTRIBUTIONS || tab === Tabs.PROJECTS" :style="{'grid-area': 'contributions'}") - base-placeholder(v-if="!(contributions && contributions.length)" :compact="isMobile" :title="isTabletOrGreater ? '' : $t('pages.profiles.profile.contributions')" :subtitle=" isOwner ? $t('pages.profiles.profile.looksLikeYouDontHaveAnyContributions') : $t('pages.profiles.profile.noContributionsToSeeHere')" icon="fas fa-file-medical" :actionButtons="isOwner ? [{label: $t('pages.profiles.profile.createContribution'), color: 'primary', onClick: () => routeTo('proposals/create')}] : []") + base-placeholder( + :actionButtons="isOwner ? [{label: $t('pages.profiles.profile.createContribution'), color: 'primary', disable: !isMember, onClick: () => routeTo('proposals/create')}] : []" + :compact="isMobile" + :subtitle=" isOwner ? $t('pages.profiles.profile.looksLikeYouDontHaveAnyContributions') : $t('pages.profiles.profile.noContributionsToSeeHere')" + :title="isTabletOrGreater ? '' : $t('pages.profiles.profile.contributions')" + icon="fas fa-file-medical" + v-if="!(contributions && contributions.length)" + ) active-assignments(v-if="contributions && contributions.length" :contributions="contributions" :owner="isOwner" :hasMore="contributionsPagination.fetchMore" @claim-all="$refs.wallet.fetchTokens()" @change-deferred="refresh" @onMore="loadMoreContributions" :daoSettings="daoSettings" :selectedDao="selectedDao" :supply="supply" :votingPercentages="votingPercentages" :compact="isMobile") .quests(v-if="tab === Tabs.QUESTS" :style="{'grid-area': 'quests'}") - base-placeholder(v-if="!(quests && quests.length)" :compact="isMobile" :title="isTabletOrGreater ? '' : $t('pages.profiles.profile.quests')" :subtitle=" isOwner ? $t('pages.profiles.profile.looksLikeYouDontHaveAnyQuests') : $t('pages.profiles.profile.noQuestsToSeeHere')" icon="fas fa-file-medical" :actionButtons="isOwner ? [{label: $t('pages.profiles.profile.createQuest'), color: 'primary', onClick: () => routeTo('proposals/create')}] : []") + base-placeholder( + :actionButtons="isOwner ? [{label: $t('pages.profiles.profile.createQuest'), color: 'primary', disable: !isMember, onClick: () => routeTo('proposals/create')}] : []" + :compact="isMobile" + :subtitle=" isOwner ? $t('pages.profiles.profile.looksLikeYouDontHaveAnyQuests') : $t('pages.profiles.profile.noQuestsToSeeHere')" + :title="isTabletOrGreater ? '' : $t('pages.profiles.profile.quests')" + icon="fas fa-file-medical" + v-if="!(quests && quests.length)" + ) active-assignments(v-if="quests && quests.length" :contributions="quests" :owner="isOwner" :hasMore="questsPagination.fetchMore" @claim-all="$refs.wallet.fetchTokens()" @change-deferred="refresh" @onMore="loadMoreQuests" :daoSettings="daoSettings" :selectedDao="selectedDao" :supply="supply" :votingPercentages="votingPercentages" :compact="isMobile") .about(v-if="tab === Tabs.ABOUT || isTabletOrGreater" :style="{'grid-area': 'about'}") - base-placeholder(:compact="isMobile" v-if="!(profile && profile.publicData && profile.publicData.bio) && showBioPlaceholder" :title="$t('pages.profiles.profile.biography')" :subtitle=" isOwner ? $t('pages.profiles.profile.writeSomethingAboutYourself') : $t('pages.profiles.profile.looksLikeDidntWrite', { username: this.username })" icon="fas fa-user-edit" :actionButtons="isOwner ? [{label: $t('pages.profiles.profile.writeBiography'), color: 'primary', onClick: () => {$refs.about.openEdit(); showBioPlaceholder = false }}] : []") + base-placeholder( + :actionButtons="isOwner ? [{label: $t('pages.profiles.profile.writeBiography'), color: 'primary', onClick: () => {$refs.about.openEdit(); showBioPlaceholder = false }}] : []" + :compact="isMobile" + :subtitle=" isOwner ? $t('pages.profiles.profile.writeSomethingAboutYourself') : $t('pages.profiles.profile.looksLikeDidntWrite', { username: this.username })" + :title="$t('pages.profiles.profile.biography')" + icon="fas fa-user-edit" + v-if="!(profile && profile.publicData && profile.publicData.bio) && showBioPlaceholder" + ) about.about(v-show="(profile && profile.publicData && profile.publicData.bio) || (!showBioPlaceholder)" :bio="(profile && profile.publicData) ? (profile.publicData.bio || '') : $t('pages.profiles.profile.retrievingBio')" @onSave="onSaveBio" @onCancel="onCancelBio" :editButton="isOwner" ref="about") .votes(v-if="tab === Tabs.VOTES || isTabletOrGreater" :style="{'grid-area': 'votes'}") - base-placeholder(:compact="isMobile" v-if="!(votes && votes.length)" :title="$t('pages.profiles.profile.recentVotes')" :subtitle=" isOwner ? $t('pages.profiles.profile.youHaventCast') : $t('pages.profiles.profile.noVotesCastedYet')" icon="fas fa-vote-yea" :actionButtons="isOwner ? [{label: $t('pages.profiles.profile.vote'), color: 'primary', onClick: () => routeTo('proposals')}] : []") + base-placeholder( + :actionButtons="isOwner ? [{label: $t('pages.profiles.profile.vote'), color: 'primary', disable: !isMember, onClick: () => routeTo('proposals')}] : []" + :compact="isMobile" + :subtitle=" isOwner ? $t('pages.profiles.profile.youHaventCast') : $t('pages.profiles.profile.noVotesCastedYet')" + :title="$t('pages.profiles.profile.recentVotes')" + icon="fas fa-vote-yea" + v-if="!(votes && votes.length)" + ) voting-history(v-if="votes && votes.length" :name="(profile && profile.publicData) ? profile.publicData.name : username" :votes="votes" @onMore="loadMoreVotes") diff --git a/src/pages/proposals/create/StepPayout.vue b/src/pages/proposals/create/StepPayout.vue index 935476095..02e65eb48 100644 --- a/src/pages/proposals/create/StepPayout.vue +++ b/src/pages/proposals/create/StepPayout.vue @@ -51,6 +51,13 @@ export default { } }, + annualUsdSalary: { + immediate: true, + handler () { + this.calculateTokens() + } + }, + usdAmount: { immediate: true, handler () {