Skip to content
Snippets Groups Projects
Suggestions.vue 7.93 KiB
Newer Older
<template>
  <div>
    <ul class="collection with-header">
      <li class="collection-header">
Eliot Berriot's avatar
Eliot Berriot committed
        <router-link to="/connect" class="secondary-content">Add another account</router-link>
        <h5>Connected accounts</h5>
      <li class="collection-item avatar" v-for="account in accounts" :key="account.fullId">
        <img v-if="account._source.getAvatar(account)" :src="account._source.getAvatar(account)" alt="" class="circle">
        <span class="title">{{ account._source.getDisplayName(account) }}</span>
        <p>{{ account._source.label }}</p>
        <div v-if="isLoadingSources && results[account.id] && results[account.id].results.isLoading">
Eliot Berriot's avatar
Eliot Berriot committed
          <div class="progress">
            <div v-if="results[account.id].results.progress === 'indeterminate'" :class="indeterminate"></div>
            <div v-else class="determinate" :style="{width: `${results[account.id].results.progress}%`}"></div>
          </div>
          {{ results[account.id].results.status }}
        </div>
        <a @click="fetch(account.id)" class="secondary-content"><i class="material-icons">refresh</i></a>
    <h2>
      Suggestions
      <button
        @click="fetch()"
        :class="['waves-effect', 'waves-light', {disabled: isLoading}, 'btn-small']" :disabled="isLoading">
        <i class="material-icons left">refresh</i>Fetch data
      </button>
    </h2>
    <div v-if="isLoading" class="progress">
      <div class="indeterminate"></div>
    </div>
    <ul class="collection">
      <li class="collection-item avatar" v-for="suggestion in filteredSuggestions" :key="suggestion.fullId">
        <img v-if="suggestion.avatar" :src="suggestion.avatar" alt="" class="circle">
        <a target="_blank" rel="noopener noreferrer" :href="suggestion.url" class="title">{{ suggestion.name }}</a>
        <p>Score: {{ suggestion.weight }}</p>
Eliot Berriot's avatar
Eliot Berriot committed
        <a v-if="retributeProfiles[suggestion.fullId] === undefined" @click="lookup(suggestion.fullId)" class="secondary-content"><i class="material-icons">search</i></a>
        <div v-else-if="retributeProfiles[suggestion.fullId]">
          <h6>Donation platforms</h6>
          <!-- {{ retributeProfiles[suggestion.fullId] }} -->
          <template v-for="mean in retributeProfiles[suggestion.fullId].means">
            <a
              :href="mean.url"
              :key="mean.provider + mean.id"
Eliot Berriot's avatar
Eliot Berriot committed
              target="_blank"
              rel="noopener noreferrer"
              :class="['waves-effect', 'waves-light', 'btn-small']">
              <span :title="mean.summary">{{ mean.provider }}</span>
            </a>

          </template>
        </div>
        <div v-else>No retribute information found for this account</div>
      </li>
    </ul>
  </div>

</template>

