Project

General

Profile

1 61381 k.triantaf
import {Component, Input, Output, EventEmitter, ChangeDetectorRef} from '@angular/core';
2
import {Metrics} from '../../../utils/entities/metrics';
3
import {MetricsService} from '../../../services/metrics.service';
4
import {ErrorCodes} from '../../../utils/properties/errorCodes';
5
6
import {Subscription} from 'rxjs';
7
import {EnvProperties} from '../../../utils/properties/env-properties';
8
import {animate, state, style, transition, trigger} from "@angular/animations";
9
10
@Component({
11
  selector: 'metrics',
12
  styleUrls: ['metrics.component.css'],
13
  template: `
14
    <div *ngIf="metrics && (pageViews >0 || metrics.totalViews > 0|| metrics.totalDownloads >0)" class="metrics"
15
         click-outside-or-esc (clickOutside)="close($event)"
16
         id="metrics" targetId="metrics">
17
      <div class="m-badge clickable" (click)="toggle($event)">
18
        <img src="assets/common-assets/logo-small-usage-counts.png" loading="lazy">
19
        <div class="number">{{total | number}}</div>
20
      </div>
21
      <div class="widget" [@widget]="state.toString()">
22
        <div class="body">
23
          <div [@body]="state.toString()">
24
            <div *ngIf="entityType == 'projects'" class="uk-margin-bottom">
25
              <i class="uk-text-center">Project metrics
26
                are derived from aggregating individual research results metrics.
27
              </i>
28
            </div>
29
            <div class="uk-child-width-1-3@m uk-grid-small uk-grid-divider uk-grid-match" uk-grid>
30
              <div class="uk-text-center uk-first-column">
31
                <div class="number">{{metrics.totalDownloads | number}}</div>
32
                <div>Downloads</div>
33
              </div>
34
              <div class="uk-text-center">
35
                <div class="number">{{pageViews | number}}</div>
36
                <div>OpenAIRE views</div>
37
              </div>
38
              <div class="uk-text-center">
39
                <div class="number">{{metrics.totalViews | number}}</div>
40
                <div>Total views</div>
41
              </div>
42
            </div>
43
            <div *ngIf="(metrics.totalViews > 0 && viewsFrameUrl) || (metrics.totalDownloads > 0 && downloadsFrameUrl)"
44
                 [@charts]="state.toString()"
45
                 class="charts uk-visible-toggle" tabindex="-1" uk-slider>
46
              <ul class="uk-slider-items uk-child-width-1-1">
47
                <li *ngIf="metrics && metrics.infos.size > 0" class="uk-overflow-auto" style="height: 200px">
48
                  <table
49
                      class="uk-table uk-table-small uk-table-striped">
50
                    <thead>
51
                    <tr>
52
                      <th class="uk-text-center uk-text-bold">From</th>
53
                      <th class="uk-text-center  uk-text-bold">Views</th>
54
                      <th class="uk-text-center  uk-text-bold">Downloads</th>
55
                    </tr>
56
                    </thead>
57
                    <tbody>
58
                    <tr *ngFor="let key of getKeys(metrics.infos)">
59
                      <td class="uk-text-center">
60
                        <a href="{{metrics.infos.get(key).url}}">
61
                          {{metrics.infos.get(key).name}}
62
                        </a>
63
                      </td>
64
                      <td class="uk-text-center">
65
                        {{metrics.infos.get(key).numOfViews | number}}
66
                       <!-- <span *ngIf="metrics.infos.get(key).numOfViews > 0 && metrics.infos.get(key).openaireViews > 0">
67
                        ( {{metrics.infos.get(key).openaireViews | number}} from OpenAIRE )
68
                      </span>-->
69
                      </td>
70
                      <td class="uk-text-center">
71
                        {{metrics.infos.get(key).numOfDownloads | number}}
72
                        <!--<span *ngIf="metrics.infos.get(key).numOfDownloads > 0 && metrics.infos.get(key).openaireDownloads > 0">
73
                        ( {{metrics.infos.get(key).openaireDownloads | number}} from OpenAIRE )
74
                      </span>-->
75
                      </td>
76
                    </tr>
77
                    </tbody>
78
                  </table>
79
                </li>
80
<!--                remove check for datasources when with the new charts -->
81
                <li  *ngIf="entityType == 'datasources'" #element>
82
                  <i-frame *ngIf="metricsClicked && metrics.totalViews > 0 && viewsFrameUrl"
83
                           [height]="200"
84
                           [url]=viewsFrameUrl>
85
                  </i-frame>
86
                </li>
87
                <li *ngIf="entityType == 'datasources'" #element>
88
                  <i-frame *ngIf="metricsClicked && metrics.totalDownloads > 0 && downloadsFrameUrl"
89
                           [height]="200"
90
                           [url]=downloadsFrameUrl>
91
                  </i-frame>
92
                </li>
93
              </ul>
94
              <div class="uk-text-right uk-margin-small-top">
95
                <a href="#" uk-slidenav-previous uk-slider-item="previous"></a>
96
                <a href="#" class="space" uk-slidenav-next uk-slider-item="next"></a>
97
              </div>
98
            </div>
99
          </div>
100
        </div>
101
        <div class="footer uk-flex uk-flex-middle" [@footer]="state.toString()">
102
          <span>Powered by</span>
103
          <a href="https://usagecounts.openaire.eu" target="_blank">
104
            <img width="120" src="assets/common-assets/logo-large-usage-counts.png" loading="lazy">
105
          </a>
106
        </div>
107
      </div>
108
    </div>
109
  `,
110
  animations: [
111
    trigger('widget', [
112
      state('-1', style({
113
        width: '150px',
114
        opacity: 0,
115
        height: '60px',
116
      })),
117
      state('0', style({
118
        width: '150px',
119
        opacity: 0,
120
        height: '60px',
121
        "margin-top": '-25px'
122
      })),
123
      state('1', style({
124
        width: '150px',
125
        opacity: 1,
126
        height: '60px',
127
      })),
128
      state('2', style({
129
        width: '350px',
130
        height: 'auto',
131
      })),
132
      state('3', style({
133
        width: '350px',
134
        height: 'auto',
135
      })),
136
      state('4', style({
137
        width: '350px',
138
        height: 'auto',
139
      })),
140
      transition('0 => 1', [
141
        animate('300ms ease-out')
142
      ]),
143
      transition('1 => 2', [
144
        animate('400ms cubic-bezier(.18,.89,.56,1)')
145
      ])
146
    ]),
147
    trigger('body', [
148
      state('2', style({
149
        opacity: 1,
150
        height: 'auto',
151
      })),
152
      state('3', style({
153
        opacity: 1,
154
        height: 'auto'
155
      })),
156
      state('4', style({
157
        opacity: 1,
158
        height: 'auto'
159
      })),
160
      transition('* => 2', [
161
        animate('400ms cubic-bezier(.18,.89,.56,1)')
162
      ])
163
    ]),
164
    trigger('charts', [
165
      state('3', style({
166
        opacity: 1
167
      })),
168
      state('4', style({
169
        opacity: 1
170
      })),
171
      transition('* => 3', [
172
        animate('800ms ease-out')
173
      ])
174
    ]),
175
    trigger('footer', [
176
      state('4', style({
177
        transform: 'translateY(0)'
178
      })),
179
      transition('3 => 4', [
180
        animate('800ms ease-out')
181
      ])
182
    ])
183
  ]
184
})
185
186
export class MetricsComponent {
187
  @Output() metricsResults = new EventEmitter();
188
  @Input() id: string;
189
  @Input() entityType: string;
190
  @Input() entity: string;
191
  //@Input() name: string = "";
192
  @Input() pageViews: number = 0;
193
  @Input() properties: EnvProperties;
194
  @Input() shortView: boolean = false;
195
  @Input() open = false;
196
  @Input() viewsFrameUrl: string;
197
  @Input() downloadsFrameUrl: string;
198
199
  public metrics: Metrics;
200
  public errorCodes: ErrorCodes;
201
  private sub: Subscription;
202
  private timeouts: any[] = [];
203
204
  public metricsClicked: boolean = false;
205
206
  public status: number;
207
  public state: number = -1;
208
209
  constructor(private metricsService: MetricsService, private cdr: ChangeDetectorRef) {
210
  }
211
212
  ngOnInit() {
213
    this.errorCodes = new ErrorCodes();
214
    if (typeof document !== 'undefined') {
215
      this.status = this.errorCodes.LOADING;
216
      this.getMetrics();
217
    }
218
  }
219
220
  ngOnDestroy() {
221
    if(this.sub) {
222
      this.sub.unsubscribe();
223
    }
224
  }
225
226
  public get total(): number {
227
    return +this.pageViews + +this.metrics.totalViews + +this.metrics.totalDownloads;
228
  }
229
230
  private getMetrics() {
231
    this.sub = this.metricsService.getMetrics(this.id, this.entityType, this.properties).subscribe(
232
      data => {
233
        this.metrics = data;
234
        this.cdr.detectChanges();
235
        this.status = this.errorCodes.DONE;
236
        this.metricsResults.emit({
237
          totalViews: this.metrics.totalViews,
238
          totalDownloads: this.metrics.totalDownloads,
239
          pageViews: this.metrics.pageViews
240
        });
241
      },
242
      err => {
243
        if (err.status == '404') {
244
          this.status = this.errorCodes.NOT_FOUND;
245
        } else if (err.status == '500') {
246
          this.status = this.errorCodes.ERROR;
247
        } else {
248
          this.status = this.errorCodes.NOT_AVAILABLE;
249
        }
250
        this.metricsResults.emit({
251
          totalViews: 0,
252
          totalDownloads: 0
253
        });
254
      }
255
    );
256
  }
257
258
  public close(event) {
259
    if(event.value && this.state !== -1) {
260
      this.timeouts.forEach(timeout => {
261
        clearTimeout(timeout);
262
      });
263
      this.state = -1;
264
      this.timeouts = [];
265
    }
266
  }
267
268
269
  public toggle(event) {
270
    this.metricsClicked = true;
271
272
    event.stopPropagation();
273
    if(this.state !== -1) {
274
      this.timeouts.forEach(timeout => {
275
        clearTimeout(timeout);
276
      });
277
      this.state = -1;
278
      this.timeouts = [];
279
    } else {
280
      this.state++;
281
      this.timeouts.push(setTimeout(() => {
282
        this.state++;
283
        this.timeouts.push(setTimeout(() => {
284
          this.state++;
285
          this.timeouts.push(setTimeout(() => {
286
            this.state++;
287
            this.timeouts.push(setTimeout(() => {
288
              this.state++;
289
            }, 400));
290
          }, 800));
291
        }, 300));
292
      }, 100));
293
    }
294
    this.cdr.detectChanges();
295
  }
296
297
  public getKeys(map) {
298
    return Array.from(map.keys());
299
  }
300
}