Updated Hero Points Page
Added everything
This commit is contained in:
parent
08a8f464f3
commit
e378f57a8c
23 changed files with 6634 additions and 1017 deletions
|
@ -2,6 +2,11 @@
|
|||
|
||||
# Next Release
|
||||
|
||||
# v0.1.1
|
||||
|
||||
* Redid layout on circle customer view
|
||||
* Renamed customer dashboard headers
|
||||
|
||||
# v0.1.0
|
||||
|
||||
* Changed Story Trail choosing to modals
|
||||
|
|
5103
package-lock.json
generated
5103
package-lock.json
generated
File diff suppressed because it is too large
Load diff
32
package.json
32
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "localloop-web",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.1",
|
||||
"description": "LocalLoop Web - Web interface for LocalLoop app",
|
||||
"author": "",
|
||||
"url": "http://www.peartrade.org",
|
||||
|
@ -20,32 +20,38 @@
|
|||
"dependencies": {
|
||||
"@agm/core": "1.0.0-beta.2",
|
||||
"@agm/js-marker-clusterer": "1.0.0-beta.2",
|
||||
"@angular/common": "5.0.1",
|
||||
"@angular/compiler": "5.0.1",
|
||||
"@angular/core": "5.0.1",
|
||||
"@angular/forms": "5.0.1",
|
||||
"@angular/platform-browser": "5.0.1",
|
||||
"@angular/platform-browser-dynamic": "5.0.1",
|
||||
"@angular/router": "5.0.1",
|
||||
"@angular/upgrade": "5.0.1",
|
||||
"@angular/common": "5.2.0",
|
||||
"@angular/compiler": "5.2.0",
|
||||
"@angular/core": "5.2.0",
|
||||
"@angular/forms": "5.2.0",
|
||||
"@angular/platform-browser": "5.2.0",
|
||||
"@angular/platform-browser-dynamic": "5.2.0",
|
||||
"@angular/router": "5.2.0",
|
||||
"@angular/upgrade": "5.2.0",
|
||||
"@types/moment": "2.13.0",
|
||||
"angular-scrollable-table": "^1.1.2",
|
||||
"chart.js": "2.7.1",
|
||||
"core-js": "2.5.1",
|
||||
"js-marker-clusterer": "1.0.0",
|
||||
"moment": "^2.19.2",
|
||||
"ng2-charts": "1.6.0",
|
||||
"ng2-expanding-table": "^1.5.2",
|
||||
"ng2-validation-manager": "0.5.3",
|
||||
"ngx-bootstrap": "2.0.0-beta.8",
|
||||
"ngx-order-pipe": "^1.1.2",
|
||||
"ngx-pagination": "3.0.3",
|
||||
"rxjs": "5.5.2",
|
||||
"ngx-pipes": "^2.1.0",
|
||||
"node": "^9.4.0",
|
||||
"rxjs": "5.5.6",
|
||||
"ts-helpers": "1.1.2",
|
||||
"webpack": "3.8.1",
|
||||
"webpack-dev-server": "2.9.4",
|
||||
"zone.js": "0.8.18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/cli": "1.5.0",
|
||||
"@angular/compiler-cli": "5.0.1",
|
||||
"@angular-devkit/schematics": "0.0.48",
|
||||
"@angular/cli": "^1.6.6",
|
||||
"@angular/compiler-cli": "5.2.0",
|
||||
"@types/jasmine": "2.8.2",
|
||||
"@types/jasminewd2": "2.0.3",
|
||||
"@types/node": "8.0.52",
|
||||
|
@ -61,6 +67,6 @@
|
|||
"protractor": "5.2.0",
|
||||
"ts-node": "3.3.0",
|
||||
"tslint": "5.8.0",
|
||||
"typescript": "2.4.2"
|
||||
"typescript": "^2.5.3"
|
||||
}
|
||||
}
|
||||
|
|
4
src/app/_guards/_interfaces/chart-data.ts
Normal file
4
src/app/_guards/_interfaces/chart-data.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
export interface ChartData {
|
||||
data: Array<number>;
|
||||
label: string;
|
||||
}
|
|
@ -25,6 +25,9 @@ import { CustGraphsService } from './providers/cust-graphs.service';
|
|||
import { OrgSnippetsService } from './providers/org-snippets.service';
|
||||
import { CustSnippetsService } from './providers/cust-snippets.service';
|
||||
import { CustPiesService } from './providers/cust-pies.service';
|
||||
import { MedalsService } from './providers/medals.service';
|
||||
//import { HeroPointsSnippetsService } from './providers/hero-points-snippets.service';
|
||||
//import { HeroPointsStatsService } from './providers/hero-points-stats.service';
|
||||
|
||||
// Layouts
|
||||
import { FullLayoutComponent } from './layouts/full-layout.component';
|
||||
|
@ -38,11 +41,15 @@ import { P500Component } from './pages/500.component';
|
|||
import { AuthModule } from './auth/auth.module';
|
||||
import { DashboardModule } from './dashboard/dashboard.module';
|
||||
|
||||
// Pipes
|
||||
import { NgPipesModule } from 'ngx-pipes';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
BrowserModule,
|
||||
HttpClientModule,
|
||||
NgxPaginationModule,
|
||||
NgPipesModule,
|
||||
BsDropdownModule.forRoot(),
|
||||
TabsModule.forRoot(),
|
||||
AuthModule,
|
||||
|
@ -70,12 +77,18 @@ import { DashboardModule } from './dashboard/dashboard.module';
|
|||
OrgSnippetsService,
|
||||
CustGraphsService,
|
||||
CustSnippetsService,
|
||||
//HeroPointsSnippetsService,
|
||||
//HeroPointsStatsService,
|
||||
MedalsService,
|
||||
CustPiesService,
|
||||
{
|
||||
provide: LocationStrategy,
|
||||
useClass: HashLocationStrategy
|
||||
}
|
||||
],
|
||||
exports: [
|
||||
NgPipesModule,
|
||||
],
|
||||
bootstrap: [ AppComponent ]
|
||||
})
|
||||
export class AppModule { }
|
||||
|
|
|
@ -24,6 +24,20 @@
|
|||
<span class="help-block">Enter the amount spent, such as 5.35 for £5.35.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-md-3 form-control-label" for="text-input">Category</label>
|
||||
<div class="col-md-9">
|
||||
<div class="input-group">
|
||||
<select type="text" class="form-control" [(ngModel)]="categoryId">
|
||||
<option value="">Uncategorised</option>
|
||||
<option *ngFor="let category of categoryIdList, let i=index" [ngValue]="category" >
|
||||
{{ categoryNameList[i] }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<span class="help-block"><strong>Optional:</strong> Choose the relevant Category for the purchase.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-md-3 form-control-label" for="text-input"><strong>Organisation Name</strong></label>
|
||||
<div class="col-md-9">
|
||||
|
|
|
@ -30,6 +30,8 @@ export class AddDataComponent implements OnInit {
|
|||
organisationTown: string;
|
||||
organisationPostcode: string;
|
||||
amount: number;
|
||||
// Assumes Groceries is 1st category
|
||||
categoryId: number = 1;
|
||||
transactionAdditionType = 1;
|
||||
storeList = [];
|
||||
showAddStore = false;
|
||||
|
@ -37,6 +39,8 @@ export class AddDataComponent implements OnInit {
|
|||
transactionFormInvalid = true;
|
||||
myDate: any;
|
||||
minDate: any;
|
||||
categoryIdList: number[] = [];
|
||||
categoryNameList: string[] = [];
|
||||
|
||||
constructor(
|
||||
private formBuilder: FormBuilder,
|
||||
|
@ -64,6 +68,15 @@ export class AddDataComponent implements OnInit {
|
|||
});
|
||||
this.myDate = moment().format('YYYY-MM-DD[T]HH:mm');
|
||||
// this.myDate = new Date().toISOString().slice(0, 16);
|
||||
this.api.categoryList().subscribe(
|
||||
result => {
|
||||
this.setCategoryList(result.categories);
|
||||
},
|
||||
error => {
|
||||
console.log('Retrieval Error');
|
||||
console.log( error._body );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
@ -71,6 +84,11 @@ export class AddDataComponent implements OnInit {
|
|||
this.accountType = localStorage.getItem('usertype');
|
||||
}
|
||||
|
||||
private setCategoryList(data: any) {
|
||||
this.categoryIdList = Object.keys(data.ids).map(key => data.ids[key]);
|
||||
this.categoryNameList = Object.keys(data.names).map(key => data.names[key]);
|
||||
}
|
||||
|
||||
getMinDate() {
|
||||
// gets the April 1st date of the current year
|
||||
const aprilDate = moment().month(3).date(1);
|
||||
|
@ -170,6 +188,7 @@ export class AddDataComponent implements OnInit {
|
|||
transaction_value : this.amount,
|
||||
purchase_time : purchaseTime,
|
||||
organisation_id : this.organisationId,
|
||||
category : this.categoryId,
|
||||
};
|
||||
break;
|
||||
case 2:
|
||||
|
@ -178,6 +197,7 @@ export class AddDataComponent implements OnInit {
|
|||
transaction_value : this.amount,
|
||||
purchase_time : purchaseTime,
|
||||
organisation_id : this.organisationId,
|
||||
category : this.categoryId,
|
||||
};
|
||||
break;
|
||||
case 3:
|
||||
|
@ -189,6 +209,7 @@ export class AddDataComponent implements OnInit {
|
|||
street_name : this.submitOrg.street_name,
|
||||
town : this.submitOrg.town,
|
||||
postcode : this.submitOrg.postcode,
|
||||
category : this.categoryId,
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -20,10 +20,12 @@ import { PayrollLogComponent } from './payroll-log.component';
|
|||
import { LeaderboardComponent } from './leaderboard.component';
|
||||
import { MapComponent } from './map.component';
|
||||
import { TrailMapComponent } from './trail-map.component';
|
||||
import { HeroPointsComponent } from './hero-points.component';
|
||||
|
||||
import { GraphWidget } from '../widgets/graph-widget.component';
|
||||
import { OrgBarSnippetComponent } from '../snippets/org-snippet-bar.component';
|
||||
import { CustBarSnippetComponent } from '../snippets/cust-snippet-bar.component';
|
||||
//import { HeroPointsSnippetBarComponent } from '../snippets/hero-points-snippet-bar.component';
|
||||
import { GraphPanel } from '../panels/graph-panel.component';
|
||||
import { PiePanel } from '../panels/pie-panel.component';
|
||||
|
||||
|
@ -37,6 +39,9 @@ import { LeaderboardResultComponent } from '../shared/leaderboard-result.compone
|
|||
// API key env variable import
|
||||
import { environment } from '../../environments/environment';
|
||||
|
||||
// Pipes
|
||||
import { NgPipesModule } from 'ngx-pipes';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
// Angular imports
|
||||
|
@ -52,6 +57,7 @@ import { environment } from '../../environments/environment';
|
|||
NgxPaginationModule,
|
||||
DashboardRoutingModule,
|
||||
ModalModule.forRoot(),
|
||||
NgPipesModule,
|
||||
],
|
||||
declarations: [
|
||||
DashboardComponent,
|
||||
|
@ -72,8 +78,10 @@ import { environment } from '../../environments/environment';
|
|||
GraphWidget,
|
||||
OrgBarSnippetComponent,
|
||||
CustBarSnippetComponent,
|
||||
//HeroPointsSnippetBarComponent,
|
||||
GraphPanel,
|
||||
PiePanel,
|
||||
HeroPointsComponent,
|
||||
],
|
||||
providers: [
|
||||
CurrencyPipe,
|
||||
|
|
|
@ -16,6 +16,7 @@ import { PayrollLogComponent } from './payroll-log.component';
|
|||
import { LeaderboardComponent } from './leaderboard.component';
|
||||
import { MapComponent } from './map.component';
|
||||
import { TrailMapComponent } from './trail-map.component';
|
||||
import { HeroPointsComponent } from './hero-points.component';
|
||||
|
||||
// Using child path to allow for FullLayout theming
|
||||
const routes: Routes = [
|
||||
|
@ -78,6 +79,11 @@ const routes: Routes = [
|
|||
path: 'feedback',
|
||||
component: FeedbackComponent,
|
||||
data: { title: 'Give Feedback' },
|
||||
},
|
||||
{
|
||||
path: 'hero-points',
|
||||
component: HeroPointsComponent,
|
||||
data: { title: 'Hero Points' }
|
||||
}
|
||||
],
|
||||
}
|
||||
|
|
224
src/app/dashboard/hero-points.component.html
Normal file
224
src/app/dashboard/hero-points.component.html
Normal file
|
@ -0,0 +1,224 @@
|
|||
<div class="animated fadeIn">
|
||||
<!--<snippet-bar-hero-points></snippet-bar-hero-points>--><!-- Snippet for hero points (four circles) -->
|
||||
<div class="row"> <!-- second row -->
|
||||
<div class="col-md-6 col-xl-3"> <!-- Hero points gain charts -->
|
||||
<div *ngFor="let widget of widgetList"> <!-- Points gain line graph -->
|
||||
<!--<widget-graph *ngIf="widget.type == 'graph'"
|
||||
[graphName]="widget.name"
|
||||
[graphTitle]="widget.title"
|
||||
[graphIcon]="widget.icon"
|
||||
[dataType]="widget.dataType">
|
||||
</widget-graph>-->
|
||||
</div> <!-- let widget of widgetList -->
|
||||
<div class="card"> <!-- Points gain by week charts -->
|
||||
<div class="card-block">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h5 class="card-title float-left mb-0">Points Gain by Week</h5>
|
||||
</div> <!--/.col-->
|
||||
</div> <!--/.row-->
|
||||
<div class="chart-wrapper">
|
||||
<ul class="horizontal-bars type-2">
|
||||
<li> <!-- This Week -->
|
||||
<span class="title">This Week</span>
|
||||
<span class="value">{{ transactionListWeek | filterBy: ['weekId']: (transactionListWeek | pluck: 'weekId' | max) | pluck: 'pointsEarned' }}<span class="text-muted small"> ({{( transactionListWeek | filterBy: ['weekId']: (transactionListWeek | pluck: 'weekId' | max) | pluck: 'pointsEarned' ) / ( transactionListWeek | pluck: 'pointsEarned' | max ) | percent:'1.0-0' }})</span></span>
|
||||
<div class="bars">
|
||||
<div class="progress" style="height: 6px;">
|
||||
<div class="progress-bar bg-success" role="progressbar"
|
||||
style="width: 39%" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div> <!-- progress -->
|
||||
</div> <!-- bars -->
|
||||
</li>
|
||||
<li> <!-- Last Week -->
|
||||
<span class="title">Last Week</span>
|
||||
<span class="value">{{ transactionListWeek | filterBy: ['weekId']: (transactionListWeek | pluck: 'weekId' | max) - 1 | pluck: 'pointsEarned' }}<span class="text-muted small"> ({{( transactionListWeek | filterBy: ['weekId']: (transactionListWeek | pluck: 'weekId' | max) - 1 | pluck: 'pointsEarned' ) / ( transactionListWeek | pluck: 'pointsEarned' | max ) | percent:'1.0-0' }})</span></span>
|
||||
<div class="bars">
|
||||
<div class="progress" style="height: 6px;">
|
||||
<div class="progress-bar bg-success" role="progressbar"
|
||||
style="width: 100%" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div> <!-- progress -->
|
||||
</div> <!-- bars -->
|
||||
</li>
|
||||
<li> <!-- Week Maximum -->
|
||||
<span class="title">Week Maximum</span>
|
||||
<span class="value">{{ transactionListWeek | pluck: 'pointsEarned' | max }}<span class="text-muted small"> (100%)</span></span>
|
||||
<div class="bars">
|
||||
<div class="progress" style="height: 6px;">
|
||||
<div class="progress-bar bg-success" role="progressbar"
|
||||
style="width: 100%" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div> <!-- progress -->
|
||||
</div> <!-- bars -->
|
||||
</li>
|
||||
<li> <!-- Weekly Average -->
|
||||
<span class="title">Weekly Average</span>
|
||||
<span class="value">{{ ((transactionListWeek | pluck: 'pointsEarned' | sum) / (transactionListWeek.length)) | round }}<span class="text-muted small"> ({{ (((transactionListWeek | pluck: 'pointsEarned' | sum) / (transactionListWeek.length)) | round ) / ( transactionListWeek | pluck: 'pointsEarned' | max ) | percent:'1.0-0' }})</span></span>
|
||||
<div class="bars">
|
||||
<div class="progress" style="height: 6px;">
|
||||
<div class="progress-bar bg-success" role="progressbar"
|
||||
style="width: 51%" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div> <!-- progess -->
|
||||
</div> <!-- bars -->
|
||||
</li>
|
||||
</ul> <!-- horizontal-bars -->
|
||||
</div> <!-- chart-wrapper -->
|
||||
</div> <!-- card-block -->
|
||||
</div> <!-- card -->
|
||||
</div> <!-- col -->
|
||||
<div class="col-md-6 col-xl-3"> <!-- Leaderboard -->
|
||||
<div *ngIf="!noUserList">
|
||||
<table class="table table-striped table-hover"> <!-- Leaderboard Table -->
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Rank</th>
|
||||
<th>Name</th>
|
||||
<th>Hero Points</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let user of userList | orderBy: '-heroPoints' | paginate: paginateLeadConfig; let i = index" [ngStyle]="{'background-color': user.userId === 1 ? '#F39C12': 'auto', 'color': user.userId === 1 ? '#ffffff': 'auto'}">
|
||||
<td>{{ i + 1 + (paginateLeadConfig.itemsPerPage * paginateLeadConfig.currentPage) - paginateLeadConfig.itemsPerPage }}</td> <!-- uses page number and number of pages to calculate the rankings -->
|
||||
<td>{{ user.displayName }}</td> <!-- Display Name -->
|
||||
<td>{{ user.heroPoints }}</td> <!-- Hero Points -->
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<pagination-template #p="paginationApi" [id]="paginateLeadConfig.id" (pageChange)="paginateLeadConfig.currentPage = $event"> <!-- Leaderboard pagination -->
|
||||
<ul class="pagination">
|
||||
<li class="page-item" [class.disabled]="p.isFirstPage()">
|
||||
<a class="page-link clickable" *ngIf="!p.isFirstPage()" (click)="p.previous()">Prev</a>
|
||||
</li>
|
||||
<li *ngFor="let page of p.pages" class="page-item" [class.active]="p.getCurrent() === page.value">
|
||||
<a class="page-link clickable" (click)="p.setCurrent(page.value)" *ngIf="p.getCurrent() !== page.value">
|
||||
<span>{{ page.label }}</span>
|
||||
</a>
|
||||
<div class="page-link" *ngIf="p.getCurrent() === page.value">
|
||||
<span>{{ page.label }}</span>
|
||||
</div>
|
||||
</li>
|
||||
<li class="page-item" [class.disabled]="p.isLastPage()">
|
||||
<a class="page-link clickable" *ngIf="!p.isLastPage()" (click)="p.next()">Next</a>
|
||||
</li>
|
||||
</ul>
|
||||
</pagination-template>
|
||||
</div> <!-- if !noUserList -->
|
||||
<div *ngIf="noUserList" class="card-block">
|
||||
No Leaderboard available.
|
||||
</div> <!-- if noUserList -->
|
||||
</div>
|
||||
<div class="col-md-6 col-xl-6"> <!-- Medal Table -->
|
||||
<div *ngIf="!noMedalList">
|
||||
<table class="table header-fixed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col-3">Medal</th>
|
||||
<th class="col-9">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<ng-container *ngFor="let groupNo of medalList | unique: 'medalGroupId'; let i = index"> <!-- ngFor each group of medals (global) -->
|
||||
<ng-container *ngIf="(medalList | filterBy: ['title']: groupNo.title: search: true).length > 1"> <!-- if the group is longer than 1 -->
|
||||
<!-- *ngIf 'global' medal and is/isn't expanded (headers)-->
|
||||
<tr *ngIf="groupNo.expanded && groupNo.medalType == 'global'" (click)="groupNo.expanded = false" [ngStyle]="{'background-color': '#20A8D8', 'color': '#ffffff' }">
|
||||
<td class="col-3">{{groupNo.title}}</td>
|
||||
<td class="col-6">Click to collapse</td>
|
||||
<td class="col-1">-</td>
|
||||
<td class="col-2" [ngStyle]="{'text-align': 'right'}">{{ ((medalList | filterBy: ['medalType']: 'global' | filterBy: ['title']: groupNo.title: search: true) | filterBy: ['unlocked']: true).length }}/{{ (medalList | filterBy: ['medalType']: 'global'| filterBy: ['title']: groupNo.title: search: true).length }}</td>
|
||||
</tr>
|
||||
<tr *ngIf="!groupNo.expanded && groupNo.medalType == 'global'" (click)="groupNo.expanded = true" [ngStyle]="{'background-color': '#20A8D8', 'color': '#ffffff' }">
|
||||
<td class="col-3">{{groupNo.title}}</td>
|
||||
<td class="col-6">Click to expand</td>
|
||||
<td class="col-1">+</td>
|
||||
<td class="col-2" [ngStyle]="{'text-align': 'right'}"> {{ ((medalList | filterBy: ['medalType']: 'global' | filterBy: ['title']: groupNo.title: search: true) | filterBy: ['unlocked']: true).length }}/{{ (medalList | filterBy: ['medalType']: 'global'| filterBy: ['title']: groupNo.title: search: true).length }}</td>
|
||||
</tr>
|
||||
<!-- display actual medals -->
|
||||
<ng-container *ngFor="let medal of medalList | orderBy: ['+medalGroupId', '+reward']"> <!-- list each medal in each group, ordered by rewards, ascending order -->
|
||||
<tr *ngIf="groupNo.expanded && medal.medalGroupId == i && groupNo.medalType == 'global'" [ngStyle]="{'background-color':medal.unlocked === true ? '#89DD73' : '#F25F5F', 'color': '#ffffff' }">
|
||||
<td class="col-3">{{ medal.title }}</td>
|
||||
<td class="col-7">{{ medal.description }}</td>
|
||||
<td class="col-2" [ngStyle]="{'text-align': 'right'}">0/{{ medal.valueRequired }}</td> <!-- progress -->
|
||||
</tr>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="(medalList | filterBy: ['title']: groupNo.title: search: true).length == 1"> <!-- if there is only one medal in the group, just display medal, no header -->
|
||||
<ng-container *ngFor="let medal of medalList | orderBy: ['+medalGroupId', '+reward']"> <!-- Unnecessary loop because there is only one medal in each group -->
|
||||
<tr *ngIf="medal.medalGroupId == i && groupNo.medalType == 'global'" [ngStyle]="{'background-color':medal.unlocked === true ? '#89DD73' : '#F25F5F', 'color': '#ffffff' }">
|
||||
<td class="col-3">{{ medal.title }}</td> <!-- medal name -->
|
||||
<td class="col-7">{{ medal.description }}</td> <!-- medal description -->
|
||||
<td class="col-2" [ngStyle]="{'text-align': 'right'}">0/{{ medal.valueRequired }}</td> <!-- progress -->
|
||||
</tr>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</ng-container> <!-- ngFor each group of medals (global) -->
|
||||
<ng-container *ngFor="let organisation of organisationList | orderBy: '+name'; let orgI = index"> <!-- ngFor organisation of organisationList -->
|
||||
<!-- ngIf organisation is/isn't expanded display correct header -->
|
||||
<tr *ngIf="organisation.expanded" (click)="organisation.expanded = false" [ngStyle]="{'background-color': '#F39C12', 'color': '#ffffff' }">
|
||||
<td class="col-3">{{organisation.name}}</td>
|
||||
<td class="col-6">Click to collapse</td>
|
||||
<td class="col-1">-</td>
|
||||
<td class="col-2" [ngStyle]="{'text-align': 'right'}">{{ (medalList | filterBy: ['medalType']: 'organisation' | filterBy: ['unlocked']: true).length }}/{{ (medalList | filterBy: ['medalType']: 'organisation').length }}</td>
|
||||
</tr>
|
||||
<tr *ngIf="!organisation.expanded" (click)="organisation.expanded = true" [ngStyle]="{'background-color': '#F39C12', 'color': '#ffffff' }">
|
||||
<td class="col-3">{{organisation.name}}</td>
|
||||
<td class="col-6">Click to expand</td>
|
||||
<td class="col-1">+</td>
|
||||
<td class="col-2" [ngStyle]="{'text-align': 'right'}">{{ (medalList | filterBy: ['medalType']: 'organisation' | filterBy: ['unlocked']: true).length }}/{{ (medalList | filterBy: ['medalType']: 'organisation').length }}</td>
|
||||
</tr>
|
||||
<ng-container *ngFor="let groupNo of medalList | unique: 'medalGroupId'; let i = index"> <!-- ngFor each group of medals (organisation) -->
|
||||
<ng-container *ngIf="(medalList | filterBy: ['title']: groupNo.title: search: true).length > 1"> <!-- ngIf length of group is more than 1 -->
|
||||
<!-- ngIf organisation is/isn't expanded -->
|
||||
<tr *ngIf="organisation.expanded && groupNo.expanded && groupNo.medalType == 'organisation'" (click)="groupNo.expanded = false" [ngStyle]="{'background-color': '#20A8D8', 'color': '#ffffff' }">
|
||||
<td class="col-3">{{groupNo.title}}</td>
|
||||
<td class="col-6">Click to collapse</td>
|
||||
<td class="col-1">-</td>
|
||||
<td class="col-2" [ngStyle]="{'text-align': 'right'}">{{ ((medalList | filterBy: ['medalType']: 'organisation' | filterBy: ['title']: groupNo.title: search: true) | filterBy: ['unlocked']: true).length }}/{{ (medalList | filterBy: ['medalType']: 'organisation'| filterBy: ['title']: groupNo.title: search: true).length }}</td>
|
||||
</tr>
|
||||
<tr *ngIf="organisation.expanded && !groupNo.expanded && groupNo.medalType == 'organisation'" (click)="groupNo.expanded = true" [ngStyle]="{'background-color': '#20A8D8', 'color': '#ffffff' }">
|
||||
<td class="col-3">{{groupNo.title}}</td>
|
||||
<td class="col-6">Click to expand</td>
|
||||
<td class="col-1">+</td>
|
||||
<td class="col-2" [ngStyle]="{'text-align': 'right'}">{{ ((medalList | filterBy: ['medalType']: 'organisation' | filterBy: ['title']: groupNo.title: search: true) | filterBy: ['unlocked']: true).length }}/{{ (medalList | filterBy: ['medalType']: 'organisation'| filterBy: ['title']: groupNo.title: search: true).length }}</td>
|
||||
</tr>
|
||||
<ng-container *ngFor="let medal of medalList | orderBy: ['+medalGroupId', '+reward']">
|
||||
<tr *ngIf="organisation.expanded && groupNo.expanded && medal.medalGroupId == i && groupNo.medalType == 'organisation'" [ngStyle]="{'background-color':medal.unlocked === true ? '#89DD73' : '#F25F5F', 'color': '#ffffff' }">
|
||||
<td class="col-3">{{ medal.title }}</td>
|
||||
<td class="col-7">{{ medal.description }}</td>
|
||||
<td class="col-2" [ngStyle]="{'text-align': 'right'}">0/{{ medal.valueRequired }}</td>
|
||||
</tr>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="(medalList | filterBy: ['title']: groupNo.title: search: true).length <= 1"> <!-- ngIf length or group is <= 1 -->
|
||||
<ng-container *ngFor="let medal of medalList | orderBy: ['+medalGroupId', '+reward']">
|
||||
<tr *ngIf="organisation.expanded && medal.medalGroupId == i && groupNo.medalType == 'organisation'" [ngStyle]="{'background-color':medal.unlocked === true ? '#89DD73' : '#F25F5F', 'color': '#ffffff' }">
|
||||
<td class="col-3">{{ medal.title }}</td>
|
||||
<td class="col-7">{{ medal.description }}</td>
|
||||
<td class="col-2" [ngStyle]="{'text-align': 'right'}">0/{{ medal.valueRequired }}</td>
|
||||
</tr>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</ng-container> <!-- ngFor each group of medals (organisation) -->
|
||||
</ng-container> <!-- ngFor organisation of organisationList -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div> <!-- if !noMedalList -->
|
||||
<div *ngIf="noMedalList" class="card-block">
|
||||
No Leaderboard available.
|
||||
</div> <!-- if noMedalList -->
|
||||
</div>
|
||||
</div><!-- Row -->
|
||||
<div *ngFor="let group of globalMedalList">
|
||||
<div *ngFor="let threshold of group.group_name | pluck: 'threshold'">
|
||||
</div>
|
||||
</div>
|
||||
<div *ngFor="let medals of testList">
|
||||
<div *ngFor="let group of medals | values; let groupIndex = index">
|
||||
<div>threshold length - total {{(group[0] | values).length - 1}}</div>
|
||||
<div>group_title {{(medals | keys)[groupIndex]}}</div>
|
||||
<div>All awarded values for group {{group[0] | values | filterBy: ['awarded']: 'true' | pluck: 'awarded' | json}}</div>
|
||||
<div *ngFor="let thresholds of group[0] | values">
|
||||
<div *ngIf="thresholds | isObject">
|
||||
<div>9 {{thresholds | json}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
2081
src/app/dashboard/hero-points.component.ts
Normal file
2081
src/app/dashboard/hero-points.component.ts
Normal file
File diff suppressed because it is too large
Load diff
|
@ -89,6 +89,14 @@
|
|||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li *ngIf="accountType == 'customer'" class="nav-item">
|
||||
<a class="nav-link" routerLinkActive="active" [routerLink]="['/hero-points']">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col-2"><i class="icon-trophy"></i></div>
|
||||
<div class="col-10">Hero Points</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
|
@ -116,6 +116,17 @@ export class ApiService {
|
|||
);
|
||||
}
|
||||
|
||||
// Basic Customer User stats API
|
||||
public categoryList() {
|
||||
const key = this.sessionKey;
|
||||
return this.http.post<any>(
|
||||
this.apiUrl + '/search/category',
|
||||
{
|
||||
session_key : key,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Searches organisations used for transaction submission
|
||||
|
||||
public search(data) {
|
||||
|
|
|
@ -9,6 +9,7 @@ export class CustGraphsService {
|
|||
|
||||
public getGraph(name: string, data: any = {}) {
|
||||
data.graph = name;
|
||||
//console.log(this.api.post(this.custGraphUrl, data));
|
||||
return this.api.post(this.custGraphUrl, data);
|
||||
}
|
||||
}
|
||||
|
|
8
src/app/providers/hero-points-leaderboard.service.ts
Normal file
8
src/app/providers/hero-points-leaderboard.service.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable()
|
||||
export class HeroPointsLeaderboardService {
|
||||
|
||||
constructor() { }
|
||||
|
||||
}
|
15
src/app/providers/hero-points-snippets.service.ts
Normal file
15
src/app/providers/hero-points-snippets.service.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { ApiService } from './api-service';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
@Injectable()
|
||||
export class HeroPointsSnippetsService {
|
||||
private heroPointsSnippetsUrl = '/v1/user/points';
|
||||
|
||||
constructor(private api: ApiService) { }
|
||||
|
||||
// This endpoint should mimic basicStats
|
||||
public getPointsData(): Observable<any> {
|
||||
return this.api.post(this.heroPointsSnippetsUrl);
|
||||
}
|
||||
}
|
14
src/app/providers/hero-points-stats.service.ts
Normal file
14
src/app/providers/hero-points-stats.service.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { ApiService } from './api-service';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
@Injectable()
|
||||
export class HeroPointsStatsService {
|
||||
private heroPointsStatsUrl = '/v1/user/points';
|
||||
|
||||
constructor(private api: ApiService) { }
|
||||
|
||||
public getHeroPointsStats(): Observable<any> {
|
||||
return this.api.post(this.heroPointsStatsUrl);
|
||||
}
|
||||
}
|
15
src/app/providers/medals.service.ts
Normal file
15
src/app/providers/medals.service.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { ApiService } from './api-service';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
@Injectable()
|
||||
export class MedalsService {
|
||||
private medalsUrl = '/v1/user/medals';
|
||||
|
||||
constructor(private api: ApiService) { }
|
||||
|
||||
public getMedals(): Observable<any> {
|
||||
return this.api.post(this.medalsUrl);
|
||||
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import { CustSnippetsService } from '../providers/cust-snippets.service';
|
|||
selector: 'snippet-bar-cust',
|
||||
templateUrl: 'cust-snippet-bar.component.html',
|
||||
})
|
||||
|
||||
export class CustBarSnippetComponent implements OnInit {
|
||||
|
||||
public userSum = 0;
|
||||
|
|
50
src/app/snippets/hero-points-snippet-bar.component.html
Normal file
50
src/app/snippets/hero-points-snippet-bar.component.html
Normal file
|
@ -0,0 +1,50 @@
|
|||
<div class="row">
|
||||
<div class="col-md-6 col-xl-3">
|
||||
<div class="card text-center" style="background-color: transparent; border: none">
|
||||
<div class="card-block">
|
||||
<ul style="list-style: none; padding-left: 0;">
|
||||
<li class="hidden-sm-down">
|
||||
<div><h5 class="text-orange">My Hero Points</h5></div>
|
||||
<div class="number-circle-hero mx-auto"><strong>{{ pointTotal | number:'1.0-0' }}</strong></div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-xl-3">
|
||||
<div class="card text-center" style="background-color: transparent; border: none">
|
||||
<div class="card-block">
|
||||
<ul style="list-style: none; padding-left: 0;">
|
||||
<li class="hidden-sm-down">
|
||||
<div><h5 class="text-dark-green">Last Transaction Points</h5></div>
|
||||
<div class="number-circle mx-auto"><strong>{{pointLast | number:'1.0-0' }}</strong></div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-xl-3">
|
||||
<div class="card text-center" style="background-color: transparent; border: none">
|
||||
<div class="card-block">
|
||||
<ul style="list-style: none; padding-left: 0;">
|
||||
<li class="hidden-sm-down">
|
||||
<div><h5 class="text-dark-green">Total Transactions</h5></div>
|
||||
<div class="number-circle mx-auto"><strong>{{ transCount | number:'1.0-0' }}</strong></div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-xl-3">
|
||||
<div class="card text-center" style="background-color: transparent; border: none">
|
||||
<div class="card-block">
|
||||
<ul style="list-style: none; padding-left: 0;">
|
||||
<li class="hidden-sm-down">
|
||||
<div><h5 class="text-dark-green">Average Multiplier</h5></div>
|
||||
<div class="number-circle mx-auto"><strong>{{ avgMulti | number:'1.0-0' }}</strong></div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
31
src/app/snippets/hero-points-snippet-bar.component.ts
Normal file
31
src/app/snippets/hero-points-snippet-bar.component.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { HeroPointsSnippetsService } from '../providers/hero-points-snippets.service';
|
||||
|
||||
@Component({
|
||||
selector: 'snippet-bar-hero-points',
|
||||
templateUrl: './hero-points-snippet-bar.component.html',
|
||||
})
|
||||
|
||||
export class HeroPointsSnippetBarComponent implements OnInit {
|
||||
|
||||
public pointTotal = 0;
|
||||
public pointLast = 0;
|
||||
public transCount = 0;
|
||||
public avgMulti = 0;
|
||||
|
||||
constructor(
|
||||
private snippetsService: HeroPointsSnippetsService,
|
||||
) { }
|
||||
|
||||
public ngOnInit(): void {
|
||||
this.snippetsService.getPointsData()
|
||||
.subscribe(
|
||||
result => {
|
||||
this.pointTotal = result.snippets.point_total;
|
||||
this.pointLast = result.snippets.point_last;
|
||||
this.transCount = result.snippets.trans_count;
|
||||
this.avgMulti = result.snippets.avg_multi;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -6,8 +6,14 @@
|
|||
.table-striped tbody tr:nth-of-type(odd) {
|
||||
background-color: #d2eef7;
|
||||
}
|
||||
|
||||
.table-striped tbody tr:nth-of-type(even) {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.table-hover tbody tr:hover td {
|
||||
background-color: $table-bg-hover;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.table thead tr {
|
||||
|
@ -15,6 +21,63 @@
|
|||
color: #e8ebed;
|
||||
}
|
||||
|
||||
.header-fixed {
|
||||
width: 100%;
|
||||
table-layout:fixed;
|
||||
display: table;
|
||||
}
|
||||
|
||||
.header-fixed > thead,
|
||||
.header-fixed > tbody,
|
||||
.header-fixed > thead > tr,
|
||||
.header-fixed > tbody > tr,
|
||||
.header-fixed > thead > tr > th,
|
||||
.header-fixed > tbody > tr > td {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.header-fixed > tbody > tr:after,
|
||||
.header-fixed > thead > tr:after {
|
||||
content: ' ';
|
||||
display: block;
|
||||
visibility: hidden;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.header-fixed {
|
||||
|
||||
tbody {
|
||||
overflow-y: auto;
|
||||
height: 370px;
|
||||
}
|
||||
}
|
||||
|
||||
tr.collapse.in {
|
||||
display:table-row;
|
||||
}
|
||||
|
||||
.header-fixed > tbody > tr > td,
|
||||
.header-fixed > thead > tr > th,
|
||||
{
|
||||
//width: 33.33%;
|
||||
float: left;
|
||||
overflow-wrap: break-word;
|
||||
|
||||
.col-1 {width: 8.33%;}
|
||||
.col-2 {width: 16.66%;}
|
||||
.col-3 {width: 25%;}
|
||||
.col-4 {width: 33.33%;}
|
||||
.col-5 {width: 41.66%;}
|
||||
.col-6 {width: 50%;}
|
||||
.col-7 {width: 58.33%;}
|
||||
.col-8 {width: 66.66%;}
|
||||
.col-9 {width: 75%;}
|
||||
.col-10 {width: 83.33%;}
|
||||
.col-11 {width: 91.66%;}
|
||||
.col-12 {width: 100%;}
|
||||
}
|
||||
|
||||
|
||||
// Map styling
|
||||
agm-map {
|
||||
height: 75vh;
|
||||
|
@ -43,6 +106,23 @@ agm-map {
|
|||
color: #10602c;
|
||||
}
|
||||
|
||||
.number-circle-hero {
|
||||
height: 10rem;
|
||||
border-radius:50%;
|
||||
text-align:center;
|
||||
width: 10rem;
|
||||
padding: 5rem 5%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
background: #F39C12;
|
||||
color: white;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.text-orange {
|
||||
color: #D35400;
|
||||
}
|
||||
|
||||
// white title font variant on type-2 as defined in _widgets.css
|
||||
.horizontal-bars {
|
||||
padding: 0;
|
||||
|
|
Reference in a new issue