diff --git a/.meteor/packages b/.meteor/packages index ea7db3d8c..83e71991f 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -12,7 +12,7 @@ meteor-base@1.4.0 # Packages every Meteor app needs to have tracker@1.2.0 # Meteor's client-side reactive programming library es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers. -ecmascript@0.14.0 # Enable ECMAScript2015+ syntax in app code +ecmascript@0.14.3 # Enable ECMAScript2015+ syntax in app code # standard libraries jquery@1.11.10 # Helpful client-side library @@ -31,7 +31,7 @@ react-template-helper react-meteor-data # data -mongo@1.8.0 # The database Meteor supports right now +mongo@1.10.0 # The database Meteor supports right now aldeed:simple-schema aldeed:collection2 dburles:collection-helpers @@ -46,12 +46,12 @@ tap:i18n # accounts, users session@1.2.0 # Client-side reactive dictionary for your app accounts-ui@1.3.1 -accounts-password@1.5.2 +accounts-password@1.6.0 accounts-twitter@1.4.2 accounts-facebook@1.3.2 # mobile -mobile-experience@1.0.5 # Packages for a great mobile UX +mobile-experience@1.1.0 # Packages for a great mobile UX # production @@ -79,13 +79,13 @@ edgee:slingshot http@1.4.2 email@1.2.3 service-configuration@1.0.11 -shell-server@0.4.0 +shell-server@0.5.0 dispatch:mocha-phantomjs reactive-var@1.0.11 reactive-dict@1.3.0 facebook-config-ui@1.0.2 twitter-config-ui@1.0.0 -dynamic-import@0.5.1 +dynamic-import@0.5.2 mdg:meteor-apm-agent tmeasday:publish-counts konecty:nrr diff --git a/.meteor/release b/.meteor/release index c6ae8ec13..3ea26528c 100644 --- a/.meteor/release +++ b/.meteor/release @@ -1 +1 @@ -METEOR@1.9 +METEOR@1.10.2 diff --git a/.meteor/versions b/.meteor/versions index 360ea064f..cc828bcbd 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -1,7 +1,7 @@ -accounts-base@1.5.0 +accounts-base@1.6.0 accounts-facebook@1.3.2 -accounts-oauth@1.1.16 -accounts-password@1.5.3 +accounts-oauth@1.2.0 +accounts-password@1.6.0 accounts-twitter@1.4.2 accounts-ui@1.3.1 accounts-ui-unstyled@1.4.2 @@ -12,15 +12,15 @@ aldeed:schema-index@1.1.1 aldeed:simple-schema@1.5.4 allow-deny@1.1.0 autoupdate@1.6.0 -babel-compiler@7.5.1 +babel-compiler@7.5.3 babel-runtime@1.5.0 base64@1.0.12 binary-heap@1.0.11 blaze@2.3.4 blaze-html-templates@1.1.2 blaze-tools@1.0.10 -boilerplate-generator@1.6.0 -caching-compiler@1.2.1 +boilerplate-generator@1.7.0 +caching-compiler@1.2.2 caching-html-compiler@1.1.3 callback-hook@1.3.0 cfs:http-methods@0.0.32 @@ -32,13 +32,13 @@ ddp@1.4.0 ddp-client@2.3.3 ddp-common@1.4.0 ddp-rate-limiter@1.0.7 -ddp-server@2.3.0 +ddp-server@2.3.1 deps@1.0.12 diff-sequence@1.1.1 dispatch:mocha-phantomjs@0.1.9 dispatch:phantomjs-tests@0.0.7 -dynamic-import@0.5.1 -ecmascript@0.14.1 +dynamic-import@0.5.2 +ecmascript@0.14.3 ecmascript-runtime@0.7.0 ecmascript-runtime-client@0.10.0 ecmascript-runtime-server@0.9.0 @@ -47,7 +47,7 @@ ejson@1.1.1 email@1.2.3 es5-shim@4.8.0 facebook-config-ui@1.0.2 -facebook-oauth@1.6.0 +facebook-oauth@1.7.0 fetch@0.1.1 geojson-utils@1.0.10 harrison:papa-parse@1.1.7 @@ -56,7 +56,7 @@ html-tools@1.0.11 htmljs@1.0.11 http@1.4.2 id-map@1.1.0 -inter-process-messaging@0.1.0 +inter-process-messaging@0.1.1 iron:controller@1.0.12 iron:core@1.0.11 iron:dynamic-template@1.0.12 @@ -68,7 +68,7 @@ iron:url@1.1.0 jquery@1.11.11 kadira:dochead@1.5.0 konecty:nrr@2.0.2 -launch-screen@1.1.1 +launch-screen@1.2.0 less@2.8.0 lh84:medium-editor@5.4.0 livedata@1.0.18 @@ -84,14 +84,14 @@ meteorhacks:search-source@1.4.2 meteorhacks:ssr@2.2.0 meteorspark:util@0.2.0 minifier-css@1.5.0 -minimongo@1.4.5 +minimongo@1.6.0 miro:preloader@1.2.4 -mobile-experience@1.0.5 -mobile-status-bar@1.0.14 +mobile-experience@1.1.0 +mobile-status-bar@1.1.0 modern-browsers@0.1.5 modules@0.15.0 modules-runtime@0.12.0 -mongo@1.8.0 +mongo@1.10.0 mongo-decimal@0.1.1 mongo-dev-server@1.1.0 mongo-id@1.0.7 @@ -99,10 +99,10 @@ mongo-livedata@1.0.12 mrt:jquery-ui@1.9.2 mystor:device-detection@0.2.0 npm-bcrypt@0.9.3 -npm-mongo@3.3.0 -oauth@1.2.8 -oauth1@1.2.2 -oauth2@1.2.1 +npm-mongo@3.7.1 +oauth@1.3.0 +oauth1@1.3.0 +oauth2@1.3.0 observe-sequence@1.0.16 ordered-dict@1.1.0 practicalmeteor:chai@2.1.0_1 @@ -113,7 +113,7 @@ practicalmeteor:sinon@1.14.1_2 promise@0.11.2 raix:eventemitter@0.1.3 rajit:bootstrap3-datepicker@1.7.1_1 -random@1.1.0 +random@1.2.0 rate-limit@1.0.9 react-meteor-data@0.2.16 react-template-helper@0.2.11 @@ -126,11 +126,11 @@ server-render@0.3.1 service-configuration@1.0.11 session@1.2.0 sha@1.0.9 -shell-server@0.4.0 -socket-stream-client@0.2.2 +shell-server@0.5.0 +socket-stream-client@0.3.0 spacebars@1.0.15 spacebars-compiler@1.1.3 -srp@1.0.12 +srp@1.1.0 standard-minifier-css@1.6.0 tap:i18n@1.8.2 templating@1.3.2 @@ -145,9 +145,9 @@ twitter-config-ui@1.0.0 twitter-oauth@1.2.0 ui@1.0.13 underscore@1.0.10 -url@1.2.0 +url@1.3.0 velocityjs:velocityjs@1.2.1 -webapp@1.8.2 +webapp@1.9.1 webapp-hashing@1.0.9 xolvio:backdoor@0.2.1 -xolvio:cleaner@0.3.3 +xolvio:cleaner@0.4.0 diff --git a/= b/= new file mode 100644 index 000000000..e69de29bb diff --git a/README.md b/README.md index 90cc16659..a481235fc 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Read our ๐Ÿ“ƒ [white paper](https://github.com/DemocracyEarth/paper) and check o **Release:** -* Currently [`version 0.7`](https://github.com/DemocracyEarth/sovereign/releases) +* Currently [`version 0.8`](https://github.com/DemocracyEarth/sovereign/releases) * This [User Agreement](https://github.com/DemocracyEarth/sovereign/blob/master/UserAgreement.md) governs access to and use of the Democracy Earth platform. ## Setup @@ -104,7 +104,7 @@ Read our ๐Ÿ“ƒ [white paper](https://github.com/DemocracyEarth/paper) and check o ## Specifications -* Built with [Meteor](https://github.com/meteor/meteor) version 1.9 +* Built with [Meteor](https://github.com/meteor/meteor) version 1.10 * Check our [documentation](http://docs.democracy.earth) for further technical reference (work in progress). **Supported Browsers:** diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index b0ecb2327..e2d0669ad 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -216,12 +216,12 @@ "vote-proposal": "Vote Proposal", "edit-draft": "Edit Draft", "posted": "Posted", - "years-ago" : "years ago.", - "months-ago" : "months ago.", - "days-ago" : "days ago.", - "hours-ago" : "hours ago.", - "minutes-ago" : "minutes ago.", - "seconds-ago" : "seconds ago.", + "years-ago" : "years ago", + "months-ago" : "months ago", + "days-ago" : "days ago", + "hours-ago" : "hours ago", + "minutes-ago" : "minutes ago", + "seconds-ago" : "seconds ago", "years-compressed" : "years", "months-compressed" : "months", "days-compressed" : "days", @@ -524,8 +524,8 @@ "email-farewell": "Be well and keep in touch,", "email-modified-vote": "a modified vote", "username-already-exists": "Username already exists.", - "profile-tag-title": "{{user}}'s profile on {{collective}}.", - "profile-tag-description": "Proposed ideas, delegations and votes by {{user}} on {{collective}}.", + "profile-tag-title": "{{user}} activity.", + "profile-tag-description": "Proposals by {{user}}.", "vote-tag-title": "Posted on {{collective}}.", "vote-tag-ballot-title": "Vote on {{collective}}.", "hashtag-tag-title": "{{hashtag}} posts on {{collective}}.", @@ -716,15 +716,15 @@ "duration": "Duration", "blockchain-time-closing-criteria": "Poll ends when {{blockchain}} reaches a cycle of {{height}} cycles estimated on {{date}}.", "blockchain-time-always-on": "This poll never ends and tallies an ongoing result.", - "countdown-expiration": "Poll ends in {{days}} {{hours}} (in {{blocks}})", - "countdown-queue": "Poll will begin in {{days}} {{hours}} (in {{blocks}})", - "countdown-grace": "Grace period ends in {{days}} {{hours}} (in {{blocks}})", + "countdown-expiration": "Poll ends in {{days}} {{hours}}.", + "countdown-queue": "Poll will begin in {{days}} {{hours}}.", + "countdown-grace": "Grace period ends in {{days}} {{hours}}.", "countdown-process": "Proposal is ready to be processed.", "periods-compressed": "cycles", "periods-singular": "cycle", "blocks-compressed": "blocks", "blocks-singular": "block", - "poll-closed-after-time": "Poll ended after {{days}} (at cycle {{height}})", + "poll-closed-after-time": "Poll ended after {{days}}.", "poll-never-ends": "This poll never ends (always on).", "height-compressed": "blocks", "height-singular": "block", @@ -768,8 +768,10 @@ "moloch-process": "Ready for processing", "moloch-period": "Period", "moloch-results": "Results", - "moloch-map-submit-proposal": " ", - "moloch-map-rage-quit": "", + "moloch-period-dao-specific": "Period of {{dao}}", + "moloch-results-dao-specific": "Results of {{dao}}", + "moloch-map-submit-proposal": " ", + "moloch-map-rage-quit": "", "moloch-yes": "Yes", "moloch-no": "No", "moloch-tribute": "Tribute to DAO", @@ -789,7 +791,7 @@ "moloch-period-rejected": "Rejected.", "moloch-period-aborted": "Aborted.", "syncing": "Syncing...", - "moloch-all": "All History", + "moloch-all": "History", "moloch-addresses": "Member addresses", "moloch-address": "Member address", "sign-out": "Sign Out", @@ -810,6 +812,7 @@ "moloch-alert-not-member": "The address being used to vote is not a valid member of this DAO.", "moloch-not-member": "Not a Member", "moloch-period-ragequit": "Ragequit", + "moloch-ragequit-short": "Quit", "moloch-ragequit": "Ragequit", "moloch-ragequit-shares-burn": "Burnt shares", "moloch-ragequit-funds-withdraw": "Withdrawn Funds", @@ -837,5 +840,11 @@ "replica-detail-unlikely-human": "๐Ÿค– Maybe robot.", "replica-detail-not-human": "๐Ÿ‘พ Definitely robot.", "replica-detail-unknown-human": "๐Ÿ˜” Unknown score.", - "sign-out-prompt": "Sign out from current account?" + "sign-out-prompt": "Sign out from current account?", + "search-daos": "Search DAOs", + "collective-dao-title": "{{dao}} โ€” Distributed Autonomous Organization.", + "collective-dao-description": "Proposals and votes from {{dao}}.", + "dao-proposals": "DAO Proposals.", + "dao-events": "DAO Events.", + "all-daos": "All DAOs" } diff --git a/imports/api/contracts/Contracts.js b/imports/api/contracts/Contracts.js index 2fc200c5e..163f102ac 100644 --- a/imports/api/contracts/Contracts.js +++ b/imports/api/contracts/Contracts.js @@ -615,6 +615,10 @@ Schema.Contract = new SimpleSchema({ type: String, optional: true, }, + proposalIndex: { + type: Number, + optional: true, + }, didPass: { type: Boolean, optional: true, diff --git a/imports/api/server/methods.js b/imports/api/server/methods.js index 78f387742..c0eeffb86 100644 --- a/imports/api/server/methods.js +++ b/imports/api/server/methods.js @@ -14,6 +14,12 @@ import { notifierHTML } from '/imports/api/notifier/notifierTemplate.js'; import { getLastTimestamp, getBlockHeight } from '/lib/web3'; import { Collectives } from '/imports/api/collectives/Collectives'; +/** +* @summary include a quantity in a message +* @param {string} quantity to include +* @param {string} message to parse +* @return {number} with total proposals +*/ const _includeQuantity = (quantity, message) => { let modified; if (quantity === 0) { @@ -26,6 +32,24 @@ const _includeQuantity = (quantity, message) => { return modified; }; +/** +* @summary quick count of all proposals in the system +* @return {number} with total proposals +*/ +const _getHistoryCount = () => { + const collectives = Collectives.find().fetch(); + let finalCount = 0; + for (const dao of collectives) { + for (const item of dao.profile.menu) { + if ((item.label === 'moloch-all') && item.count) { + finalCount += item.count; + break; + } + } + } + return finalCount; +}; + Meteor.methods({ /** * @summary sends email verififcation @@ -52,7 +76,6 @@ Meteor.methods({ // Make sure that all arguments are strings. check([toId, fromId, story], [String]); check(transaction, Object); - log(`{ method: 'sendEmail', user: ${logUser()}, story: '${story}' }`); let receiver; @@ -132,7 +155,6 @@ Meteor.methods({ */ subsidizeUser(userId) { check(userId, String); - log(`{ method: 'subsidizeUser', user: ${logUser()} }`); genesisTransaction(userId); }, @@ -142,7 +164,6 @@ Meteor.methods({ */ loadUserTokenBalance(userId) { check(userId, String); - log(`{ method: 'loadUserTokenBalance', user: ${logUser()} }`); loadExternalCryptoBalance(userId); }, @@ -213,7 +234,6 @@ Meteor.methods({ */ getContract(keyword) { check(keyword, String); - log(`{ method: 'getContract', user: ${logUser()}, keyword: '${keyword}' }`); return Contracts.findOne({ keyword }); }, @@ -224,7 +244,6 @@ Meteor.methods({ */ getContractById(contractId) { check(contractId, String); - log(`{ method: 'getContractById', user: ${logUser()}, _id: '${contractId}' }`); return Contracts.findOne({ _id: contractId }); }, @@ -235,7 +254,6 @@ Meteor.methods({ */ getCollectiveById(collectiveId) { check(collectiveId, String); - log(`{ method: 'getCollectiveById', user: ${logUser()}, _id: '${collectiveId}' }`); return Collectives.findOne({ _id: collectiveId }); }, @@ -246,7 +264,6 @@ Meteor.methods({ */ getUser(username) { check(username, String); - log(`{ method: 'getUser', user: ${logUser()}, keyword: '${username}' }`); const user = Meteor.users.findOne({ username }); if (user) { @@ -271,7 +288,6 @@ Meteor.methods({ getOtherDelegate(contractId, currentDelegateId) { check(contractId, String); check(currentDelegateId, String); - log(`{ method: 'getOtherDelegate', user: ${logUser()}, contractId: '${contractId}', currentDelegateId: '${currentDelegateId}' }`); const contract = Contracts.findOne({ _id: contractId }); let user; @@ -300,7 +316,6 @@ Meteor.methods({ */ countReplies(contractId) { check(contractId, String); - log(`{ method: 'countReplies', user: ${logUser()}, contractId: '${contractId}' }`); return Contracts.find({ replyId: contractId }).count(); }, @@ -342,7 +357,6 @@ Meteor.methods({ */ async getBlock(collectives) { check(collectives, Array); - log(`{ method: 'getBlock', collectiveId: ${JSON.stringify(collectives)} }`); const lastTimestamp = await getLastTimestamp().then((resolved) => { return resolved; }); @@ -417,4 +431,73 @@ Meteor.methods({ return replica; }, + /** + * @summary get a user or collective based on a public address with its corresponding replica score + * @param {string} publicAddress to calculate replica on + */ + getMenu(daoName) { + check(daoName, String); + log(`{ method: 'getMenu', daoName: '${daoName}' }`); + + let collectives; + let daoSpecific = false; + if (!daoName) { + collectives = Collectives.find().fetch(); + } else { + collectives = Collectives.find({ name: new RegExp(['^', daoName, '$'].join(''), 'i') }).fetch(); + daoSpecific = true; + } + + const finalMenu = []; + let found = false; + for (const dao of collectives) { + for (const item of dao.profile.menu) { + found = false; + if (finalMenu.length > 0) { + for (const finalItem of finalMenu) { + if (finalItem.label === item.label) { + item.count = parseInt(finalItem.count + item.count, 10); + found = true; + break; + } + } + } + if (!found) { + if (daoSpecific && item.url) { + item.url = `/dao/${daoName.toLowerCase()}${(item.url === '/') ? '' : item.url}`; + } + if (daoSpecific && item.separator) { + item.label = TAPi18n.__(`${item.label}-dao-specific`).replace('{{dao}}', daoName); + } + finalMenu.push(item); + } else { + for (let i = 0; i < finalMenu.length; i += 1) { + if (finalMenu[i].label === item.label) { + finalMenu[i].count = item.count; + finalMenu[i].url = item.url; + } + } + } + } + } + + // insert back to general view + if (daoSpecific) { + finalMenu.unshift({ + label: 'all-daos', + icon: 'images/globe.svg', + iconActivated: 'images/globe-active.svg', + feed: 'user', + value: true, + separator: false, + url: '/', + displayToken: false, + displayCount: true, + count: _getHistoryCount(), + }); + } + + return finalMenu; + }, + }); diff --git a/imports/api/server/publications.js b/imports/api/server/publications.js index 125b995b0..f8043f264 100644 --- a/imports/api/server/publications.js +++ b/imports/api/server/publications.js @@ -33,6 +33,20 @@ Meteor.publish('singleUser', function (userQuery) { return this.ready(); }); +/** +* @summary gets information of a single user +* @return {Object} user data +*/ +Meteor.publish('singleDao', function (daoQuery) { + check(daoQuery, Object); + const daos = Collectives.find(daoQuery); + log(`{ publish: 'singleDao', user: ${logUser()}, query: ${JSON.stringify(daoQuery)}, count: ${daos.count()} }`); + if (daos.count() > 0) { + return daos; + } + return this.ready(); +}); + /** * @summary transactions between a user and a contract * @return {Object} querying terms @@ -41,6 +55,7 @@ Meteor.publish('transaction', function (terms) { check(terms, Object); const parameters = query(terms); const transactions = Transactions.find(parameters.find, parameters.options); + log(`{ publish: 'transaction', user: ${logUser()}, contractId: '${terms.contractId}', count: ${transactions.count()} }`); if (transactions.count() > 0) { return transactions; @@ -248,7 +263,6 @@ Meteor.publish('collectives', function (terms) { return this.ready(); }); - /** * @summary gets information of registered collectives on this instance * @param {Object} terms of query diff --git a/imports/api/transactions/Transactions.js b/imports/api/transactions/Transactions.js index 2786baae7..a53b9fab6 100644 --- a/imports/api/transactions/Transactions.js +++ b/imports/api/transactions/Transactions.js @@ -80,6 +80,10 @@ Schema.Transaction = new SimpleSchema({ type: String, optional: true, }, + collectiveId: { + type: String, + optional: true, + }, timestamp: { type: Date, optional: true, diff --git a/imports/startup/both/modules/metamask.js b/imports/startup/both/modules/metamask.js index 5265a6351..833bc6679 100644 --- a/imports/startup/both/modules/metamask.js +++ b/imports/startup/both/modules/metamask.js @@ -897,6 +897,19 @@ if (Meteor.isServer) { }); } +/** +* @summary shortens the username if its a crypto address +* @param {object} publicAddress string of username to check +* @returns {string} username string +*/ +const _shortenCryptoName = (publicAddress) => { + if (publicAddress.length === 42 && publicAddress.slice(0, 2) === '0x') { + return `${publicAddress.slice(0, 6)}...${publicAddress.slice(38, 42)}`.toLowerCase(); + } + return publicAddress; +}; + +export const shortenCryptoName = _shortenCryptoName; export const transactWithMetamask = _transactWithMetamask; export const coinvote = _coinvote; export const getTransactionStatus = _getTransactionStatus; diff --git a/imports/startup/both/routes.js b/imports/startup/both/routes.js index 1bc72c530..864dd14d3 100644 --- a/imports/startup/both/routes.js +++ b/imports/startup/both/routes.js @@ -3,16 +3,16 @@ import { Session } from 'meteor/session'; import { Meteor } from 'meteor/meteor'; import { DocHead } from 'meteor/kadira:dochead'; import { TAPi18n } from 'meteor/tap:i18n'; -import { HTTP } from 'meteor/http'; +import { Tracker } from 'meteor/tracker'; import { gui } from '/lib/const'; -import { urlDoctor, toTitleCase } from '/lib/utils'; +import { urlDoctor } from '/lib/utils'; import { Contracts } from '/imports/api/contracts/Contracts'; import { stripHTMLfromText } from '/imports/ui/modules/utils'; import { displayNotice } from '/imports/ui/modules/notice'; -import { tokenWeb } from '/lib/token'; -import { sync } from '/imports/ui/templates/layout/sync'; -import { request } from 'http'; +import { Collectives } from '/imports/api/collectives/Collectives'; +import { updateMenu } from '/imports/ui/modules/menu'; + if (Meteor.isClient) { import '/imports/ui/templates/layout/main.js'; @@ -73,6 +73,7 @@ const _meta = (tag, includeTitle) => { const _reset = async () => { Session.set('castSingleVote', undefined); Session.set('newLogin', false); + updateMenu(Router.current().params.dao ? Router.current().params.dao : ''); }; /** @@ -155,19 +156,6 @@ Router.route('/address/:username', { this.next(); }, data() { - /* - let settings; - const user = Meteor.users.findOne({ username: this.params.username }); - if (!user) { - settings = { - username: this.params.username, - }; - } else { - settings = { - username: this.params.username, - userId: user._id, - }; - }*/ return { options: { view: 'peer', sort: { timestamp: -1 }, limit: gui.ITEMS_PER_PAGE, skip: 0, username: this.params.username }, }; @@ -200,6 +188,69 @@ Router.route('/address/:username', { }, }); +/** +* @summary loads a peer feed from @ +**/ +Router.route('/dao/:dao', { + name: 'dao', + template: 'home', + onBeforeAction() { + Session.set('sidebarMenuSelectedId', 999); + _reset(); + this.next(); + }, + waitOn() { + const daoName = new RegExp(['^', this.params.dao, '$'].join(''), 'i'); + return Meteor.subscribe('collectives', { view: 'singleDao', name: daoName }); + }, + data() { + let period = ''; + if (this.params.query.period) { + period = this.params.query.period; + } + + if (this.ready()) { + const daoName = new RegExp(['^', this.params.dao, '$'].join(''), 'i'); + const collective = Collectives.findOne({ name: daoName }); + + return { + options: { view: 'dao', period, collectiveId: collective._id, sort: { timestamp: -1 }, limit: gui.ITEMS_PER_PAGE, skip: 0, name: daoName }, + }; + } + return {}; + }, + onAfterAction() { + let collective; + let title; + let description; + let image; + DocHead.removeDocHeadAddedTags(); + + if (this.ready()) { + collective = Collectives.findOne({ name: new RegExp(['^', this.params.dao, '$'].join(''), 'i') }); + if (collective.name) { + title = `${TAPi18n.__('collective-dao-title').replace('{{dao}}', `${collective.name}`)}`; + description = `${TAPi18n.__('collective-dao-description').replace('{{dao}}', collective.name)}`; + image = `${Router.path('home')}${collective.profile.logo}`; + } + } else { + title = `${TAPi18n.__('collective-dao-title').replace('{{dao}}', `${this.params.dao}`)}`; + description = `${TAPi18n.__('collective-dao-description').replace('{{dao}}', this.params.dao)}`; + image = `${urlDoctor(Meteor.absoluteUrl.defaultOptions.rootUrl)}${Meteor.settings.public.app.logo}`; + } + + DocHead.setTitle(title); + + _meta({ + title, + description, + image, + twitter: Meteor.settings.public.app.twitter, + }); + }, +}); + + /** * @summary loads a post using date in url **/ diff --git a/imports/startup/client/subscribe.js b/imports/startup/client/subscribe.js index 3014999b4..9728e1d6c 100644 --- a/imports/startup/client/subscribe.js +++ b/imports/startup/client/subscribe.js @@ -2,6 +2,3 @@ import { Meteor } from 'meteor/meteor'; import initReactFastclick from 'react-fastclick'; initReactFastclick(); - -Meteor.subscribe('tags'); -Meteor.subscribe('collectives', { view: 'daoList' }); diff --git a/imports/ui/modules/chronos.js b/imports/ui/modules/chronos.js index fe34f153a..b5a34895d 100644 --- a/imports/ui/modules/chronos.js +++ b/imports/ui/modules/chronos.js @@ -27,7 +27,7 @@ const buildSentence = (seconds, mode, micro) => { return `${Math.floor(seconds)} ${TAPi18n.__(`seconds-${mode}${micro ? '-micro' : ''}`)}`; }; -const timeAgo = (date) => { +const _timeAgo = (date) => { const seconds = Math.floor((new Date() - date) / 1000); return buildSentence(seconds, 'ago'); }; @@ -37,6 +37,10 @@ const _timeCompressed = (date, micro) => { return buildSentence(seconds, 'compressed', micro); }; +const _timeComplete = (date) => { + const options = { year: 'numeric', month: 'long', day: 'numeric' }; + return `${_timeAgo(date)} · ${date.toLocaleDateString('en', options)} · ${(date.getHours() < 10) ? `0${(date.getHours())}` : date.getHours()}:${(date.getMinutes() < 10) ? `0${(date.getMinutes())}` : date.getMinutes()}`; +}; const timeLeft = (date) => { const seconds = Math.floor((date - new Date()) / 1000); @@ -47,5 +51,6 @@ const timeLeft = (date) => { }; export const timeCompressed = _timeCompressed; -export const timeSince = timeAgo; +export const timeSince = _timeAgo; +export const timeComplete = _timeComplete; export const countdown = timeLeft; diff --git a/imports/ui/modules/menu.js b/imports/ui/modules/menu.js index d16401b09..b308e6caf 100644 --- a/imports/ui/modules/menu.js +++ b/imports/ui/modules/menu.js @@ -6,10 +6,19 @@ import { gui } from '/lib/const'; import { showFullName } from '/imports/startup/both/modules/utils'; import { Contracts } from '/imports/api/contracts/Contracts'; -import { Transactions } from '/imports/api/transactions/Transactions'; import { getVotes } from '/imports/api/transactions/transaction'; -import { animationSettings } from './animation'; +/** +* @summary updates the sidebar menu according to url context +* @param {string} context with dao name or url data +* @returns {object} menu +*/ +const _updateMenu = (context) => { + Meteor.call('getMenu', context, function (error, result) { + Session.set('sidebarMenu', result); + }); +}; + /** /* @summary for a specific section returns how many new items to signal as new in sidebar @@ -391,3 +400,4 @@ export const toggleSelectedItem = _toggleSelectedItem; export const toggleSidebar = animateMenu; export const sidebarWidth = _sidebarWidth; export const sidebarPercentage = _sidebarPercentage; +export const updateMenu = _updateMenu; diff --git a/imports/ui/templates/components/collective/collective.js b/imports/ui/templates/components/collective/collective.js index abbe30838..e24909573 100644 --- a/imports/ui/templates/components/collective/collective.js +++ b/imports/ui/templates/components/collective/collective.js @@ -11,7 +11,7 @@ import { resetSplit } from '/imports/ui/modules/split'; import { showSidebar } from '/imports/ui/templates/layout/sidebar/sidebar'; import { ReactiveVar } from 'meteor/reactive-var'; -import { shortenCryptoName } from '/imports/ui/templates/components/identity/avatar/avatar'; +import { shortenCryptoName } from '/imports/startup/both/modules/metamask'; import '/imports/ui/templates/components/collective/collective.html'; diff --git a/imports/ui/templates/components/collective/guild/guild.js b/imports/ui/templates/components/collective/guild/guild.js index d7f8acd79..a3b4f7a32 100644 --- a/imports/ui/templates/components/collective/guild/guild.js +++ b/imports/ui/templates/components/collective/guild/guild.js @@ -12,7 +12,7 @@ import '/imports/ui/templates/widgets/chart/chart.js'; const standardBalance = { - token: 'MOLOCH', + token: 'SHARES', balance: 0, available: 0, placed: 0, diff --git a/imports/ui/templates/components/decision/ballot/ballot.js b/imports/ui/templates/components/decision/ballot/ballot.js index 1aa7a3d3e..0d7401a6d 100644 --- a/imports/ui/templates/components/decision/ballot/ballot.js +++ b/imports/ui/templates/components/decision/ballot/ballot.js @@ -172,7 +172,7 @@ const _cryptoVote = async () => { if (Meteor.user()) { if (isMember(Meteor.user(), poll)) { if (isPollOpen(Template.instance().now.get(), poll)) { - if (await hasRightToVote(Meteor.user().username, poll.importId.toNumber(), contract.collectiveId)) { + if (await hasRightToVote(Meteor.user().username, poll.proposalIndex, contract.collectiveId)) { if (setupWeb3(true)) { // wallet alert const icon = Meteor.settings.public.app.logo; @@ -180,11 +180,11 @@ const _cryptoVote = async () => { switch (voteValue) { case defaults.YES: message = TAPi18n.__('dao-confirm-tally').replace('{{voteValue}}', TAPi18n.__('yes')).replace('{{proposalName}}', getProposalDescription(poll.title, true)); - await submitVote(poll.importId.toNumber(), 1, poll, contract); + await submitVote(poll.proposalIndex, 1, poll, contract); break; case defaults.NO: message = TAPi18n.__('dao-confirm-tally').replace('{{voteValue}}', TAPi18n.__('no')).replace('{{proposalName}}', getProposalDescription(poll.title, true)); - await submitVote(poll.importId.toNumber(), 2, poll, contract); + await submitVote(poll.proposalIndex, 2, poll, contract); break; default: message = TAPi18n.__('dao-default-tally').replace('{{proposalName}}', getProposalDescription(poll.title, true)); diff --git a/imports/ui/templates/components/decision/countdown/countdown.html b/imports/ui/templates/components/decision/countdown/countdown.html index 43d71df22..dc78dae1c 100644 --- a/imports/ui/templates/components/decision/countdown/countdown.html +++ b/imports/ui/templates/components/decision/countdown/countdown.html @@ -1,9 +1,16 @@