<script>
import sources from '@/sources'
import config from '@/config'
import orderBy from 'lodash/orderBy'
import pull from 'lodash/pull'
Eliot Berriot's avatar
Eliot Berriot committed
import chunk from 'lodash/chunk'
import axios from 'axios'
export default {
  data () {
    return {
      isLoadingSources: false,
      isLoadingRetribute: false,
      results: {},
Eliot Berriot's avatar
Eliot Berriot committed
      aggregatedSuggestions: this.$store.state.cache.aggregatedSuggestions || {},
      retributeProfiles: this.$store.state.cache.retributeProfiles || {},
      loadingRetributeProfiles: [],
      filters: {
        retributeOnly: true
      }
    }
  },
  computed: {
    accounts () {
      return this.$store.getters.sortedAccounts.map((a) => {
        a._source = sources.sources[a.source]
        return a
      })
    allSuggestions () {
      return Object.values(this.aggregatedSuggestions)
    },
    filteredSuggestions () {
      let self = this
      let suggestions = this.allSuggestions.filter((s) => {
        let f = true
        if (self.filters.retributeOnly != null) {
          f = !!this.retributeProfiles[s.fullId] === self.filters.retributeOnly
        }
        return f
      })
      return orderBy(suggestions, ['weight', 'id'], ['desc', 'asc'])
    missingRetributeProfiles () {
      return this.allSuggestions.filter((s) => {
        return this.retributeProfiles[s.fullId] === undefined
      })
    },
    isLoading () {
      return this.isLoadingSources || this.isLoadingRetribute
    clearCache () {
      this.isLoadingSources = false
      this.isLoadingRetribute = false
      this.results = {}
      this.aggregatedSuggestions = {}
      this.retributeProfiles = {}
      this.loadingRetributeProfiles = {}
    aggregateSuggestions (results) {
      const aggregated = {}
      Object.keys(results).forEach((account) => {
        let r = results[account]
        if (!r.results || !r.results.accounts) {

        } else {
          Object.keys(r.results.accounts).forEach((key) => {
            if (aggregated[key]) {
              aggregated[key].weight += r.results.accounts[key].weight
              aggregated[key].accounts.push(account)
            } else {
              aggregated[key] = {...r.results.accounts[key], accounts: [account], fullId: key}
            }
          })
        }
      })
      return aggregated
    },
Eliot Berriot's avatar
Eliot Berriot committed
    async fetch (id) {
      let accounts
      if (id) {
        accounts = this.accounts.filter((a) => {
          return a.id == id
        })
      } else {
        accounts = this.accounts
        this.retributeProfiles = {}
        this.loadingRetributeProfiles = []
      this.isLoadingSources = true
Eliot Berriot's avatar
Eliot Berriot committed
      accounts.forEach((a) => {
        let r = {isLoading: true, progress: 'indeterminate', status: ''}
        let promise = a._source.fetch({account: a, store: this.$store, results: r, vue: this})
        this.$set(this.results, a.id, {account: a, promise, results: r})
      })
      const keys = Object.keys(this.results)
      for(let i = 0; i < keys.length; i++){
        await this.results[keys[i]].promise
      }
      this.isLoadingSources = false
Eliot Berriot's avatar
Eliot Berriot committed
    },
    async lookupAll () {
      let self = this
      const toLoad = this.missingRetributeProfiles.filter((p) => {
        return self.loadingRetributeProfiles.indexOf(p.fullId) === -1
      })
      if (toLoad.length === 0) {
        return
      }
      this.isLoadingRetribute = true
      const chunkSize = 10
      // lock
      toLoad.forEach((p) => {
        self.loadingRetributeProfiles.push(p.fullId)
      })
      const chunks = chunk(toLoad, chunkSize)
Eliot Berriot's avatar
Eliot Berriot committed
      for (let i = 0; i < chunks.length; i++){
        let chunk = chunks[i]
        let ids = chunk.map((s) => {
          return s.fullId
        })
        await this.lookups(ids)
      }
      this.isLoadingRetribute = false
Eliot Berriot's avatar
Eliot Berriot committed

    },
    async lookups(ids) {
      let self = this
      ids.forEach((id) => {
        self.loadingRetributeProfiles.push(id)
      })
      const client = axios.create()
      let url = config.RetributeAPIUrl + `v1/search/`
      let response
      try {
        response = await client.post(url, {lookups: ids})
      } catch {
        ids.forEach((id) => {
          self.$set(self.retributeProfiles, id, null)
        })
        return
Eliot Berriot's avatar
Eliot Berriot committed
      }
      ids.forEach((id) => {
        self.$set(self.retributeProfiles, id, response.data[id])
      })
Eliot Berriot's avatar
Eliot Berriot committed

    },
    async lookup (id) {
      this.loadingRetributeProfiles.push(id)
      const client = axios.create()
      let url = config.RetributeAPIUrl + `v1/search/${id}`
Eliot Berriot's avatar
Eliot Berriot committed
      try {
        const response = await client.get(url)
        this.$set(this.retributeProfiles, id, response.data)
      } catch {
        this.$set(this.retributeProfiles, id, null)
      }
      pull(this.loadingRetributeProfiles, [id])
  },
  watch: {
    async missingRetributeProfiles (v) {
      await this.lookupAll()
    },
    results: {
      handler (v) {
        this.aggregatedSuggestions = this.aggregateSuggestions(v)
Eliot Berriot's avatar
Eliot Berriot committed
        this.$store.commit('setRecursiveState', {key: 'cache.aggregatedSuggestions', value: this.aggregatedSuggestions})
      },
      deep: true,
Eliot Berriot's avatar
Eliot Berriot committed
    },
    retributeProfiles: {
      handler (v) {
        this.$store.commit('setRecursiveState', {key: 'cache.retributeProfiles', value: this.retributeProfiles})
      },
      deep: true