Skip to content
Commits on Source (20)
......@@ -66,12 +66,13 @@ export class FeaturedContentComponent implements OnInit {
update() {
this.clear();
const {component, injector} = this.resolve();
if (!this.dynamicHost) {
console.log('tried to load a boost but no dynamicHost found', this.entity);
return;
}
const {component, injector} = this.resolve();
if (component) {
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(component);
......
import { Injectable } from "@angular/core";
import { filter, first, map, switchMap } from 'rxjs/operators';
import { filter, first, map, switchMap, mergeMap, skip, take } from 'rxjs/operators';
import { FeedsService } from "../../services/feeds.service";
@Injectable()
......@@ -11,21 +11,27 @@ export class FeaturedContentService {
protected feedsService: FeedsService,
) {
this.feedsService
.setLimit(50)
.setLimit(12)
.setOffset(0)
.setEndpoint('api/v2/boost/feed')
.fetch();
}
async fetch() {
if (this.offset >= this.feedsService.rawFeed.getValue().length) {
this.offset = -1;
}
return await this.feedsService.feed
.pipe(
filter(feed => feed.length > 0),
first(),
map(feed => feed[this.offset++]),
mergeMap(feed => feed),
skip(this.offset++),
take(1),
switchMap(async entity => {
if (!entity)
if (!entity) {
return false;
}
return await entity.pipe(first()).toPromise();
}),
).toPromise();
......
......@@ -38,6 +38,11 @@
<li class="mdl-menu__item" *ngIf="!asyncBlockInProgress && !asyncBlock" (click)="block()" i18n="@@COMMON__POST_MENU__BLOCK">Block user</li>
<li class="mdl-menu__item" *ngIf="!asyncBlockInProgress && asyncBlock" (click)="unBlock()" i18n="@@COMMON__POST_MENU__UNBLOCK">Unblock user</li>
</ng-container>
<!-- ALLOW COMMENTS -->
<ng-container *ngIf="featuresService.has('allow-comments-toggle') && options.indexOf('allow-comments') !== -1 && entity.ownerObj.guid == session.getLoggedInUser().guid ">
<li class="mdl-menu__item" *ngIf="!entity.allow_comments" (click)="allowComments(true)" i18n="@@COMMON__POST_MENU__ALLOW_COMMENTS">Allow Comments</li>
<li class="mdl-menu__item" *ngIf="entity.allow_comments" (click)="allowComments(false)" i18n="@@COMMON__POST_MENU__DISABLE_COMMENTS">Disable Comments</li>
</ng-container>
<!-- ADMIN EDIT FLAGS -->
<ng-container *ngIf="options.indexOf('set-explicit') !== -1 && session.isAdmin()">
<li class="mdl-menu__item m-postMenu__item--nsfw">
......
......@@ -15,7 +15,11 @@ import { sessionMock } from '../../../../tests/session-mock.spec';
import { FormsModule } from '@angular/forms';
import { RouterTestingModule } from '@angular/router/testing';
import { BlockListService } from '../../services/block-list.service';
import { ActivityService } from '../../services/activity.service';
import { FeaturesService } from '../../../services/features.service';
import { activityServiceMock } from '../../../../tests/activity-service-mock.spec';
import { storageMock } from '../../../../tests/storage-mock.spec';
import { featuresServiceMock } from '../../../../tests/features-service-mock.spec';
/* tslint:disable */
/* Mock section */
......@@ -95,6 +99,8 @@ describe('PostMenuComponent', () => {
{ provide: Client, useValue: clientMock },
{ provide: Session, useValue: sessionMock },
{ provide: OverlayModalService, useValue: overlayModalServiceMock },
{ provide: ActivityService, useValue: activityServiceMock },
{ provide: FeaturesService, useValue: featuresServiceMock },
{ provide: Storage, useValue: storageMock },
{ provide: BlockListService, useFactory: () => {
return BlockListService._(clientMock, sessionMock, storageMock);
......@@ -110,6 +116,7 @@ describe('PostMenuComponent', () => {
// synchronous beforeEach
beforeEach(() => {
featuresServiceMock.mock('allow-comments-toggle', true);
fixture = TestBed.createComponent(PostMenuComponent);
comp = fixture.componentInstance;
......@@ -117,8 +124,9 @@ describe('PostMenuComponent', () => {
comp.entity = {};
// comp.opened = true;
comp.entity.ownerObj = { guid: '1' };
comp.cardMenuHandler();
comp.cardMenuHandler();
fixture.detectChanges();
});
it('should have dropdown', () => {
......@@ -140,4 +148,19 @@ describe('PostMenuComponent', () => {
fixture.detectChanges();
expect(clientMock.delete.calls.mostRecent().args[0]).toEqual('api/v1/block/1');
});
it('should allow comments', () => {
spyOn(comp.optionSelected, 'emit');
comp.allowComments(true);
expect(activityServiceMock.toggleAllowComments).toHaveBeenCalledWith(comp.entity, true);
expect(comp.entity.allow_comments).toEqual(true);
});
it('should disable comments', () => {
spyOn(comp.optionSelected, 'emit');
comp.allowComments(false);
expect(activityServiceMock.toggleAllowComments).toHaveBeenCalledWith(comp.entity, false);
expect(comp.entity.allow_comments).toEqual(false);
});
});
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output } from '@angular/core';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output, OnInit } from '@angular/core';
import { Session } from '../../../services/session';
import { OverlayModalService } from '../../../services/ux/overlay-modal';
import { Client } from '../../../services/api/client';
import { ReportCreatorComponent } from '../../../modules/report/creator/creator.component';
import { MindsUser } from '../../../interfaces/entities';
import { SignupModalService } from '../../../modules/modals/signup/service';
import { BlockListService } from "../../services/block-list.service";
import { BlockListService } from '../../services/block-list.service';
import { ActivityService } from '../../../common/services/activity.service';
import { FeaturesService } from '../../../services/features.service';
type Option =
'edit'
......@@ -26,7 +27,8 @@ type Option =
| 'subscribe'
| 'unsubscribe'
| 'rating'
| 'block';
| 'block'
| 'allow-comments';
@Component({
moduleId: module.id,
......@@ -35,7 +37,7 @@ type Option =
changeDetection: ChangeDetectionStrategy.OnPush
})
export class PostMenuComponent {
export class PostMenuComponent implements OnInit {
@Input() entity: any;
@Input() options: Array<Option>;
@Output() optionSelected: EventEmitter<Option> = new EventEmitter<Option>();
......@@ -66,10 +68,13 @@ export class PostMenuComponent {
private overlayModal: OverlayModalService,
public signupModal: SignupModalService,
protected blockListService: BlockListService,
) {
protected activityService: ActivityService,
public featuresService: FeaturesService) {
this.initCategories();
}
ngOnInit() {}
initCategories() {
for (let category in window.Minds.categories) {
this.categories.push({
......@@ -329,4 +334,12 @@ export class PostMenuComponent {
this.entity.nsfw = nsfw;
}
async allowComments(areAllowed: boolean) {
this.entity.allow_comments = areAllowed;
const result = await this.activityService.toggleAllowComments(this.entity, areAllowed);
if (result !== areAllowed) {
this.entity.allow_comments = result;
}
}
}
import { EventEmitter, Injectable } from '@angular/core';
import { Client } from '../../services/api/client';
import { BehaviorSubject, Observable } from 'rxjs';
@Injectable()
export class ActivityService {
public allowComment$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
constructor(
private client: Client
) {}
public async toggleAllowComments(entity: any, areAllowed: boolean) {
const payload = {
allowed: areAllowed
};
const oldValue = entity['allow_comments'];
try {
await this.client.post(`api/v2/permissions/comments/${entity.guid}`, payload);
this.allowComment$.next(areAllowed);
return areAllowed;
} catch (ex) {
console.error('Error posting activity comment permissions', ex);
return oldValue;
}
}
}
......@@ -39,6 +39,8 @@ export class FeedsService {
limit: BehaviorSubject<number> = new BehaviorSubject(12);
offset: BehaviorSubject<number> = new BehaviorSubject(0);
pageSize: Observable<number>;
pagingToken: string = '';
canFetchMore: boolean = true;
endpoint: string = '';
params: any = { sync: 1 };
castToActivities: boolean = false;
......@@ -112,16 +114,26 @@ export class FeedsService {
}
fetch(): FeedsService {
this.inProgress.next(true);
if (!this.offset.getValue())
this.inProgress.next(true);
this.client.get(this.endpoint, {
...this.params,
...{
limit: 150, // Over 12 scrolls
as_activities: this.castToActivities ? 1 : 0,
from_timestamp: this.pagingToken,
}})
.then((response: any) => {
this.inProgress.next(false);
this.rawFeed.next(response.entities);
if (!this.offset.getValue())
this.inProgress.next(false);
if (response.entities.length) {
this.rawFeed.next(this.rawFeed.getValue().concat(response.entities));
this.pagingToken = response['load-next'];
} else {
this.canFetchMore = false;
}
})
.catch(err => {
});
......@@ -138,6 +150,7 @@ export class FeedsService {
clear(): FeedsService {
this.offset.next(0);
this.pagingToken = '';
this.rawFeed.next([]);
return this;
}
......
......@@ -89,8 +89,10 @@ export class UpdateMarkersService {
if (!opts.marker)
throw "marker must be set";
this.http.post('api/v2/notifications/markers/read', opts)
.subscribe(res => null, err => console.warn(err));
if (!opts.noReply) {
this.http.post('api/v2/notifications/markers/read', opts)
.subscribe(res => null, err => console.warn(err));
}
for (let i = 0; i < this.data.length; i++) {
if (this.data[i].entity_guid == opts.entity_guid) {
......@@ -127,15 +129,16 @@ export class UpdateMarkersService {
(marker) => {
marker = JSON.parse(marker);
let entity_guid = marker.entity_guid;
if (this.muted.indexOf(entity_guid) > -1)
return; //muted, so take no action
//this.entityGuids$[entity_guid].next(marker);
let found:boolean = false;
for(let i in this.data) {
if (this.data[i].entity_guid === entity_guid
&& this.data[i].marker === marker.marker) {
if (this.muted.indexOf(entity_guid) > -1) {
return;
}
let found = false;
for (let i in this.data) {
if (this.data[i].entity_guid === entity_guid &&
this.data[i].marker === marker.marker &&
this.data[i].user_guid === marker.user_guid) {
this.data[i].updated_timestamp = marker.updated_timestamp;
found = true;
}
......
......@@ -5,7 +5,8 @@ import { WireRewardsStruc } from '../modules/wire/interfaces/wire.interfaces';
export interface MindsActivityObject {
activity : Array<any>;
pinned : Array<any>;
pinned : Array<any>;
allow_comments: boolean;
}
export interface MindsBlogEntity {
......@@ -27,6 +28,7 @@ export interface MindsBlogEntity {
time_published?: number;
access_id?: number;
license?: string;
allow_comments: boolean;
}
export interface Message {
......
......@@ -47,6 +47,8 @@ import { RewardsChartComponent } from "./components/charts/rewards/rewards.compo
import { RewardsCardComponent } from "./components/cards/rewards/rewards.component";
import { ActiveUsersChartComponent } from "./components/charts/active-users/active-users.component";
import { Graph } from "./graph.component";
import { PageviewsCardComponent } from "./components/cards/pageviews/pageviews.component";
import { PageviewsChartComponent } from "./components/charts/pageviews/pageviews.component";
PlotlyModule.plotlyjs = PlotlyJS;
......@@ -130,6 +132,8 @@ const routes: Routes = [
UserSegmentsChartComponent,
UserSegmentsCardComponent,
EngagementCardComponent,
PageviewsChartComponent,
PageviewsCardComponent,
Graph,
],
providers: [],
......
......@@ -6,36 +6,36 @@
<ng-container *ngIf="card.selectedOption=='hourly'">
<div class="m-analytics__average">
<h6>AVG HAU (Unique)</h6>
<h6>AVG Hourly Unique Visits</h6>
<h5>{{hauUnique | number : '1.0-0'}}</h5>
</div>
<div class="m-analytics__average">
<h6>AVG HAU (Logged In)</h6>
<h6>AVG Hourly Active Users</h6>
<h5>{{hauLoggedIn | number : '1.0-0'}}</h5>
</div>
</ng-container>
<ng-container *ngIf="card.selectedOption=='daily'">
<div class="m-analytics__average">
<h6>AVG DAU (Unique)</h6>
<h6>AVG Daily Unique Visits</h6>
<h5>{{dauUnique | number : '1.0-0'}}</h5>
</div>
<div class="m-analytics__average">
<h6>AVG DAU (Logged In)</h6>
<h6>AVG Daily Active Users</h6>
<h5>{{dauLoggedIn | number : '1.0-0'}}</h5>
</div>
</ng-container>
<ng-container *ngIf="card.selectedOption=='monthly'">
<div class="m-analytics__average">
<h6>AVG MAU (Unique)</h6>
<h6>AVG Monthly Unique Vists</h6>
<h5>{{mauUnique | number : '1.0-0'}}</h5>
</div>
<div class="m-analytics__average">
<h6>AVG MAU (Logged In)</h6>
<h6>AVG Monthly Active Users</h6>
<h5>{{mauLoggedIn | number : '1.0-0'}}</h5>
</div>
......@@ -46,7 +46,14 @@
</ng-container>
</div>
<div class="m-analytics__averages">
<div class="m-analytics__average" *ngFor="let current of currents">
<h6>Current {{current.name}}</h6>
<h5>{{current.value | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analyticsCard__charts">
<m-analyticscharts__activeusers [timespan]="card.selectedOption"></m-analyticscharts__activeusers>
<m-analyticscharts__activeusers [timespan]="card.selectedOption" (loaded)="currents = $event"></m-analyticscharts__activeusers>
</div>
</m-analytics__card>
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, ViewChild } from '@angular/core';
import { Client } from "../../../../../services/api/client";
import { AnalyticsCardComponent } from "../card/card.component";
import { Subscription } from "rxjs";
@Component({
selector: 'm-analyticsactiveusers__card',
......@@ -7,6 +9,10 @@ import { Client } from "../../../../../services/api/client";
})
export class ActiveUsersCardComponent implements OnInit {
@ViewChild('card', { static: true }) card: AnalyticsCardComponent;
subscription: Subscription;
hauUnique: number = 0;
hauLoggedIn: number = 0;
mauUnique: number = 0;
......@@ -14,37 +20,47 @@ export class ActiveUsersCardComponent implements OnInit {
dauUnique: number = 0;
dauLoggedIn: number = 0;
total: number = 0;
currents: { name: string, value: number }[];
constructor(private client: Client) { }
constructor(private client: Client) {
}
ngOnInit() {
this.getAvgData();
this.subscription = this.card.selectedOptionChange.subscribe(() => {
this.getAvgData();
});
}
private async getAvgData() {
try {
let avgs: Array<any> = await Promise.all([
this.client.get('api/v2/analytics/avgpageviews', { key: 'mau_unique' }),
this.client.get('api/v2/analytics/avgpageviews', { key: 'mau_loggedin' }),
this.client.get('api/v2/analytics/avgpageviews', { key: 'dau_loggedin' }),
this.client.get('api/v2/analytics/avgpageviews', { key: 'dau_unique' }),
this.client.get('api/v2/analytics/avgpageviews', { key: 'hau_unique' }),
this.client.get('api/v2/analytics/avgpageviews', { key: 'hau_loggedin' }),
this.client.get('api/v2/analytics/activeusers', {
key: 'avg',
timespan: 'hourly',
}),
this.client.get('api/v2/analytics/activeusers', {
key: 'avg',
timespan: 'daily',
}),
this.client.get('api/v2/analytics/activeusers', {
key: 'avg',
timespan: 'monthly',
}),
this.client.get('api/v2/analytics/avgpageviews', { key: 'total_pageviews' })
]);
this.mauUnique = avgs[0].data;
this.mauLoggedIn = avgs[1].data;
this.dauLoggedIn = avgs[2].data;
this.dauUnique = avgs[3].data;
this.hauUnique = avgs[0].data.uniqueHAU;
this.hauLoggedIn = avgs[0].data.loggedInHAU;
this.hauUnique = avgs[4].data;
this.dauUnique = avgs[1].data.uniqueDAU;
this.dauLoggedIn = avgs[1].data.loggedInDAU;
this.hauLoggedIn = avgs[5].data;
this.mauUnique = avgs[2].data.uniqueMAU;
this.mauLoggedIn = avgs[2].data.loggedInMAU;
this.total = avgs[6].data;
this.total = avgs[3].data;
} catch (e) {
console.error(e);
}
......
......@@ -3,8 +3,27 @@
[options]="['hourly', 'daily', 'monthly']"
#posts>
<div class="m-analytics__averages">
<div class="m-analytics__average">
<h6>Avg Posts</h6>
<h5>{{avgPosts | number : '1.0-0'}}</h5>
</div>
<div class="m-analytics__average">
<h6>Avg Posting Users</h6>
<h5>{{avgPostingUsers | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analytics__averages">
<div class="m-analytics__average" *ngFor="let current of currentPosts">
<h6>Current {{current.name}}</h6>
<h5>{{current.value | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analyticsCard__charts">
<m-analyticscharts__posts [timespan]="posts.selectedOption"></m-analyticscharts__posts>
<m-analyticscharts__posts [timespan]="posts.selectedOption" (loaded)="currentPosts = $event"></m-analyticscharts__posts>
</div>
</m-analytics__card>
......@@ -13,8 +32,27 @@
[options]="['hourly', 'daily', 'monthly']"
#comments>
<div class="m-analyticsCard__charts">
<m-analyticscharts__comments [timespan]="comments.selectedOption"></m-analyticscharts__comments>
<div class="m-analytics__averages">
<div class="m-analytics__average">
<h6>Avg Comments</h6>
<h5>{{avgComments | number : '1.0-0'}}</h5>
</div>
<div class="m-analytics__average">
<h6>Avg Commenting Users</h6>
<h5>{{avgCommentingUsers | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analytics__averages">
<div class="m-analytics__average" *ngFor="let current of currentComments">
<h6>Current {{current.name}}</h6>
<h5>{{current.value | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analyticsCard__charts">
<m-analyticscharts__comments [timespan]="comments.selectedOption" (loaded)="currentComments = $event"></m-analyticscharts__comments>
</div>
</m-analytics__card>
......@@ -23,8 +61,27 @@
[options]="['hourly', 'daily', 'monthly']"
#votes>
<div class="m-analyticsCard__charts">
<m-analyticscharts__votes [timespan]="votes.selectedOption"></m-analyticscharts__votes>
<div class="m-analytics__averages">
<div class="m-analytics__average">
<h6>Avg Votes</h6>
<h5>{{avgVotes | number : '1.0-0'}}</h5>
</div>
<div class="m-analytics__average">
<h6>Avg Voting Users</h6>
<h5>{{avgVotingUsers | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analytics__averages">
<div class="m-analytics__average" *ngFor="let current of currentVotes">
<h6>Current {{current.name}}</h6>
<h5>{{current.value | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analyticsCard__charts">
<m-analyticscharts__votes [timespan]="votes.selectedOption" (loaded)="currentVotes = $event"></m-analyticscharts__votes>
</div>
</m-analytics__card>
......@@ -33,7 +90,26 @@
[options]="['hourly', 'daily', 'monthly']"
#reminds>
<div class="m-analyticsCard__charts">
<m-analyticscharts__reminds [timespan]="reminds.selectedOption"></m-analyticscharts__reminds>
<div class="m-analytics__averages">
<div class="m-analytics__average">
<h6>Avg Reminds</h6>
<h5>{{avgReminds | number : '1.0-0'}}</h5>
</div>
<div class="m-analytics__average">
<h6>Avg Reminding Users</h6>
<h5>{{avgRemindingUsers | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analytics__averages">
<div class="m-analytics__average" *ngFor="let current of currentReminds">
<h6>Current {{current.name}}</h6>
<h5>{{current.value | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analyticsCard__charts">
<m-analyticscharts__reminds [timespan]="reminds.selectedOption" (loaded)="currentReminds = $event"></m-analyticscharts__reminds>
</div>
</m-analytics__card>
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, ViewChild } from '@angular/core';
import { AnalyticsCardComponent } from "../card/card.component";
import { Client } from "../../../../../services/api/client";
@Component({
selector: 'm-analyticsengagement__card',
......@@ -6,9 +8,104 @@ import { Component, OnInit } from '@angular/core';
})
export class EngagementCardComponent implements OnInit {
constructor() {
@ViewChild('posts', { static: true }) posts: AnalyticsCardComponent;
@ViewChild('comments', { static: true }) comments: AnalyticsCardComponent;
@ViewChild('votes', { static: true }) votes: AnalyticsCardComponent;
@ViewChild('reminds', { static: true }) reminds: AnalyticsCardComponent;
avgPosts: number = 0;
avgPostingUsers: number = 0;
currentPosts: { name: string, value: number }[];
avgComments: number = 0;
avgCommentingUsers: number = 0;
currentComments: { name: string, value: number }[];
avgVotes: number = 0;
avgVotingUsers: number = 0;
currentVotes: { name: string, value: number }[];
avgReminds: number = 0;
avgRemindingUsers: number = 0;
currentReminds: { name: string, value: number }[];
constructor(private client: Client) {
}
ngOnInit() {
this.getAvgPosts();
this.getAvgComments();
this.getAvgVotes();
this.getAvgReminds();
this.posts.selectedOptionChange.subscribe(() => {
this.getAvgPosts();
});
this.comments.selectedOptionChange.subscribe(() => {
this.getAvgComments();
});
this.votes.selectedOptionChange.subscribe(() => {
this.getAvgVotes();
});
this.reminds.selectedOptionChange.subscribe(() => {
this.getAvgReminds();
});
}
private async getAvgPosts() {
try {
const response: any = await this.client.get('api/v2/analytics/posts', {
key: 'avg',
timespan: this.posts.selectedOption,
});
this.avgPosts = response.data.posts;
this.avgPostingUsers = response.data.postingUsers;
} catch (e) {
console.error(e);
}
}
private async getAvgComments() {
try {
const response: any = await this.client.get('api/v2/analytics/comments', {
key: 'avg',
timespan: this.comments.selectedOption,
});
this.avgComments = response.data.comments;
this.avgCommentingUsers = response.data.commentingUsers;
} catch (e) {
console.error(e);
}
}
private async getAvgVotes() {
try {
const response: any = await this.client.get('api/v2/analytics/votes', {
key: 'avg',
timespan: this.votes.selectedOption,
});
this.avgVotes = response.data.votes;
this.avgVotingUsers = response.data.votingUsers;
} catch (e) {
console.error(e);
}
}
private async getAvgReminds() {
try {
const response: any = await this.client.get('api/v2/analytics/reminds', {
key: 'avg',
timespan: this.reminds.selectedOption,
});
this.avgReminds = response.data.reminds;
this.avgRemindingUsers = response.data.remindingUsers;
} catch (e) {
console.error(e);
}
}
}
......@@ -3,8 +3,27 @@
[options]="['daily', 'monthly']"
#completed
>
<div class="m-analytics__averages">
<div class="m-analytics__average">
<h6>Avg Newsfeed</h6>
<h5>{{avgNewsfeedCompleted | number : '1.0-0'}}</h5>
</div>
<div class="m-analytics__average">
<h6>Avg Content</h6>
<h5>{{avgContentCompleted | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analytics__averages">
<div class="m-analytics__average" *ngFor="let current of currentCompleted">
<h6>Current {{current.name}}</h6>
<h5>{{current.value | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analyticsCard__charts">
<m-analyticscharts__offchainboosts [analytics]="'completed'" [timespan]="completed.selectedOption"></m-analyticscharts__offchainboosts>
<m-analyticscharts__offchainboosts [analytics]="'completed'" [timespan]="completed.selectedOption" (loaded)="currentCompleted = $event"></m-analyticscharts__offchainboosts>
</div>
</m-analytics__card>
......@@ -13,8 +32,27 @@
[options]="['daily', 'monthly']"
#notcompleted
>
<div class="m-analyticsCard__charts">
<m-analyticscharts__offchainboosts [analytics]="'not_completed'" [timespan]="notcompleted.selectedOption"></m-analyticscharts__offchainboosts>
<div class="m-analytics__averages">
<div class="m-analytics__average">
<h6>Avg Newsfeed</h6>
<h5>{{avgNewsfeedNotCompleted | number : '1.0-0'}}</h5>
</div>
<div class="m-analytics__average">
<h6>Avg Content</h6>
<h5>{{avgContentNotCompleted | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analytics__averages">
<div class="m-analytics__average" *ngFor="let current of currentNotCompleted">
<h6>Current {{current.name}}</h6>
<h5>{{current.value | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analyticsCard__charts">
<m-analyticscharts__offchainboosts [analytics]="'not_completed'" [timespan]="notcompleted.selectedOption" (loaded)="currentNotCompleted = $event"></m-analyticscharts__offchainboosts>
</div>
</m-analytics__card>
......@@ -23,8 +61,27 @@
[options]="['daily', 'monthly']"
#revoked
>
<div class="m-analytics__averages">
<div class="m-analytics__average">
<h6>Avg Newsfeed</h6>
<h5>{{avgNewsfeedRevoked | number : '1.0-0'}}</h5>
</div>
<div class="m-analytics__average">
<h6>Avg Content</h6>
<h5>{{avgContentRevoked | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analytics__averages">
<div class="m-analytics__average" *ngFor="let current of currentRevoked">
<h6>Current {{current.name}}</h6>
<h5>{{current.value | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analyticsCard__charts">
<m-analyticscharts__offchainboosts [analytics]="'revoked'" [timespan]="revoked.selectedOption"></m-analyticscharts__offchainboosts>
<m-analyticscharts__offchainboosts [analytics]="'revoked'" [timespan]="revoked.selectedOption" (loaded)="currentRevoked = $event"></m-analyticscharts__offchainboosts>
</div>
</m-analytics__card>
......@@ -33,8 +90,27 @@
[options]="['daily', 'monthly']"
#rejected
>
<div class="m-analytics__averages">
<div class="m-analytics__average">
<h6>Avg Newsfeed</h6>
<h5>{{avgNewsfeedRejected | number : '1.0-0'}}</h5>
</div>
<div class="m-analytics__average">
<h6>Avg Content</h6>
<h5>{{avgContentRejected | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analytics__averages">
<div class="m-analytics__average" *ngFor="let current of currentRejected">
<h6>Current {{current.name}}</h6>
<h5>{{current.value | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analyticsCard__charts">
<m-analyticscharts__offchainboosts [analytics]="'rejected'" [timespan]="rejected.selectedOption"></m-analyticscharts__offchainboosts>
<m-analyticscharts__offchainboosts [analytics]="'rejected'" [timespan]="rejected.selectedOption" (loaded)="currentRejected = $event"></m-analyticscharts__offchainboosts>
</div>
</m-analytics__card>
......@@ -42,19 +118,58 @@
[title]="'Offchain Boosts: Users (Completed)'"
[options]="['daily', 'monthly']"
#userscompleted
>
>
<div class="m-analytics__averages">
<div class="m-analytics__average">
<h6>Avg Newsfeed</h6>
<h5>{{avgNewsfeedUsersCompleted | number : '1.0-0'}}</h5>
</div>
<div class="m-analytics__average">
<h6>Avg Content</h6>
<h5>{{avgContentUsersCompleted | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analytics__averages">
<div class="m-analytics__average" *ngFor="let current of currentUsersCompleted">
<h6>Current {{current.name}}</h6>
<h5>{{current.value | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analyticsCard__charts">
<m-analyticscharts__offchainboosts [analytics]="'users_who_completed'" [timespan]="userscompleted.selectedOption"></m-analyticscharts__offchainboosts>
<m-analyticscharts__offchainboosts [analytics]="'users_who_completed'" [timespan]="userscompleted.selectedOption" (loaded)="currentUsersCompleted = $event"></m-analyticscharts__offchainboosts>
</div>
</m-analytics__card>
<m-analytics__card
[title]="'Offchain Boosts: Users (Pending)'"
[options]="['daily', 'monthly']"
[options]="['daily']"
[defaultOption]="'daily'"
#userspending
>
>
<div class="m-analytics__averages">
<div class="m-analytics__average">
<h6>Avg Newsfeed</h6>
<h5>{{avgNewsfeedUsersAwaitingCompletion | number : '1.0-0'}}</h5>
</div>
<div class="m-analytics__average">
<h6>Avg Content</h6>
<h5>{{avgContentUsersAwaitingCompletion | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analytics__averages">
<div class="m-analytics__average" *ngFor="let current of currentUsersAwaitingCompletion">
<h6>Current {{current.name}}</h6>
<h5>{{current.value | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analyticsCard__charts">
<m-analyticscharts__offchainboosts [analytics]="'users_waiting_for_completion'" [timespan]="userspending.selectedOption"></m-analyticscharts__offchainboosts>
<m-analyticscharts__offchainboosts [analytics]="'users_waiting_for_completion'" [timespan]="userspending.selectedOption" (loaded)="currentUsersAwaitingCompletion = $event"></m-analyticscharts__offchainboosts>
</div>
</m-analytics__card>
......@@ -62,9 +177,28 @@
[title]="'Offchain Boosts: Reclaimed Tokens'"
[options]="['daily', 'monthly']"
#reclaimedtokens
>
>
<div class="m-analytics__averages">
<div class="m-analytics__average">
<h6>Avg Newsfeed</h6>
<h5>{{avgNewsfeedReclaimed | number : '1.0-0'}}</h5>
</div>
<div class="m-analytics__average">
<h6>Avg Content</h6>
<h5>{{avgContentReclaimed | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analytics__averages">
<div class="m-analytics__average" *ngFor="let current of currentReclaimed">
<h6>Current {{current.name}}</h6>
<h5>{{current.value | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analyticsCard__charts">
<m-analyticscharts__offchainboosts [analytics]="'reclaimed_tokens'" [timespan]="reclaimedtokens.selectedOption"></m-analyticscharts__offchainboosts>
<m-analyticscharts__offchainboosts [analytics]="'reclaimed_tokens'" [timespan]="reclaimedtokens.selectedOption" (loaded)="currentReclaimed = $event"></m-analyticscharts__offchainboosts>
</div>
</m-analytics__card>
......@@ -72,8 +206,26 @@
[title]="'Offchain Boosts: Impressions Served'"
[options]="['daily', 'monthly']"
#impressions
>
>
<div class="m-analytics__averages">
<div class="m-analytics__average">
<h6>Avg Newsfeed</h6>
<h5>{{avgNewsfeedImpressions | number : '1.0-0'}}</h5>
</div>
<div class="m-analytics__average">
<h6>Avg Content</h6>
<h5>{{avgContentImpressions | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analytics__averages">
<div class="m-analytics__average" *ngFor="let current of currentImpressions">
<h6>Current {{current.name}}</h6>
<h5>{{current.value | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analyticsCard__charts">
<m-analyticscharts__offchainboosts [analytics]="'impressions_served'" [timespan]="impressions.selectedOption"></m-analyticscharts__offchainboosts>
<m-analyticscharts__offchainboosts [analytics]="'impressions_served'" [timespan]="impressions.selectedOption" (loaded)="currentImpressions = $event"></m-analyticscharts__offchainboosts>
</div>
</m-analytics__card>
import { Component } from '@angular/core';
import { Component, ViewChild } from '@angular/core';
import { Client } from "../../../../../services/api/client";
import { AnalyticsCardComponent } from "../card/card.component";
@Component({
selector: 'm-analyticsoffchainboosts__card',
......@@ -6,5 +8,203 @@ import { Component } from '@angular/core';
})
export class OffChainBoostsCardComponent {
@ViewChild('completed', { static: true }) completed: AnalyticsCardComponent;
@ViewChild('notcompleted', { static: true }) notcompleted: AnalyticsCardComponent;
@ViewChild('revoked', { static: true }) revoked: AnalyticsCardComponent;
@ViewChild('rejected', { static: true }) rejected: AnalyticsCardComponent;
@ViewChild('userscompleted', { static: true }) userscompleted: AnalyticsCardComponent;
@ViewChild('userspending', { static: true }) userspending: AnalyticsCardComponent;
@ViewChild('reclaimedtokens', { static: true }) reclaimedtokens: AnalyticsCardComponent;
@ViewChild('impressions', { static: true }) impressions: AnalyticsCardComponent;
avgNewsfeedCompleted: number = 0;
avgContentCompleted: number = 0;
avgNewsfeedNotCompleted: number = 0;
avgContentNotCompleted: number = 0;
avgNewsfeedRevoked: number = 0;
avgContentRevoked: number = 0;
avgNewsfeedRejected: number = 0;
avgContentRejected: number = 0;
avgNewsfeedUsersCompleted: number = 0;
avgContentUsersCompleted: number = 0;
avgNewsfeedUsersAwaitingCompletion: number = 0;
avgContentUsersAwaitingCompletion: number = 0;
avgNewsfeedReclaimed: number = 0;
avgContentReclaimed: number = 0;
avgNewsfeedImpressions: number = 0;
avgContentImpressions: number = 0;
currentCompleted: { name: string, value: number }[];
currentNotCompleted: { name: string, value: number }[];
currentRevoked: { name: string, value: number }[];
currentRejected: { name: string, value: number }[];
currentUsersCompleted: { name: string, value: number }[];
currentUsersAwaitingCompletion: { name: string, value: number }[];
currentReclaimed: { name: string, value: number }[];
currentImpressions: { name: string, value: number }[];
constructor(private client: Client) {
}
ngOnInit() {
this.getAvgCompleted();
this.getAvgNotCompleted();
this.getAvgRevoked();
this.getAvgRejected();
this.getAvgUsersCompleted();
this.getAvgUsersAwaitingCompletion();
this.getAvgReclaimed();
this.getAvgImpressions();
this.completed.selectedOptionChange.subscribe(() => {
this.getAvgCompleted();
});
this.notcompleted.selectedOptionChange.subscribe(() => {
this.getAvgNotCompleted();
});
this.revoked.selectedOptionChange.subscribe(() => {
this.getAvgRevoked();
});
this.rejected.selectedOptionChange.subscribe(() => {
this.getAvgRejected();
});
this.userscompleted.selectedOptionChange.subscribe(() => {
this.getAvgUsersCompleted();
});
this.userspending.selectedOptionChange.subscribe(() => {
this.getAvgUsersAwaitingCompletion();
});
this.reclaimedtokens.selectedOptionChange.subscribe(() => {
this.getAvgReclaimed();
});
this.impressions.selectedOptionChange.subscribe(() => {
this.getAvgImpressions();
});
}
private async getAvgCompleted() {
try {
const response: any = await this.client.get('api/v2/analytics/offchainboosts', {
key: 'completed_avg',
timespan: this.completed.selectedOption,
});
this.avgNewsfeedCompleted = response.data.newsfeed;
this.avgContentCompleted = response.data.content;
} catch (e) {
console.error(e);
}
}
private async getAvgNotCompleted() {
try {
const response: any = await this.client.get('api/v2/analytics/offchainboosts', {
key: 'not_completed_avg',
timespan: this.notcompleted.selectedOption,
});
this.avgNewsfeedNotCompleted = response.data.newsfeed;
this.avgContentNotCompleted = response.data.content;
} catch (e) {
console.error(e);
}
}
private async getAvgRevoked() {
try {
const response: any = await this.client.get('api/v2/analytics/offchainboosts', {
key: 'revoked_avg',
timespan: this.revoked.selectedOption,
});
this.avgNewsfeedRevoked = response.data.newsfeed;
this.avgContentRevoked = response.data.content;
} catch (e) {
console.error(e);
}
}
private async getAvgRejected() {
try {
const response: any = await this.client.get('api/v2/analytics/offchainboosts', {
key: 'rejected_avg',
timespan: this.rejected.selectedOption,
});
this.avgNewsfeedRejected = response.data.newsfeed;
this.avgContentRejected = response.data.content;
} catch (e) {
console.error(e);
}
}
private async getAvgUsersCompleted() {
try {
const response: any = await this.client.get('api/v2/analytics/offchainboosts', {
key: 'users_who_completed_avg',
timespan: this.userscompleted.selectedOption,
});
this.avgNewsfeedUsersCompleted = response.data.newsfeed;
this.avgContentUsersCompleted = response.data.content;
} catch (e) {
console.error(e);
}
}
private async getAvgUsersAwaitingCompletion() {
try {
const response: any = await this.client.get('api/v2/analytics/offchainboosts', {
key: 'users_waiting_for_completion_avg',
timespan: this.userspending.selectedOption,
});
this.avgNewsfeedUsersAwaitingCompletion = response.data.newsfeed;
this.avgContentUsersAwaitingCompletion = response.data.content;
} catch (e) {
console.error(e);
}
}
private async getAvgReclaimed() {
try {
const response: any = await this.client.get('api/v2/analytics/offchainboosts', {
key: 'reclaimed_tokens_avg',
timespan: this.reclaimedtokens.selectedOption,
});
this.avgNewsfeedReclaimed = response.data.newsfeed;
this.avgContentReclaimed = response.data.content;
} catch (e) {
console.error(e);
}
}
private async getAvgImpressions() {
try {
const response: any = await this.client.get('api/v2/analytics/offchainboosts', {
key: 'impressions_served_avg',
timespan: this.impressions.selectedOption,
});
this.avgNewsfeedImpressions = response.data.newsfeed;
this.avgContentImpressions = response.data.content;
} catch (e) {
console.error(e);
}
}
}
......@@ -4,24 +4,28 @@
#card
>
<div class="m-analytics__averages">
<div class="m-analytics__average">
<h6>Overall Avg Reclaimed Tokens</h6>
<h5>{{reclaimedTokens | number : '1.0'}}</h5>
</div>
<div class="m-analytics__average">
<h6>Avg Number of Plus Users</h6>
<h6>Avg Plus Users</h6>
<h5>{{users | number : '1.0'}}</h5>
</div>
<div class="m-analytics__average">
<h6>Avg Plus Transactions</h6>
<h5>{{transactions | number : '1.0'}}</h5>
</div>
</div>
<div class="m-analytics__averages">
<div class="m-analytics__average" *ngFor="let current of currents">
<h6>Current {{current.name}}</h6>
<h5>{{current.value | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analyticsCard__charts">
<m-analyticscharts__offchainplus [timespan]="card.selectedOption"></m-analyticscharts__offchainplus>
<m-analyticscharts__offchainplus [timespan]="card.selectedOption" (loaded)="currents = $event"></m-analyticscharts__offchainplus>
</div>
</m-analytics__card>
......@@ -13,6 +13,7 @@ export class OffChainPlusCardComponent {
reclaimedTokens: number = 0;
users: number = 0;
transactions: number = 0;
currents: { name: string, value: number }[];
constructor(private client: Client) {
}
......@@ -23,24 +24,14 @@ export class OffChainPlusCardComponent {
private async getAvgData() {
try {
let avgs: Array<any> = await Promise.all([
this.client.get('api/v2/analytics/offchainplus', {
key: 'average_reclaimed_tokens',
timespan: this.card.selectedOption
}),
this.client.get('api/v2/analytics/offchainplus', {
key: 'average_plus_users',
timespan: this.card.selectedOption
}),
this.client.get('api/v2/analytics/offchainplus', {
key: 'average_plus_tx',
timespan: this.card.selectedOption
}),
]);
this.reclaimedTokens = avgs[0].data;
this.users = avgs[1].data;
this.transactions = avgs[2].data;
const response: any = await this.client.get('api/v2/analytics/offchainplus', {
key: 'avg',
timespan: this.card.selectedOption
});
this.reclaimedTokens = response.data.tokens;
this.users = response.data.users;
this.transactions = response.data.transactions;
} catch (e) {
console.error(e);
}
......
......@@ -3,29 +3,34 @@
[options]="['daily', 'monthly']"
#card>
<div class="m-analytics__averages">
<div class="m-analytics__average">
<h6>Avg Wired Tokens</h6>
<h5>{{tokens | number : '1.0'}}</h5>
</div>
<div class="m-analytics__average">
<h6>Avg Number of Transactions</h6>
<h6>Avg Transactions</h6>
<h5>{{transactions | number : '1.0'}}</h5>
</div>
<div class="m-analytics__average">
<h6>Avg Number of Wire Receivers</h6>
<h6>Avg Wire Receivers</h6>
<h5>{{receivers | number : '1.0'}}</h5>
</div>
<div class="m-analytics__average">
<h6>Avg Number of Wire Senders</h6>
<h6>Avg Wire Senders</h6>
<h5>{{senders | number : '1.0'}}</h5>
</div>
</div>
<div class="m-analytics__averages">
<div class="m-analytics__average" *ngFor="let current of currents">
<h6>Current {{current.name}}</h6>
<h5>{{current.value | number : '1.0-0'}}</h5>
</div>
</div>
<div class="m-analyticsCard__charts">
<m-analyticscharts__offchainwire [timespan]="card.selectedOption"></m-analyticscharts__offchainwire>
<m-analyticscharts__offchainwire [timespan]="card.selectedOption" (loaded)="currents = $event"></m-analyticscharts__offchainwire>
</div>
</m-analytics__card>
......@@ -17,6 +17,7 @@ export class OffchainWireCardComponent implements OnInit {
transactions: number = 0;
receivers: number = 0;
senders: number = 0;
currents: { name: string, value: number }[];
constructor(private client: Client) {
}
......@@ -35,29 +36,15 @@ export class OffchainWireCardComponent implements OnInit {
private async getAvgData() {
try {
let avgs: Array<any> = await Promise.all([
this.client.get('api/v2/analytics/offchainwire', {
key: 'average_tokens',
timespan: this.card.selectedOption
}),
this.client.get('api/v2/analytics/offchainwire', {
key: 'average',
timespan: this.card.selectedOption
}),
this.client.get('api/v2/analytics/offchainwire', {
key: 'average_receivers',
timespan: this.card.selectedOption
}),
this.client.get('api/v2/analytics/offchainwire', {
key: 'average_senders',
timespan: this.card.selectedOption
}),
]);
this.tokens = avgs[0].data;
this.transactions = avgs[1].data;
this.receivers = avgs[2].data;
this.senders = avgs[3].data;
const response: any = await this.client.get('api/v2/analytics/offchainwire', {
key: 'avg',
timespan: this.card.selectedOption
});
this.tokens = response.data.tokens;
this.transactions = response.data.transactions;
this.receivers = response.data.receivers;
this.senders = response.data.senders;
} catch (e) {
console.error(e);
}
......