Project

General

Profile

1
import {Component, Input, Output, EventEmitter} 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/metrics-icon.svg">
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 uk-grid">
47
                <li>
48
                  <i-frame *ngIf="metrics.totalViews > 0 && viewsFrameUrl"
49
                           [width]="325" [height]="200"
50
                           [url]=viewsFrameUrl>
51
                  </i-frame>
52
                </li>
53
                <li>
54
                  <i-frame *ngIf="metrics.totalDownloads > 0 && downloadsFrameUrl"
55
                           [width]="325" [height]="200"
56
                           [url]=downloadsFrameUrl>
57
                  </i-frame>
58
                </li>
59
              </ul>
60
              <div class="uk-text-right">
61
                <a href="#" uk-slidenav-previous uk-slider-item="previous"></a>
62
                <a href="#" class="space" uk-slidenav-next uk-slider-item="next"></a>
63
              </div>
64
            </div>
65
          </div>
66
        </div>
67
        <div class="footer uk-flex uk-flex-middle" [@footer]="state.toString()">
68
          <span>Powered by</span>
69
          <img width="120" src="assets/common-assets/openaire-metrics.png">
70
        </div>
71
      </div>
72
    </div>
73
  `,
74
  animations: [
75
    trigger('widget', [
76
      state('-1', style({
77
        width: '150px',
78
        opacity: 0,
79
        height: '60px',
80
      })),
81
      state('0', style({
82
        width: '150px',
83
        opacity: 0,
84
        height: '60px',
85
        "margin-top": '-25px'
86
      })),
87
      state('1', style({
88
        width: '150px',
89
        opacity: 1,
90
        height: '60px',
91
      })),
92
      state('2', style({
93
        width: '350px',
94
        height: 'auto',
95
      })),
96
      state('3', style({
97
        width: '350px',
98
        height: 'auto',
99
      })),
100
      state('4', style({
101
        width: '350px',
102
        height: 'auto',
103
      })),
104
      transition('0 => 1', [
105
        animate('300ms ease-out')
106
      ]),
107
      transition('1 => 2', [
108
        animate('400ms cubic-bezier(.18,.89,.56,1)')
109
      ])
110
    ]),
111
    trigger('body', [
112
      state('2', style({
113
        opacity: 1,
114
        height: 'auto',
115
      })),
116
      state('3', style({
117
        opacity: 1,
118
        height: 'auto'
119
      })),
120
      state('4', style({
121
        opacity: 1,
122
        height: 'auto'
123
      })),
124
      transition('* => 2', [
125
        animate('400ms cubic-bezier(.18,.89,.56,1)')
126
      ])
127
    ]),
128
    trigger('charts', [
129
      state('3', style({
130
        opacity: 1
131
      })),
132
      state('4', style({
133
        opacity: 1
134
      })),
135
      transition('* => 3', [
136
        animate('800ms ease-out')
137
      ])
138
    ]),
139
    trigger('footer', [
140
      state('4', style({
141
        transform: 'translateY(0)'
142
      })),
143
      transition('3 => 4', [
144
        animate('800ms ease-out')
145
      ])
146
    ])
147
  ]
148
})
149

    
150
export class MetricsComponent {
151
  @Output() metricsResults = new EventEmitter();
152
  @Input() id: string;
153
  @Input() entityType: string;
154
  @Input() entity: string;
155
  //@Input() name: string = "";
156
  @Input() pageViews: number = 0;
157
  @Input() properties: EnvProperties;
158
  @Input() shortView: boolean = false;
159
  @Input() open = false;
160
  @Input() viewsFrameUrl: string;
161
  @Input() downloadsFrameUrl: string;
162
  
163
  public metrics: Metrics;
164
  public errorCodes: ErrorCodes;
165
  private sub: Subscription;
166
  private timeouts: any[] = [];
167
  
168
  public status: number;
169
  public state: number = -1;
170
  
171
  constructor(private _metricsService: MetricsService) {
172
  }
173
  
174
  ngOnInit() {
175
    this.errorCodes = new ErrorCodes();
176
    this.status = this.errorCodes.LOADING;
177
    this.getMetrics();
178
  }
179
  
180
  ngOnDestroy() {
181
    this.sub.unsubscribe();
182
  }
183
  
184
  public get total(): number {
185
    return +this.pageViews + +this.metrics.totalViews + +this.metrics.totalDownloads;
186
  }
187
  
188
  private getMetrics() {
189
    this.sub = this._metricsService.getMetrics(this.id, this.entityType, this.properties).subscribe(
190
      data => {
191
        this.metrics = data;
192
        this.status = this.errorCodes.DONE;
193
        this.metricsResults.emit({
194
          totalViews: this.metrics.totalViews,
195
          totalDownloads: this.metrics.totalDownloads,
196
          pageViews: this.metrics.pageViews
197
        });
198
      },
199
      err => {
200
        console.log(err);
201
        if (err.status == '404') {
202
          this.status = this.errorCodes.NOT_FOUND;
203
        } else if (err.status == '500') {
204
          this.status = this.errorCodes.ERROR;
205
        } else {
206
          this.status = this.errorCodes.NOT_AVAILABLE;
207
        }
208
        this.metricsResults.emit({
209
          totalViews: 0,
210
          totalDownloads: 0
211
        });
212
      }
213
    );
214
  }
215
  
216
  public close(event) {
217
    if(event.value && this.state !== -1) {
218
      this.timeouts.forEach(timeout => {
219
        clearTimeout(timeout);
220
      });
221
      this.state = -1;
222
      this.timeouts = [];
223
    }
224
  }
225
  
226
  
227
  public toggle(event) {
228
    event.stopPropagation();
229
    if(this.state !== -1) {
230
      this.timeouts.forEach(timeout => {
231
        clearTimeout(timeout);
232
      });
233
      this.state = -1;
234
      this.timeouts = [];
235
    } else {
236
      this.state++;
237
      this.timeouts.push(setTimeout(() => {
238
        this.state++;
239
        this.timeouts.push(setTimeout(() => {
240
          this.state++;
241
          this.timeouts.push(setTimeout(() => {
242
            this.state++;
243
            this.timeouts.push(setTimeout(() => {
244
              this.state++;
245
            }, 400));
246
          }, 800));
247
        }, 300));
248
      }, 100));
249
    }
250
  }
251
  
252
  public getKeys(map) {
253
    return Array.from(map.keys());
254
  }
255
}
(2-2/3)