list.vue 3.78 KB
Newer Older
1
<script>
2 3 4 5
import Icon from '~/vue_shared/components/icon.vue';
import bp from '../../../breakpoints';
import ModalStore from '../../stores/modal_store';
import IssueCardInner from '../issue_card_inner.vue';
6

7 8 9 10 11 12 13 14 15
export default {
  components: {
    IssueCardInner,
    Icon,
  },
  props: {
    issueLinkBase: {
      type: String,
      required: true,
16
    },
17 18 19
    rootPath: {
      type: String,
      required: true,
20
    },
21 22 23
    emptyStateSvg: {
      type: String,
      required: true,
24
    },
25 26 27 28 29 30 31 32 33
  },
  data() {
    return ModalStore.store;
  },
  computed: {
    loopIssues() {
      if (this.activeTab === 'all') {
        return this.issues;
      }
34

35 36 37 38 39 40
      return this.selectedIssues;
    },
    groupedIssues() {
      const groups = [];
      this.loopIssues.forEach((issue, i) => {
        const index = i % this.columns;
41

42 43 44
        if (!groups[index]) {
          groups.push([]);
        }
45

46 47
        groups[index].push(issue);
      });
48

49
      return groups;
50
    },
51 52 53 54 55 56
  },
  watch: {
    activeTab() {
      if (this.activeTab === 'all') {
        ModalStore.purgeUnselectedIssues();
      }
57
    },
58 59 60 61 62
  },
  mounted() {
    this.scrollHandlerWrapper = this.scrollHandler.bind(this);
    this.setColumnCountWrapper = this.setColumnCount.bind(this);
    this.setColumnCount();
63

64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
    this.$refs.list.addEventListener('scroll', this.scrollHandlerWrapper);
    window.addEventListener('resize', this.setColumnCountWrapper);
  },
  beforeDestroy() {
    this.$refs.list.removeEventListener('scroll', this.scrollHandlerWrapper);
    window.removeEventListener('resize', this.setColumnCountWrapper);
  },
  methods: {
    scrollHandler() {
      const currentPage = Math.floor(this.issues.length / this.perPage);

      if (
        this.scrollTop() > this.scrollHeight() - 100 &&
        !this.loadingNewPage &&
        currentPage === this.page
      ) {
        this.loadingNewPage = true;
        this.page += 1;
      }
83
    },
84 85 86 87
    toggleIssue(e, issue) {
      if (e.target.tagName !== 'A') {
        ModalStore.toggleIssue(issue);
      }
88
    },
89 90 91 92 93 94 95 96 97 98 99
    listHeight() {
      return this.$refs.list.getBoundingClientRect().height;
    },
    scrollHeight() {
      return this.$refs.list.scrollHeight;
    },
    scrollTop() {
      return this.$refs.list.scrollTop + this.listHeight();
    },
    showIssue(issue) {
      if (this.activeTab === 'all') return true;
100

101
      const index = ModalStore.selectedIssueIndex(issue);
102

103 104 105 106
      return index !== -1;
    },
    setColumnCount() {
      const breakpoint = bp.getBreakpointSize();
107

108 109 110 111 112 113 114
      if (breakpoint === 'lg' || breakpoint === 'md') {
        this.columns = 3;
      } else if (breakpoint === 'sm') {
        this.columns = 2;
      } else {
        this.columns = 1;
      }
115
    },
116 117
  },
};
118 119
</script>
<template>
Mike Greiling's avatar
Mike Greiling committed
120
  <section ref="list" class="add-issues-list add-issues-list-columns">
121 122
    <div
      v-if="issuesCount > 0 && issues.length === 0"
Mike Greiling's avatar
Mike Greiling committed
123 124 125 126
      class="empty-state add-issues-empty-state-filter text-center"
    >
      <div class="svg-content"><img :src="emptyStateSvg" /></div>
      <div class="text-content"><h4>There are no issues to show.</h4></div>
127
    </div>
Mike Greiling's avatar
Mike Greiling committed
128 129
    <div v-for="(group, index) in groupedIssues" :key="index" class="add-issues-list-column">
      <div v-for="issue in group" v-if="showIssue(issue)" :key="issue.id" class="board-card-parent">
130 131 132
        <div
          :class="{ 'is-active': issue.selected }"
          class="board-card"
Mike Greiling's avatar
Mike Greiling committed
133 134 135
          @click="toggleIssue($event, issue);"
        >
          <issue-card-inner :issue="issue" :issue-link-base="issueLinkBase" :root-path="rootPath" />
136
          <icon
137 138
            v-if="issue.selected"
            :aria-label="'Issue #' + issue.id + ' selected'"
139
            name="mobile-issue-close"
140
            aria-checked="true"
141 142
            class="issue-card-selected text-center"
          />
143 144 145 146 147
        </div>
      </div>
    </div>
  </section>
</template>