diff --git a/app/assets/v2/images/chains/rsk.svg b/app/assets/v2/images/chains/rsk.svg index 7e3cb0db28c..f020207239f 100644 --- a/app/assets/v2/images/chains/rsk.svg +++ b/app/assets/v2/images/chains/rsk.svg @@ -1 +1,7 @@ - \ No newline at end of file + + + + + + + diff --git a/app/assets/v2/images/grants/rocket.svg b/app/assets/v2/images/grants/rocket.svg new file mode 100644 index 00000000000..7b4c4386438 --- /dev/null +++ b/app/assets/v2/images/grants/rocket.svg @@ -0,0 +1 @@ + diff --git a/app/assets/v2/images/grants/space-funding-woman.png b/app/assets/v2/images/grants/space-funding-woman.png new file mode 100644 index 00000000000..1ac1d2e526f Binary files /dev/null and b/app/assets/v2/images/grants/space-funding-woman.png differ diff --git a/app/assets/v2/js/cart-data.js b/app/assets/v2/js/cart-data.js index f49b8730825..cda64bea3b2 100644 --- a/app/assets/v2/js/cart-data.js +++ b/app/assets/v2/js/cart-data.js @@ -19,7 +19,8 @@ class CartData { } static share_url(title) { - const donations = this.loadCart(); + const checkedOut = this.loadCheckedOut(); + const donations = (checkedOut.length > 0 ? checkedOut : this.loadCart()); let bulk_add_cart = 'https://gitcoin.co/grants/cart/bulk-add/'; let network = document.web3network; @@ -244,4 +245,28 @@ class CartData { localStorage.setItem('grants_cart', JSON.stringify(list)); applyCartMenuStyles(); } + + static loadCheckedOut() { + const checkedOutList = localStorage.getItem('contributions_were_successful'); + + if (!checkedOutList) { + return []; + } + + const parsedCheckout = JSON.parse(checkedOutList); + + if (!Array.isArray(parsedCheckout)) { + return []; + } + + return parsedCheckout; + } + + static setCheckedOut(list) { + localStorage.setItem('contributions_were_successful', JSON.stringify(list)); + } + + static clearCheckedOut() { + localStorage.removeItem('contributions_were_successful'); + } } diff --git a/app/assets/v2/js/cart.js b/app/assets/v2/js/cart.js index ad77937aea9..f5979645f5c 100644 --- a/app/assets/v2/js/cart.js +++ b/app/assets/v2/js/cart.js @@ -65,13 +65,7 @@ Vue.component('grants-cart', { // Checkout, zkSync zkSyncUnsupportedTokens: [], // Used to inform user which tokens in their cart are not on zkSync zkSyncEstimatedGasCost: undefined, // Used to tell user which checkout method is cheaper - isZkSyncDown: false, // disable zkSync when true - // Collection - showCreateCollection: false, - collectionTitle: '', - collectionDescription: '', - collections: [], - selectedCollection: null + isZkSyncDown: false // disable zkSync when true }; }, @@ -132,17 +126,6 @@ Vue.component('grants-cart', { return document.contxt.github_handle; }, - // Determine when activate the save collection button - isValidCollection() { - if (this.selectedCollection !== null) { - return true; - } else if (this.collectionTitle.length > 3 && this.collectionDescription.length < 140) { - return true; - } - - return false; - }, - // Percentage of donation that goes to Gitcoin gitcoinFactor() { return Number(this.gitcoinFactorRaw) / 100; @@ -188,7 +171,7 @@ Vue.component('grants-cart', { let gitcoinFactor = String(100 - (100 * this.gitcoinFactor)); const donations = this.grantsByTenant.map((grant, index) => { const tokenDetails = this.getTokenByName(grant.grant_donation_currency); - const amount = parseUnits(String(grant.grant_donation_amount), tokenDetails.decimals) + const amount = parseUnits(String(grant.grant_donation_amount || 0), tokenDetails.decimals) .mul(gitcoinFactor) .div(100); @@ -570,7 +553,7 @@ Vue.component('grants-cart', { this.grantsByTenant.forEach(grant => { // Scale up number by 1e18 to use BigNumber, multiply by scaleFactor - const totalDonationAmount = parseEther(String(grant.grant_donation_amount)) + const totalDonationAmount = parseEther(String(grant.grant_donation_amount || 0)) .mul(String(scaleFactor * 100)) .div('100'); @@ -658,7 +641,7 @@ Vue.component('grants-cart', { priority: 1 }; } - return this.currentTokens.filter(token => token.name === name)[0]; + return this.filterByChainId.filter(token => token.name === name)[0]; }, async applyAmountToAllGrants(grant) { @@ -1079,15 +1062,20 @@ Vue.component('grants-cart', { * success alert */ async finalizeCheckout() { + // Number of items descides the timeout time + const timeout_amount = 1500 + (this.grantsByTenant.length * 500); // Clear cart, redirect back to grants page, and show success alert - localStorage.setItem('contributions_were_successful', 'true'); - localStorage.setItem('contributions_count', String(this.grantsByTenant.length)); - let timeout_amount = 1500 + (CartData.loadCart().length * 500); + + CartData.setCheckedOut(this.grantsByTenant); + // Remove each grant from the cart which has just been checkout + this.grantsByTenant.forEach((grant) => { + CartData.removeIdFromCart(grant.grant_id); + }); setTimeout(function() { _alert('Contributions saved', 'success', 1000); setTimeout(function() { - window.location.href = `${window.location.origin}/grants`; + window.location.href = `${window.location.origin}/grants/explorer`; }, 500); }, timeout_amount); }, @@ -1246,45 +1234,7 @@ Vue.component('grants-cart', { return cartData; } return false; - }, - - // ================== Start collection logic ================== - createCollection: async function() { - const csrfmiddlewaretoken = document.querySelector('[name=csrfmiddlewaretoken]').value; - const cart = CartData.loadCart(); - const grantIds = cart.map(grant => grant.grant_id); - let response; - - const body = { - collectionTitle: this.collectionTitle, - collectionDescription: this.collectionDescription, - grants: grantIds - }; - - if (this.selectedCollection) { - body['collection'] = this.selectedCollection; - } - - try { - - response = await fetchData('/grants/v1/api/collections/new', 'POST', body, {'X-CSRFToken': csrfmiddlewaretoken}); - const redirect = `/grants/collections?collection_id=${response.collection.id}`; - - _alert('Congratulations, your new collection was created successfully!', 'success'); - this.cleanCollectionModal(); - this.showCreateCollection = false; - - window.location = redirect; - - } catch (e) { - _alert(e.msg, 'error'); - } - }, - cleanCollectionModal: function() { - this.collectionTitle = ''; - this.collectionDescription = ''; } - // ================== End collection logic ================== }, watch: { @@ -1431,10 +1381,6 @@ Vue.component('grants-cart', { // Show user cart now this.isLoading = false; - - const collections_response = await fetchData('/grants/v1/api/collections/'); - - this.collections = collections_response.collections; }, beforeDestroy() { diff --git a/app/assets/v2/js/grants/_detail-component.js b/app/assets/v2/js/grants/_detail-component.js index a57f4924153..d84a776c85c 100644 --- a/app/assets/v2/js/grants/_detail-component.js +++ b/app/assets/v2/js/grants/_detail-component.js @@ -1,8 +1,8 @@ -let isStaff = document.contxt.is_staff || false; +const isStaff = document.contxt.is_staff || false; -let userCode = typeof user_code !== 'undefined' ? user_code : undefined; -let verificationTweet = typeof verification_tweet !== 'undefined' ? verification_tweet : undefined; +const userCode = typeof user_code !== 'undefined' ? user_code : undefined; +const verificationTweet = typeof verification_tweet !== 'undefined' ? verification_tweet : undefined; Vue.component('v-select', VueSelect.VueSelect); Vue.use(VueQuillEditor); @@ -12,14 +12,14 @@ Quill.register('modules/ImageExtend', ImageExtend); Vue.mixin({ methods: { grantInCart: function() { - let vm = this; - let inCart = CartData.cartContainsGrantWithId(vm.grant.id); + const vm = this; + const inCart = CartData.cartContainsGrantWithId(vm.grant.id); vm.$set(vm.grant, 'isInCart', inCart); return vm.grant.isInCart; }, addToCart: async function() { - let vm = this; + const vm = this; const grantCartPayloadURL = `/grants/v1/api/${vm.grant.id}/cart_payload`; const response = await fetchData(grantCartPayloadURL, 'GET'); @@ -31,7 +31,7 @@ Vue.mixin({ }, removeFromCart: function() { - let vm = this; + const vm = this; vm.$set(vm.grant, 'isInCart', false); CartData.removeIdFromCart(vm.grant.id); @@ -41,7 +41,7 @@ Vue.mixin({ }, editGrantModal: function() { - let vm = this; + const vm = this; vm.logoPreview = vm.grant.logo_url; @@ -49,7 +49,7 @@ Vue.mixin({ }, saveGrant: function(event) { event.preventDefault(); - let vm = this; + const vm = this; if (!vm.checkForm(event)) return; @@ -59,7 +59,7 @@ Vue.mixin({ }; const apiUrlGrant = `/grants/v1/api/grant/edit/${vm.grant.id}/`; - let data = { + const data = { 'title': vm.grant.title, 'reference_url': vm.grant.reference_url, 'description': vm.$refs.myQuillEditor.quill.getText(), @@ -129,9 +129,9 @@ Vue.mixin({ cancelGrant: function(event) { event.preventDefault(); - let vm = this; + const vm = this; - let cancel = window.prompt('Please write "CONFIRM" to cancel the grant.'); + const cancel = window.prompt('Please write "CONFIRM" to cancel the grant.'); if (cancel !== 'CONFIRM') { return; @@ -153,10 +153,10 @@ Vue.mixin({ }, toggleFollowingGrant: async function(grantId) { - let vm = this; + const vm = this; const favoriteUrl = `/grants/${grantId}/favorite`; - let response = await fetchData(favoriteUrl, 'POST'); + const response = await fetchData(favoriteUrl, 'POST'); if (response.action === 'follow') { vm.grant.favorite = true; @@ -167,7 +167,7 @@ Vue.mixin({ return true; }, flag: function() { - let vm = this; + const vm = this; const comment = prompt('What is your reason for flagging this Grant?'); @@ -199,7 +199,7 @@ Vue.mixin({ }); }, userSearch(search, loading) { - let vm = this; + const vm = this; if (search.length < 3) { return; @@ -209,9 +209,9 @@ Vue.mixin({ }, getUser: async function(loading, search, selected) { - let vm = this; - let myHeaders = new Headers(); - let url = `/api/v0.1/users_search/?token=${currentProfile.githubToken}&term=${escape(search)}&suppress_non_gitcoiners=true`; + const vm = this; + const myHeaders = new Headers(); + const url = `/api/v0.1/users_search/?token=${currentProfile.githubToken}&term=${escape(search)}&suppress_non_gitcoiners=true`; myHeaders.append('X-Requested-With', 'XMLHttpRequest'); return new Promise(resolve => { @@ -235,12 +235,12 @@ Vue.mixin({ }); }, changeColor() { - let vm = this; + const vm = this; vm.grant.image_css = `background-color: ${vm.logoBackground};`; }, onFileChange(e) { - let vm = this; + const vm = this; if (!e.target) { return; @@ -252,7 +252,7 @@ Vue.mixin({ return; } vm.imgTransition = true; - let imgCompress = new Compressor(file, { + const imgCompress = new Compressor(file, { quality: 0.6, maxWidth: 2000, success(result) { @@ -267,7 +267,7 @@ Vue.mixin({ }); }, async twitterVerification() { - let vm = this; + const vm = this; if (!vm.grant.twitter_handle_1 || vm.grant.twitter_handle_1 == '') { _alert('Please add a twitter account to your grant!', 'error', 5000); @@ -320,13 +320,13 @@ Vue.mixin({ } }, tweetVerification() { - let vm = this; + const vm = this; const tweetContent = `https://twitter.com/intent/tweet?text=${encodeURIComponent(vm.verification_tweet)}%20${encodeURIComponent(vm.user_code)}`; window.open(tweetContent, '_blank'); }, checkForm: function(e) { - let vm = this; + const vm = this; vm.submitted = true; vm.errors = {}; @@ -405,7 +405,7 @@ Vue.mixin({ if (!user?.fields) { return user; } - let newTeam = {}; + const newTeam = {}; newTeam['id'] = user.pk; newTeam['avatar_url'] = `/dynamic/avatar/${user.fields.handle}`; @@ -425,7 +425,7 @@ Vue.mixin({ return this.$refs.myQuillEditor.quill; }, filteredMsg: function() { - let msgs = [ + const msgs = [ '💪 keep up the great work', '👍 i appreciate you', '🙌 Great Job', @@ -453,7 +453,7 @@ Vue.mixin({ ); }, isUserLogged() { - let vm = this; + const vm = this; if (document.contxt.github_handle) { return true; @@ -487,7 +487,6 @@ Vue.component('grant-details', { logo: null, logoPreview: null, logoBackground: null, - relatedGrants: [], rows: 0, perPage: 4, currentPage: 1, @@ -540,7 +539,7 @@ Vue.component('grant-details', { }; }, mounted: function() { - let vm = this; + const vm = this; vm.grant_twitter_handle_1 = vm.grant.twitter_handle_1; vm.grant.description_rich_edited = vm.grant.description_rich; @@ -553,7 +552,7 @@ Vue.component('grant-details', { grant: { deep: true, handler: function(newVal, oldVal) { - let vm = this; + const vm = this; if (this.dirty && this.submitted) { this.checkForm(); diff --git a/app/assets/v2/js/grants/_detail.js b/app/assets/v2/js/grants/_detail.js index 926c998bd03..9f9acf633df 100644 --- a/app/assets/v2/js/grants/_detail.js +++ b/app/assets/v2/js/grants/_detail.js @@ -7,14 +7,14 @@ Quill.register('modules/ImageExtend', ImageExtend); Vue.mixin({ methods: { fetchGrantDetails: function(id) { - let vm = this; + const vm = this; vm.loading = true; if (!id) { id = grantDetails.grant_id; } - let url = `/grants/v1/api/grant/${id}/`; + const url = `/grants/v1/api/grant/${id}/`; return new Promise(resolve => { @@ -32,13 +32,37 @@ Vue.mixin({ resolve(); }).catch(console.error); }); + }, + paginate: function(array, page_size, page_number) { + return array.slice(page_number * page_size, page_number * page_size + page_size); + }, + tabChange: function(input) { + console.log(input); + window.location = `${this.grant.details_url}?tab=${input}`; + }, + enableTab: function() { + let vm = this; + let urlParams = new URLSearchParams(window.location.search); + + vm.tab = urlParams.get('tab'); + switch (vm.tab) { + case 'sybil_profile': + vm.tabSelected = 3; + break; + case 'stats': + vm.tabSelected = 4; + break; + default: + vm.tabSelected = 0; + } + window.history.replaceState({}, document.title, `${window.location.pathname}`); }, fetchRelated: function() { - let vm = this; + const vm = this; + const size = 3; let ids; - let size = 6; if (!Object.keys(vm.grant.metadata).length || !vm.grant.metadata?.related?.length) { return; @@ -47,15 +71,20 @@ Vue.mixin({ ids = vm.grant.metadata.related.map(arr => { return arr[0]; }); + vm.relatedGrantsIds = vm.paginate(ids, size, vm.relatedGrantsPage); vm.relatedGrantsPage += 1; + vm.relatedGrantsHasNext = vm.relatedGrantsPage + 1 < ids.length / size; + if (!vm.relatedGrantsIds.length) { return; } + vm.loadingRelated = true; - let url = `/grants/v1/api/grants?pks=${vm.relatedGrantsIds}`; + + const url = `/grants/v1/api/grants?pks=${vm.relatedGrantsIds}`; fetch(url).then(function(res) { return res.json(); @@ -66,11 +95,8 @@ Vue.mixin({ vm.loadingRelated = false; }).catch(console.error); }, - paginate: function(array, page_size, page_number) { - return array.slice(page_number * page_size, page_number * page_size + page_size); - }, fetchTransactions: function() { - let vm = this; + const vm = this; page = vm.transactions.next_page_number; if (!page) { @@ -78,7 +104,7 @@ Vue.mixin({ } vm.loadingTx = true; - let url = `/grants/v1/api/grant/${vm.grant.id}/contributions?page=${page}`; + const url = `/grants/v1/api/grant/${vm.grant.id}/contributions?page=${page}`; fetch(url).then(function(res) { return res.json(); @@ -95,89 +121,21 @@ Vue.mixin({ }).catch(console.error); }, - fetchContributors: function() { - let vm = this; - - page = vm.contributors.next_page_number; - if (!page) { - return; - } - vm.loadingContributors = true; - - let url = `/grants/v1/api/grant/${vm.grant.id}/contributors?page=${page}`; - - fetch(url).then(function(res) { - return res.json(); - }).then(function(json) { - json.contributors.forEach(function(item) { - vm.contributors.grantContributors.push(item); - }); - - vm.contributors.num_pages = json.num_pages; - vm.contributors.has_next = json.has_next; - vm.contributors.next_page_number = json.next_page_number; - vm.contributors.count = json.count; - vm.loadingContributors = false; - - }).catch(console.error); - }, backNavigation: function() { - let vm = this; - var lgi = localStorage.getItem('last_grants_index'); - var lgt = localStorage.getItem('last_grants_title'); + const vm = this; + const lgi = localStorage.getItem('last_grants_index'); + const lgt = localStorage.getItem('last_grants_title'); if (lgi && lgt) { vm.$set(vm.backLink, 'url', lgi); vm.$set(vm.backLink, 'title', lgt); } }, - tabChange: function(input) { - - console.log(input); - window.location = `${this.grant.details_url}?tab=${input}`; - }, - enableTab: function() { - let vm = this; - let urlParams = new URLSearchParams(window.location.search); - - vm.tab = urlParams.get('tab'); - - switch (vm.tab) { - case 'sybil_profile': - vm.tabSelected = 4; - break; - case 'stats': - vm.tabSelected = 5; - break; - default: - vm.tabSelected = 0; - } - window.history.replaceState({}, document.title, `${window.location.pathname}`); - }, scrollToElement(element) { - let container = this.$refs[element]; + const container = this.$refs[element]; container.scrollIntoViewIfNeeded({behavior: 'smooth', block: 'start'}); } - }, - computed: { - // contributors() { - // let obj = this.transactions.grantTransactions.map((contributor) => { - // let newContributor = {}; - - // newContributor['id'] = contributor.subscription.id; - // newContributor['contributor_profile'] = contributor.subscription.contributor_profile; - // newContributor['avatar_url'] = `/dynamic/avatar/${contributor.subscription.contributor_profile}`; - // return newContributor; - // }) - - // return obj.reduce((user, current) => { - // return Object.assign(user, { - // [current.contributor_profile]: current - // }); - // }, {}); - - // } } }); @@ -190,25 +148,21 @@ if (document.getElementById('gc-grant-detail')) { }, data() { return { - loadingContributors: false, + loading: false, loadingTx: false, loadingRelated: false, - loading: false, - isStaff: isStaff, + relatedGrants: [], + relatedGrantsPage: 0, + relatedGrantsHasNext: false, + relatedGrantsIds: [], transactions: { grantTransactions: [], next_page_number: 1 }, - contributors: { - grantContributors: [], - next_page_number: 1 - }, + isStaff: isStaff, grant: {}, tabSelected: 0, tab: null, - relatedGrants: [], - relatedGrantsPage: 0, - relatedGrantsIds: [], backLink: { url: '/grants', title: 'Grants' diff --git a/app/assets/v2/js/grants/components.js b/app/assets/v2/js/grants/components.js index 90cc2182a8b..b2a325c1e08 100644 --- a/app/assets/v2/js/grants/components.js +++ b/app/assets/v2/js/grants/components.js @@ -1,7 +1,7 @@ Vue.component('grant-card', { delimiters: [ '[[', ']]' ], props: [ 'grant', 'cred', 'token', 'view', 'short', 'show_contributions', - 'contributions', 'toggle_following', 'collection', 'has_collections' + 'contributions', 'toggle_following', 'collection' ], data: function() { return { @@ -94,7 +94,7 @@ Vue.component('grant-card', { showSideCart(); }, addToCollection: async function({collection, grant}) { - const collectionAddGrantURL = `v1/api/collections/${collection.id}/grants/add`; + const collectionAddGrantURL = `/grants/v1/api/collections/${collection.id}/grants/add`; const response = await fetchData(collectionAddGrantURL, 'POST', { 'grant': grant.id }); @@ -102,6 +102,12 @@ Vue.component('grant-card', { _alert('Grant added successfully', 'success', 1000); } }, + computed: { + has_collections() { + return this.collections.length; + } + + }, mounted() { this.checkIsCurator(); this.grantInCart(); @@ -132,7 +138,7 @@ Vue.component('grant-collection', { window.getSelection().removeAllRanges(); }, addToCart: async function() { - const collectionDetailsURL = `v1/api/collections/${this.collection.id}`; + const collectionDetailsURL = `/grants/v1/api/collections/${this.collection.id}`; const collection = await fetchData(collectionDetailsURL, 'GET'); (collection.grants || []).forEach((grant) => { diff --git a/app/assets/v2/js/grants/create-collection-modal.js b/app/assets/v2/js/grants/create-collection-modal.js new file mode 100644 index 00000000000..952a34a8156 --- /dev/null +++ b/app/assets/v2/js/grants/create-collection-modal.js @@ -0,0 +1,75 @@ +Vue.component('create-collection-modal', { + delimiters: [ '[[', ']]' ], + data: function() { + return { + modalId: 'create-collection', + collectionTitle: '', + collectionDescription: '', + collections: [], + selectedCollection: null, + showCreateCollection: false + }; + }, + computed: { + isValidCollection() { + if (this.selectedCollection !== null) { + return true; + } else if (this.collectionTitle.length > 3 && this.collectionDescription.length < 140) { + return true; + } + + return false; + } + }, + methods: { + fetchCollections() { + this.showCreateCollection = true; + fetchData('/grants/v1/api/collections/').then(response => { + console.log('COLLECTIONS', response); + if (response.collections && response.collections.length > 0) { + this.collections = response.collections; + } + }); + }, + close() { + this.$bvModal.hide(this.modalId); + }, + createCollection: async function() { + const csrfmiddlewaretoken = document.querySelector('[name=csrfmiddlewaretoken]').value; + const checkedOut = CartData.loadCheckedOut(); + const cart = (checkedOut.length > 0 ? checkedOut : CartData.loadCart()); + const grantIds = cart.map(grant => grant.grant_id); + let response; + + const body = { + collectionTitle: this.collectionTitle, + collectionDescription: this.collectionDescription, + grants: grantIds + }; + + if (this.selectedCollection) { + body['collection'] = this.selectedCollection; + } + + try { + + response = await fetchData('/grants/v1/api/collections/new', 'POST', body, {'X-CSRFToken': csrfmiddlewaretoken}); + const redirect = `/grants/explorer/collections?collection_id=${response.collection.id}`; + + _alert('Congratulations, your new collection was created successfully!', 'success'); + this.cleanCollectionModal(); + + this.$bvModal.hide(this.modalId); + this.$bvModal.hide('contribution-thanks'); // triggers cart clear + window.location = redirect; + + } catch (e) { + _alert(e.msg, 'error'); + } + }, + cleanCollectionModal: function() { + this.collectionTitle = ''; + this.collectionDescription = ''; + } + } +}); diff --git a/app/assets/v2/js/grants/funding.js b/app/assets/v2/js/grants/funding.js index 2d3ddc5f03c..a4674423593 100644 --- a/app/assets/v2/js/grants/funding.js +++ b/app/assets/v2/js/grants/funding.js @@ -1,4 +1,3 @@ - // DOCUMENT let allTokens; const fetchTokens = async() => { @@ -11,71 +10,30 @@ fetchTokens(); $(document).ready(function() { - // Check localStorage to see if we need to show alert - const shouldShowAlert = Boolean(localStorage.getItem('contributions_were_successful')); - - if (shouldShowAlert) { - // This alert currently shows after Ethereum checkouts only. As a result, we make sure to - // only clear ETH grants from local storage - const numberOfContributions = Number(localStorage.getItem('contributions_count')); - const grantWord = numberOfContributions === 1 ? 'grant' : 'grants'; - const message = `You have successfully funded ${numberOfContributions} ${grantWord}. Thank you for your contribution!`; - - _alert(message, 'success'); - localStorage.removeItem('contributions_were_successful'); - localStorage.removeItem('contributions_count'); - $('#tweetModal').bootstrapModal('show'); - - const allDonations = CartData.loadCart(); - const ethereumDonations = allDonations.filter((grant) => grant.tenants[0] === 'ETH'); - const otherDonations = allDonations.filter((grant) => grant.tenants[0] !== 'ETH'); - - if (allDonations.length) { - let cart_html = 'You just funded: '; - let bulk_add_cart = CartData.share_url(); - - for (let i = 0; i < allDonations.length; i += 1) { - const donation = allDonations[i]; - - cart_html += '
  • ' + donation['grant_title'] + ' for ' + donation['grant_donation_amount'] + ' ' + donation['grant_donation_currency']; - if ( - donation.clr_round_num != '' && - donation.is_clr_eligible && - !donation.is_on_team - ) { - cart_html += ' (+' + donation['grant_donation_clr_match'] + ' DAI match)'; - } - cart_html += '
  • '; - } - cart_html += '
    Here is a handy link for sharing this collection with others.'; - $("" + cart_html + '').insertBefore($('#tweetModal span.copy')); - $('#tweetModal a.button').attr('href', 'https://twitter.com/intent/tweet?text=I%20just%20funded%20these%20' + allDonations.length + '%20grants%20on%20@gitcoin%20=%3E%20' + bulk_add_cart); - $('#tweetModal a.button').text('Tweet about it'); - } - CartData.setCart(otherDonations); - } - $('#js-addToCart-form').submit(function(event) { event.preventDefault(); // const formData = objectifySerialized($(this).serializeArray()); // const formData = objectifySerialized($(this).serializeArray()); - CartData.addToCart(grantDetails); showSideCart(); }); - $('.infinite-container').on('submit', '.js-addDetailToCart-form', function(event) { - event.preventDefault(); + $('.infinite-container').on( + 'submit', + '.js-addDetailToCart-form', + function(event) { + event.preventDefault(); - const formData = objectifySerialized($(this).serializeArray()); + const formData = objectifySerialized($(this).serializeArray()); - CartData.addToCart(formData); + CartData.addToCart(formData); - showSideCart(); - }); + showSideCart(); + } + ); $('#close-side-cart').click(function() { hideSideCart(); @@ -86,11 +44,13 @@ $(document).ready(function() { let cartData = CartData.loadCart(); const network = document.web3network || 'mainnet'; const selected_grant_index = $(this).data('id'); - const preferredAmount = cartData[selected_grant_index].grant_donation_amount; - const preferredTokenName = cartData[selected_grant_index].grant_donation_currency; + const preferredAmount = + cartData[selected_grant_index].grant_donation_amount; + const preferredTokenName = + cartData[selected_grant_index].grant_donation_currency; const preferredTokenAddress = tokens(network) - .filter(token => token.name === preferredTokenName) - .map(token => token.addr)[selected_grant_index]; + .filter((token) => token.name === preferredTokenName) + .map((token) => token.addr)[selected_grant_index]; // Get fallback amount in ETH (used when token is not available for a grant) const url = `${window.location.origin}/sync/get_amount?amount=${preferredAmount}&denomination=${preferredTokenName}`; @@ -99,8 +59,11 @@ $(document).ready(function() { // Update cart values cartData.forEach((grant, index) => { - const acceptsAllTokens = (grant.grant_token_address === '0x0000000000000000000000000000000000000000'); - const acceptsSelectedToken = grant.grant_token_address === preferredTokenAddress; + const acceptsAllTokens = + grant.grant_token_address === + '0x0000000000000000000000000000000000000000'; + const acceptsSelectedToken = + grant.grant_token_address === preferredTokenAddress; if (acceptsAllTokens || acceptsSelectedToken) { // Use the user selected option @@ -157,9 +120,7 @@ function sideCartRowForGrant(grant, index) { return cartRow; } - function tokenOptionsForGrant(grant) { - var network = document.web3network; if (!network) { @@ -167,39 +128,44 @@ function tokenOptionsForGrant(grant) { } // let tokenDataList = tokens(network); - let tokenDataList = allTokens.filter((token) => token.network === networkName || 'mainnet'); + let tokenDataList = allTokens.filter( + (token) => token.network === networkName || 'mainnet' + ); let tokenDefault = 'ETH'; if (grant.tenants && grant.tenants.includes('ZCASH')) { - tokenDataList = tokenDataList.filter(token => token.chainId === 123123); + tokenDataList = tokenDataList.filter((token) => token.chainId === 123123); tokenDefault = 'ZEC'; - } if (grant.tenants && grant.tenants.includes('CELO')) { - tokenDataList = tokenDataList.filter(token => token.chainId === 42220); + } + if (grant.tenants && grant.tenants.includes('CELO')) { + tokenDataList = tokenDataList.filter((token) => token.chainId === 42220); tokenDefault = 'CELO'; } else if (grant.tenants && grant.tenants.includes('ZIL')) { - tokenDataList = tokenDataList.filter(token => token.chainId === 102); + tokenDataList = tokenDataList.filter((token) => token.chainId === 102); tokenDefault = 'ZIL'; } else if (grant.tenants && grant.tenants.includes('HARMONY')) { - tokenDataList = tokenDataList.filter(token => token.chainId === 1000); + tokenDataList = tokenDataList.filter((token) => token.chainId === 1000); tokenDefault = 'ONE'; } else if (grant.tenants && grant.tenants.includes('BINANCE')) { - tokenDataList = tokenDataList.filter(token => token.chainId === 56); + tokenDataList = tokenDataList.filter((token) => token.chainId === 56); tokenDefault = 'BNB'; } else if (grant.tenants && grant.tenants.includes('POLKADOT')) { - tokenDataList = tokenDataList.filter(token => token.chainId === 58); + tokenDataList = tokenDataList.filter((token) => token.chainId === 58); tokenDefault = 'DOT'; } else if (grant.tenants && grant.tenants.includes('KUSAMA')) { - tokenDataList = tokenDataList.filter(token => token.chainId === 59); + tokenDataList = tokenDataList.filter((token) => token.chainId === 59); tokenDefault = 'KSM'; } else if (grant.tenants && grant.tenants.includes('RSK')) { tokenDataList = tokenDataList.filter(token => token.chainId === 30); tokenDefault = 'R-BTC'; } else { - tokenDataList = tokenDataList.filter(token => token.chainId === 1); + tokenDataList = tokenDataList.filter((token) => token.chainId === 1); } - const acceptsAllTokens = (grant.grant_token_address === '0x0000000000000000000000000000000000000000' || - grant.grant_token_address === '0x0'); + const acceptsAllTokens = + grant.grant_token_address === + '0x0000000000000000000000000000000000000000' || + grant.grant_token_address === '0x0'; let options = ''; @@ -208,8 +174,8 @@ function tokenOptionsForGrant(grant) { `; - tokenDataList = tokenDataList.filter(tokenData => { - return (tokenData.address === grant.grant_token_address); + tokenDataList = tokenDataList.filter((tokenData) => { + return tokenData.address === grant.grant_token_address; }); } @@ -232,9 +198,7 @@ function tokenOptionsForGrant(grant) { function showSideCart() { // Remove elements in side cart - $('#side-cart-data') - .find('div.side-cart-row') - .remove(); + $('#side-cart-data').find('div.side-cart-row').remove(); // Add all elements in side cart let cartData = CartData.loadCart(); @@ -247,13 +211,15 @@ function showSideCart() { // Register remove click handler $(`#side-cart-row-remove-${grant.grant_id}`).click(function() { if (typeof appGrants !== 'undefined') { - - appGrants.grants.filter(grantSingle => { + appGrants.grants.filter((grantSingle) => { if (Number(grantSingle.id) === Number(grant.grant_id)) { grantSingle.isInCart = false; } }); - } else if (typeof appGrantDetails !== 'undefined' && appGrantDetails.grant.id === Number(grant.grant_id)) { + } else if ( + typeof appGrantDetails !== 'undefined' && + appGrantDetails.grant.id === Number(grant.grant_id) + ) { appGrantDetails.grant.isInCart = false; } @@ -265,15 +231,25 @@ function showSideCart() { $(`#side-cart-amount-${grant.grant_id}`).change(function() { const newAmount = parseFloat($(this).val()); - CartData.updateCartItem(grant.grant_id, 'grant_donation_amount', newAmount); + CartData.updateCartItem( + grant.grant_id, + 'grant_donation_amount', + newAmount + ); }); // Select appropriate currency - $(`#side-cart-currency-${grant.grant_id}`).val(grant.grant_donation_currency); + $(`#side-cart-currency-${grant.grant_id}`).val( + grant.grant_donation_currency + ); // Register currency change handler $(`#side-cart-currency-${grant.grant_id}`).change(function() { - CartData.updateCartItem(grant.grant_id, 'grant_donation_currency', $(this).val()); + CartData.updateCartItem( + grant.grant_id, + 'grant_donation_currency', + $(this).val() + ); }); $(`#side-cart-currency-${grant.grant_id}`).select2(); @@ -304,7 +280,9 @@ function hideSideCart() { } function toggleSideCart() { - $('#grants-details > div').toggleClass('col-12 col-md-8 col-lg-9 d-none d-md-inline-flex'); + $('#grants-details > div').toggleClass( + 'col-12 col-md-8 col-lg-9 d-none d-md-inline-flex' + ); $('#side-cart').toggle(); $('#side-cart').toggleClass('col-12 col-md-4 col-lg-3'); diff --git a/app/assets/v2/js/grants/grant-thanks-modal.js b/app/assets/v2/js/grants/grant-thanks-modal.js new file mode 100644 index 00000000000..e62a790c755 --- /dev/null +++ b/app/assets/v2/js/grants/grant-thanks-modal.js @@ -0,0 +1,36 @@ +Vue.component('contribution-thanks-modal', { + delimiters: [ '[[', ']]' ], + data: function() { + return { + modalId: 'contribution-thanks', + numberOfContributions: 0, + donations: [], + tweetUrl: '' + }; + }, + mounted: function() { + const checkoutData = CartData.loadCheckedOut(); + const shouldShow = checkoutData.length > 0; + + this.numberOfContributions = checkoutData.length; + + this.tweetUrl = `https://twitter.com/intent/tweet?text=I just funded ${this.numberOfContributions} grants on @gitcoin ${CartData.share_url()}`; + + if (shouldShow) { + this.$bvModal.show(this.modalId); + } + + this.donations = checkoutData; + }, + methods: { + close() { + this.$bvModal.hide(this.modalId); + }, + handleHide() { + CartData.clearCheckedOut(); + }, + showSaveAsCollection() { + this.$bvModal.show('create-collection'); + } + } +}); diff --git a/app/assets/v2/js/grants/index.js b/app/assets/v2/js/grants/index.js index ae99b1a8fe7..22230cff23a 100644 --- a/app/assets/v2/js/grants/index.js +++ b/app/assets/v2/js/grants/index.js @@ -2,35 +2,8 @@ let grantsNumPages = ''; let grantsHasNext = false; let numGrants = ''; -const toggleStyle = function(style) { - - if (!style) { - return; - } - - let banner; - - if (style.bg) { - banner = `url("${style.bg }") center top / ${style.size || ''} ${style.color || ''} no-repeat`; - } else { - banner = `url("${ style.banner_image }") center no-repeat`; - } - $('#grant-hero-img').css('background', banner); - if (style.background_image) { - $('#grant-background-image-mount-point').css('background-image', style.background_image); - } - - if (style.inline_css) { - $('style').last().text(style.inline_css); - } else { - $('style').last().text(''); - } -}; $(document).ready(() => { - $('#sort_option').select2({ - minimumResultsForSearch: Infinity - }); if ($('.grants_type_nav').length) { localStorage.setItem('last_grants_index', document.location.href); @@ -41,31 +14,6 @@ $(document).ready(() => { localStorage.setItem('last_all_grants_title', $('title').text().split('|')[0]); } - $('#wall_of_love .show_more_wall_of_love').click(function(e) { - $('#wall_of_love .hidden').removeClass('hidden'); - $(this).remove(); - e.preventDefault(); - }); - - - $(document).on('click', '.grant-item', function() { - $(this).find('img').each(function() { - var src_url = $(this).data('src'); - - $(this).attr('src', src_url); - }); - }); - - - $('.select2-selection__rendered').removeAttr('title'); - - waitforWeb3(() => { - let _network = $('#grant-network').html(); - let links = $('.etherscan_link'); - - etherscanUrlConvert(links, _network); - }); - window.addEventListener('scroll', function() { if ($('.activity_stream').length && $('.activity_stream').isInViewport()) { $('#skip').addClass('hidden'); @@ -75,7 +23,7 @@ $(document).ready(() => { }); - toggleStyle(document.current_style); + // toggleStyle(document.current_style); }); Vue.component('grant-sidebar', { @@ -108,12 +56,21 @@ Vue.component('grant-sidebar', { let me = state ? 'me' : 'all'; event.preventDefault; - this.filter_grants({type: me, category: ''}); + this.filter_grants({type: me, category: '', keyword: ''}); }, isMobileDevice: function() { return window.innerWidth < 576; }, + toggleMyCollections: function(state, event) { + let me = state ? {type: 'collections', keyword: this.handle} : {type: 'all', keyword: ''}; + + this.filter_grants(me); + + this.search = me.keyword; + console.log('searchkey', this.search); + }, filterLink: function(params) { + return this.filter_grants(params); }, searchKeyword: function() { @@ -122,6 +79,7 @@ Vue.component('grant-sidebar', { } this.timeout = setTimeout(() => { + console.log('searchkey', this.search); this.filter_grants({keyword: this.search}); }, 1000); }, @@ -148,6 +106,7 @@ if (document.getElementById('grants-showcase')) { delimiters: [ '[[', ']]' ], el: '#grants-showcase', data: { + activePage: document.activePage, grants: [], grant: {}, page: 1, @@ -181,9 +140,34 @@ if (document.getElementById('grants-showcase')) { activeCollection: null, grantsNumPages, grantsHasNext, - numGrants + numGrants, + regex_style: {} }, methods: { + toggleStyle: function(style) { + + if (!style) { + return; + } + + // let banner; + + // if (style.bg) { + // banner = `url("${style.bg }") center top / ${style.size || ''} ${style.color || ''} no-repeat`; + // } else { + // banner = `url("${ style.banner_image }") center no-repeat`; + // } + // $('#grant-hero-img').css('background', banner); + // if (style.background_image) { + // $('#grant-background-image-mount-point').css('background-image', style.background_image); + // } + + if (style.inline_css) { + $('.page-styles').last().text(style.inline_css); + } else { + $('.page-styles').last().text(''); + } + }, toggleActiveCLRs() { this.show_active_clrs = !this.show_active_clrs; window.localStorage.setItem('show_active_clrs', this.show_active_clrs); @@ -227,7 +211,7 @@ if (document.getElementById('grants-showcase')) { window.history.pushState('', '', `${uri}?type=${this.current_type}&${q || ''}`); } } else { - let uri = '/grants/'; + let uri = '/grants/explorer/'; if (this.current_type === 'all') { window.history.pushState('', '', `${uri}?${q || ''}`); @@ -290,6 +274,10 @@ if (document.getElementById('grants-showcase')) { if (event) { event.preventDefault(); } + if (filters.type == 'all' && location.href.indexOf('grants/explorer') == -1) { + location.href = '/grants/explorer'; + return false; + } let current_style; if (filters.type !== null && filters.type !== undefined) { @@ -328,17 +316,18 @@ if (document.getElementById('grants-showcase')) { if (filters.type === 'collections') { this.collectionsPage = 1; + } else { + this.clearSingleCollection(); } this.page = 1; this.setCurrentType(this.current_type); this.fetchGrants(this.page); - const regex_style = document.all_routing_policies && + this.regex_style = document.all_routing_policies && document.all_routing_policies.find(policy => { return new RegExp(policy.url_pattern).test(window.location.href); }); - - toggleStyle(regex_style || current_style); + this.toggleStyle(this.regex_style || current_style); }, clearSingleCollection: function() { @@ -426,20 +415,18 @@ if (document.getElementById('grants-showcase')) { if (getGrants.collections.length > 0) { this.activeCollection = getGrants.collections[0]; } + } else if (this.current_type === 'collections') { + getGrants.collections.forEach(function(item) { + vm.collections.push(item); + }); } else { - if (this.current_type === 'collections') { - getGrants.collections.forEach(function(item) { - vm.collections.push(item); - }); - } else { - vm.collections = getGrants.collections; - } - - vm.credentials = getGrants.credentials; - vm.grant_types = getGrants.grant_types; - vm.contributions = getGrants.contributions; + vm.collections = getGrants.collections; } + vm.credentials = getGrants.credentials; + vm.grant_types = getGrants.grant_types; + vm.contributions = getGrants.contributions; + vm.grantsNumPages = getGrants.num_pages; vm.grantsHasNext = getGrants.has_next; vm.numGrants = getGrants.count; @@ -514,7 +501,7 @@ if (document.getElementById('grants-showcase')) { this.cart_lock = false; }, removeCollection: async function({collection, grant, event}) { - const getGrants = await fetchData(`v1/api/collections/${collection.id}/grants/remove`, 'POST', { + const getGrants = await fetchData(`/grants/v1/api/collections/${collection.id}/grants/remove`, 'POST', { 'grant': grant.id }); @@ -522,9 +509,20 @@ if (document.getElementById('grants-showcase')) { } }, computed: { - isLandingPage() { - return (window.location.pathname == '/grants/'); + isGrantExplorer() { + return (this.activePage == 'grants_explorer'); + }, + isGrantCollectionExplorer() { + return this.current_type === 'collections'; + }, + isUserLogged() { + let vm = this; + + if (document.contxt.github_handle) { + return true; + } } + }, beforeMount() { window.addEventListener('scroll', () => { @@ -541,15 +539,6 @@ if (document.getElementById('grants-showcase')) { this.fetchGrants(this.page); - $('#sort_option2').select2({ - minimumResultsForSearch: Infinity, - templateSelection: function(data, container) { - // Add custom attributes to the