| @@ -22,16 +22,16 @@ const routes: Routes = [ | |||
| {path : 'login', component: AuthComponent}, | |||
| {path : 'transaction', component: TransactionComponent, canActivate: [AuthGuard]}, | |||
| {path : 'transaction-list', component: TransactionListComponent, canActivate: [AuthGuard]}, | |||
| {path : 'list-all-loans', component: ListAllLoansComponent, }, | |||
| {path : 'edit-loan/:id', component: LoanEditComponent, }, | |||
| {path : 'edit-loan', component: LoanEditComponent, }, | |||
| {path : 'uploads', component: LenderUploadsComponent, }, | |||
| {path : 'uploads/:id', component: LenderUploadsComponent, }, | |||
| {path : 'broker-loan-list', component: BrokerLoanListComponent, }, | |||
| {path : 'broker-reward', component: BrokerRewardComponent, }, | |||
| {path : 'broker-profile', component: BrokerProfileComponent, }, | |||
| {path : 'client-loan-list', component: ClientLoanListComponent, }, | |||
| {path : 'client-profile', component: ClientProfileComponent, }, | |||
| {path : 'list-all-loans', component: ListAllLoansComponent, canActivate: [AuthGuard]}, | |||
| {path : 'edit-loan/:id', component: LoanEditComponent, canActivate: [AuthGuard]}, | |||
| {path : 'edit-loan', component: LoanEditComponent, canActivate: [AuthGuard]}, | |||
| {path : 'uploads', component: LenderUploadsComponent, canActivate: [AuthGuard]}, | |||
| {path : 'uploads/:id', component: LenderUploadsComponent, canActivate: [AuthGuard]}, | |||
| {path : 'broker-loan-list', component: BrokerLoanListComponent, canActivate: [AuthGuard] }, | |||
| {path : 'broker-reward', component: BrokerRewardComponent, canActivate: [AuthGuard] }, | |||
| {path : 'broker-profile', component: BrokerProfileComponent, canActivate: [AuthGuard]}, | |||
| {path : 'client-loan-list', component: ClientLoanListComponent, canActivate: [AuthGuard] }, | |||
| {path : 'client-profile', component: ClientProfileComponent, canActivate: [AuthGuard] }, | |||
| {path : 'e403', component: E403Component, }, | |||
| ]; | |||
| @@ -57,7 +57,6 @@ import { EditorModule } from '@progress/kendo-angular-editor'; | |||
| import { BasicinfoComponent } from './loan-edit/basicinfo/basicinfo.component'; | |||
| import { PeopleRewardComponent } from './loan-edit/people-reward/people-reward.component'; | |||
| import { TrailIncomeComponent } from './loan-edit/trail-income/trail-income.component'; | |||
| import { HintCardComponent } from './loan-edit/hint-card/hint-card.component'; | |||
| import { PeopleSelectComponent } from './people-select/people-select.component'; | |||
| import { LoanDetailComponent } from './loan-detail/loan-detail.component'; | |||
| import {LoanSingleService} from './service/loan.single.service'; | |||
| @@ -100,7 +99,6 @@ import { E403Component } from './e403/e403.component'; | |||
| BasicinfoComponent, | |||
| PeopleRewardComponent, | |||
| TrailIncomeComponent, | |||
| HintCardComponent, | |||
| PeopleSelectComponent, | |||
| LoanDetailComponent, | |||
| RatingInputComponent, | |||
| @@ -5,7 +5,7 @@ div.parent { | |||
| width: 100%; | |||
| height: 100vh; | |||
| opacity: 0.95; | |||
| background: url('../../assets/img/body_bg.jpg') no-repeat center center fixed; | |||
| background: url('/assets/img/body_bg.jpg') no-repeat center center fixed; | |||
| background-size: cover; | |||
| } | |||
| @@ -22,4 +22,4 @@ div.parent { | |||
| padding-bottom: 20px; | |||
| box-shadow: 0 0 6px black; | |||
| border-radius: 5px; | |||
| } | |||
| } | |||
| @@ -38,7 +38,7 @@ export class AuthComponent implements OnInit, OnDestroy{ | |||
| // tslint:disable-next-line:typedef | |||
| submitForm() { | |||
| console.log(this.userForm); | |||
| // console.log(this.userForm); | |||
| this.loading = true; | |||
| this.authService.login(this.userForm.value.email, this.userForm.value.password); | |||
| } | |||
| @@ -1 +1,34 @@ | |||
| <p>broker-loan-list works!</p> | |||
| <kendo-grid | |||
| [data]="brokerLoans | async" | |||
| [height]="610" | |||
| [loading]="brokerLoans.loading" | |||
| class="fullheight_grid" | |||
| > | |||
| <kendo-grid-column field="Id"></kendo-grid-column> | |||
| <kendo-grid-column field="Item"></kendo-grid-column> | |||
| <kendo-grid-column field="Amount"> | |||
| <ng-template kendoGridCellTemplate let-dataItem> | |||
| <span [ngClass]="{'green text-bold': dataItem.Amount < 500000}">{{ dataItem.Amount | currency }}</span> | |||
| </ng-template> | |||
| </kendo-grid-column> | |||
| <kendo-grid-column field="Settlement"> | |||
| <ng-template kendoGridCellTemplate let-dataItem > | |||
| <div *ngIf="dataItem.Settlement != null" > | |||
| {{ dataItem.Settlement | date: 'yyyy-MM-dd' }} | |||
| </div> | |||
| </ng-template> | |||
| </kendo-grid-column> | |||
| <kendo-grid-column field="broker"> | |||
| <ng-template kendoGridCellTemplate let-dataItem> | |||
| <div *ngFor="let p of dataItem.Broker, let idx=index "> | |||
| <div class="customer-photo" [ngStyle]="{'background-image' : photoURL(dataItem.BrokerIds[idx])}"></div> | |||
| <div class="customer-name"> {{ p }}</div> | |||
| </div> | |||
| </ng-template> | |||
| </kendo-grid-column> | |||
| </kendo-grid> | |||
| @@ -0,0 +1,24 @@ | |||
| .fullheight_grid { | |||
| height: calc(100vh - 48px) !important; | |||
| } | |||
| .customer-photo{ | |||
| display: inline-block; | |||
| width: 32px; | |||
| height: 32px; | |||
| border-radius: 50%; | |||
| background-size: 32px 35px; | |||
| background-position: center center; | |||
| vertical-align: middle; | |||
| line-height: 32px; | |||
| box-shadow: inset 0 0 1px #999, inset 0 0 10px rgba(0,0,0,.2); | |||
| margin-left: 5px; | |||
| margin-bottom: 10px; | |||
| } | |||
| .customer-name { | |||
| display: inline-block; | |||
| vertical-align: middle; | |||
| line-height: 32px; | |||
| padding-left: 10px; | |||
| } | |||
| @@ -1,4 +1,10 @@ | |||
| import { Component, OnInit } from '@angular/core'; | |||
| import {Component, Input, OnInit} from '@angular/core'; | |||
| import {BrokerModel} from '../models/broker.model'; | |||
| import {LoanModel} from '../models/loan.model'; | |||
| import {LoanSummaryService} from '../service/loan_summary.service'; | |||
| import {CompositeFilterDescriptor, SortDescriptor} from '@progress/kendo-data-query'; | |||
| import {AuthService} from '../service/auth.service'; | |||
| import {PeopleModel} from '../models/people.model'; | |||
| @Component({ | |||
| selector: 'app-broker-loan-list', | |||
| @@ -7,9 +13,25 @@ import { Component, OnInit } from '@angular/core'; | |||
| }) | |||
| export class BrokerLoanListComponent implements OnInit { | |||
| constructor() { } | |||
| @Input() public broker: PeopleModel = PeopleModel.EmptyNew(); | |||
| public brokerLoans: LoanSummaryService; | |||
| constructor( private lss: LoanSummaryService, private auth: AuthService) { } | |||
| ngOnInit(): void { | |||
| this.brokerLoans = this.lss; | |||
| this.broker = this.auth.loggedIn.user; | |||
| this.loadData(); | |||
| } | |||
| private loadData(): void { | |||
| const sort: Array <SortDescriptor> = [{dir: 'desc', field: 'Settlement'}]; | |||
| const filter: CompositeFilterDescriptor = {logic: 'and', filters: [] }; | |||
| this.lss.query({ skip: 0, take: 1000, sort, filter}); | |||
| } | |||
| private photoURL(peopleId: any): string { | |||
| const url = this.auth.getUrl('avatar/') + peopleId; | |||
| return 'url("' + url + '")'; | |||
| } | |||
| } | |||
| @@ -13,7 +13,7 @@ h1 { | |||
| font-size: 50px; | |||
| } | |||
| body { | |||
| div.body { | |||
| font: 20px Helvetica, sans-serif; | |||
| color: #333; | |||
| } | |||
| @@ -112,7 +112,7 @@ | |||
| <kendo-grid-column field="Settlement" title="Settlement" [class]="'topAlign'" width="300" filterable="false" filter="date"> | |||
| <ng-template kendoGridCellTemplate let-dataItem > | |||
| <div *ngIf="dataItem.Settlement != null" > | |||
| {{ dataItem.Settlement | date: 'yyyy-MM-dd' }} {{dataItem.Index}} | |||
| {{ dataItem.Settlement | date: 'yyyy-MM-dd' }} | |||
| </div> | |||
| </ng-template> | |||
| <ng-template kendoGridFilterCellTemplate let-filter let-column="column"> | |||
| @@ -1,44 +0,0 @@ | |||
| <kendo-card [width]="'360px'"> | |||
| <kendo-card-header class="k-hbox"> | |||
| <kendo-avatar | |||
| width="40px" | |||
| height="40px" | |||
| [imageSrc]="thumbnailSrc" | |||
| [shape]="'circle'" | |||
| ></kendo-avatar> | |||
| <div> | |||
| <h1 kendoCardTitle>bg_tourism - {{currentStep}}</h1> | |||
| <p kendoCardSubtitle>Bulgaria, Europe</p> | |||
| </div> | |||
| </kendo-card-header> | |||
| <img [src]="cover" kendoCardMedia alt="cover_img" /> | |||
| <kendo-card-body> | |||
| <h4>Black Sea, Bulgaria</h4> | |||
| <hr kendoCardSeparator /> | |||
| <p> | |||
| The Black Sea is bordered by Ukraine, Romania, Bulgaria, | |||
| Turkey, Georgia, and Russia. It has a positive water | |||
| balance; that is, a net outflow of water 300 km3 per year | |||
| through the Bosphorus and the Dardanelles into the Aegean | |||
| Sea. | |||
| </p> | |||
| </kendo-card-body> | |||
| <kendo-card-actions orientation="horizontal" layout="stretched"> | |||
| <button class="k-button k-flat" (click)="toggleLike()"> | |||
| <span [ngClass]="heartIcon()"></span> | |||
| Like | |||
| </button> | |||
| <hr kendoCardSeparator [orientation]="'vertical'" /> | |||
| <button class="k-button k-flat"> | |||
| Share | |||
| </button> | |||
| <hr kendoCardSeparator [orientation]="'vertical'" /> | |||
| <button class="k-button k-flat"> | |||
| Read More | |||
| </button> | |||
| </kendo-card-actions> | |||
| <kendo-card-footer class="k-hbox"> | |||
| <span>Created By @alex</span> | |||
| <span>March 4, 2020</span> | |||
| </kendo-card-footer> | |||
| </kendo-card> | |||
| @@ -1,25 +0,0 @@ | |||
| import { ComponentFixture, TestBed } from '@angular/core/testing'; | |||
| import { HintCardComponent } from './hint-card.component'; | |||
| describe('HintCardComponent', () => { | |||
| let component: HintCardComponent; | |||
| let fixture: ComponentFixture<HintCardComponent>; | |||
| beforeEach(async () => { | |||
| await TestBed.configureTestingModule({ | |||
| declarations: [ HintCardComponent ] | |||
| }) | |||
| .compileComponents(); | |||
| }); | |||
| beforeEach(() => { | |||
| fixture = TestBed.createComponent(HintCardComponent); | |||
| component = fixture.componentInstance; | |||
| fixture.detectChanges(); | |||
| }); | |||
| it('should create', () => { | |||
| expect(component).toBeTruthy(); | |||
| }); | |||
| }); | |||
| @@ -1,29 +0,0 @@ | |||
| import {Component, Input, OnInit} from '@angular/core'; | |||
| @Component({ | |||
| selector: 'app-loan-edit-hint-card', | |||
| templateUrl: './hint-card.component.html', | |||
| styleUrls: ['./hint-card.component.scss'] | |||
| }) | |||
| export class HintCardComponent implements OnInit { | |||
| @Input() currentStep: string; | |||
| constructor() { } | |||
| ngOnInit(): void { | |||
| } | |||
| // tslint:disable-next-line:max-line-length | |||
| public thumbnailSrc = 'https://www.telerik.com/kendo-angular-ui-develop/components/layout/card/assets/rila.jpg'; | |||
| // tslint:disable-next-line:max-line-length | |||
| public cover = 'https://www.telerik.com/kendo-angular-ui-develop/components/layout/card/assets/black_sea.jpg'; | |||
| public liked = false; | |||
| public toggleLike(): void { | |||
| this.liked = !this.liked; | |||
| } | |||
| public heartIcon(): string { | |||
| return this.liked ? 'k-icon k-i-heart' : 'k-icon k-i-heart-outline'; | |||
| } | |||
| } | |||
| @@ -2,10 +2,6 @@ import { faChartArea, faIdCard, faIdCardAlt, faMoneyCheck, | |||
| faUniversity, faUserCircle, faUserTie } from '@fortawesome/free-solid-svg-icons'; | |||
| export const mainMenuItems: any[] = [ | |||
| { | |||
| text: '', | |||
| fa: faUniversity, | |||
| }, | |||
| { | |||
| text: 'SFM', | |||
| icon: 'more-vertical', | |||
| @@ -63,10 +59,7 @@ export const mainMenuItems: any[] = [ | |||
| export const brokerMenuItems: any[] = [ | |||
| { | |||
| text: '|', | |||
| fa: faUserTie, | |||
| }, | |||
| { | |||
| text: 'My Loans', | |||
| icon: 'categorize', | |||
| @@ -86,10 +79,6 @@ export const brokerMenuItems: any[] = [ | |||
| ]; | |||
| export const userMenuItems: any[] = [ | |||
| { | |||
| text: '|', | |||
| fa: faUserCircle, | |||
| }, | |||
| { | |||
| text: 'My Loans', | |||
| icon: 'categorize', | |||
| @@ -1,6 +1,8 @@ | |||
| // tslint:disable-next-line:class-name | |||
| import {PeopleModel} from './people.model'; | |||
| export class apiV1LoginResponse { | |||
| constructor( | |||
| @@ -8,7 +10,8 @@ export class apiV1LoginResponse { | |||
| public machineId: string, | |||
| public session: string, | |||
| public sessionExpire: number, // unix timestamp | |||
| public role: string | |||
| public role: string, | |||
| public user: PeopleModel | |||
| ) { | |||
| this.login = login; | |||
| this.machineId = machineId; | |||
| @@ -18,8 +21,7 @@ export class apiV1LoginResponse { | |||
| public static EmptyNew(): apiV1LoginResponse{ | |||
| return new apiV1LoginResponse( | |||
| false, '', '', 0, '' | |||
| ); | |||
| false, '', '', 0, '', PeopleModel.EmptyNew() ); | |||
| } | |||
| public hasValidSession(): boolean { | |||
| @@ -20,4 +20,9 @@ export class BrokerModel{ | |||
| public toPeopleModel(): PeopleModel{ | |||
| return new PeopleModel( this.Id, this.First, this.Last, this.Middle, this.Title, this.Display, this.Nick ); | |||
| } | |||
| public static EmptyNew(): BrokerModel { | |||
| return new BrokerModel('', '', '', '', '', '', '', | |||
| '', false, '', '', '', ''); | |||
| } | |||
| } | |||
| @@ -19,6 +19,10 @@ export class PeopleModel{ | |||
| return this.First + ' ' + this.Middle + ' ' + this.Last; | |||
| } | |||
| } | |||
| public static EmptyNew(): PeopleModel { | |||
| return new PeopleModel('', '', '', '', '', '', '' ); | |||
| } | |||
| } | |||
| @@ -2,6 +2,7 @@ import {EventEmitter, Injectable, OnDestroy, OnInit} from '@angular/core'; | |||
| import {HttpClient, HttpEvent, HttpHandler, HttpInterceptor, HttpParams, HttpRequest} from '@angular/common/http'; | |||
| import {apiV1LoginResponse} from '../models/api-v1-login-response'; | |||
| import {Router} from '@angular/router'; | |||
| import {PeopleModel} from '../models/people.model'; | |||
| @Injectable() | |||
| export class AuthService { | |||
| @@ -29,7 +30,10 @@ export class AuthService { | |||
| sfm.machineId, | |||
| sfm.session, | |||
| sfm.sessionExpire, | |||
| sfm.role | |||
| sfm.role, | |||
| new PeopleModel( | |||
| sfm.user.Id, sfm.user.First, sfm.user.Last, sfm.user.Middle, sfm.user.Title, sfm.user.Display, sfm.user.Nick | |||
| ) | |||
| ); | |||
| this.loginSuccess.emit(this.loggedIn); | |||
| // console.log ( 'auto login emit events', this.loggedIn); | |||
| @@ -58,6 +62,19 @@ export class AuthService { | |||
| this.loggedIn.machineId = responseData['Biukop-Mid']; | |||
| this.loggedIn.sessionExpire = responseData.sessionExpire; | |||
| this.loggedIn.role = responseData.role; | |||
| if ( responseData.user !== undefined) { | |||
| this.loggedIn.user = new PeopleModel( | |||
| responseData.user.Id, | |||
| responseData.user.First, | |||
| responseData.user.Last, | |||
| responseData.user.Middle, | |||
| responseData.user.Title, | |||
| responseData.user.Display, | |||
| responseData.user.Nick | |||
| ); | |||
| }else{ | |||
| this.loggedIn.user = PeopleModel.EmptyNew(); | |||
| } | |||
| this.saveSessionInfo(); | |||
| this.loginSuccess.emit(responseData); | |||
| }, | |||
| @@ -1,4 +1,10 @@ | |||
| <kendo-appbar id='topBar' *ngIf='login && showMenu' class='appbar' [position]="'top'" [positionMode]="'sticky'"> | |||
| <kendo-appbar-section *ngIf="LoggedInUser && LoggedInUser.Id !==''"> | |||
| <kendo-avatar [imageSrc]="loggedInUserAvatar()" [shape]="'circle'" [width]="'26px'" [height]="'26px'" (click)="logout()"></kendo-avatar> | |||
| <span>{{LoggedInUser.Display}}</span> | |||
| </kendo-appbar-section> | |||
| <span class="k-appbar-separator"></span> | |||
| <kendo-appbar-section> | |||
| <kendo-menu [items]="items" (select)="onSelect($event)"> | |||
| <ng-template kendoMenuItemTemplate let-item="item"> | |||
| @@ -8,6 +14,10 @@ | |||
| </ng-template> | |||
| </kendo-menu> | |||
| </kendo-appbar-section> | |||
| <kendo-appbar-spacer></kendo-appbar-spacer> | |||
| <kendo-appbar-section class="actions"> | |||
| <kendo-badge-container *ngIf="false"> | |||
| @@ -19,6 +29,8 @@ | |||
| <span class="k-appbar-separator"></span> | |||
| </kendo-appbar-section> | |||
| <kendo-appbar-section> | |||
| <kendo-avatar [imageSrc]="Avatar" [shape]="'circle'" [width]="'26px'" [height]="'26px'" (click)="logout()"></kendo-avatar> | |||
| </kendo-appbar-section> | |||
| @@ -4,6 +4,7 @@ import {AuthService} from '../service/auth.service'; | |||
| import {brokerMenuItems, mainMenuItems, peopleMenuItems, userMenuItems} from '../main-menu-items'; | |||
| import {apiV1LoginResponse} from '../models/api-v1-login-response'; | |||
| import {Subscription} from 'rxjs'; | |||
| import {PeopleModel} from '../models/people.model'; | |||
| @Component({ | |||
| @@ -13,11 +14,13 @@ import {Subscription} from 'rxjs'; | |||
| }) | |||
| export class TopBarComponent implements OnInit , OnDestroy { | |||
| login = false; | |||
| public LoggedInUser: PeopleModel; | |||
| Avatar = './assets/img/logout.png'; | |||
| public items: any[] = mainMenuItems; | |||
| private loginSub: Subscription; | |||
| public showMenu = true; | |||
| public showMenu = true; | |||
| public opened = false; | |||
| constructor(private menuService: MenuService, | |||
| @@ -30,11 +33,14 @@ export class TopBarComponent implements OnInit , OnDestroy { | |||
| public initAndSubLogin(): void{ | |||
| this.login = this.authService.loggedIn.login; | |||
| this.LoggedInUser = this.authService.loggedIn.user; | |||
| console.log(this); | |||
| this.selectMenuShow(this.authService.loggedIn.role); | |||
| // console.log('subscribe auto login', this.authService.loggedIn); | |||
| this.loginSub = this.authService.loginSuccess.subscribe( | |||
| (rsp: apiV1LoginResponse) => { | |||
| this.login = rsp.login; | |||
| this.LoggedInUser = this.authService.loggedIn.user; | |||
| this.selectMenuShow(rsp.role); | |||
| console.log ('topbar received auth events', rsp); | |||
| } | |||
| @@ -82,8 +88,7 @@ export class TopBarComponent implements OnInit , OnDestroy { | |||
| } | |||
| } | |||
| // tslint:disable-next-line:typedef | |||
| ngOnDestroy() { | |||
| ngOnDestroy(): void { | |||
| this.loginSub.unsubscribe(); | |||
| } | |||
| @@ -97,4 +102,9 @@ export class TopBarComponent implements OnInit , OnDestroy { | |||
| this.authService.logout(); | |||
| } | |||
| } | |||
| public loggedInUserAvatar(): string { | |||
| return this.authService.getUrl('avatar/') + this.authService.loggedIn.user.Id; | |||
| } | |||
| } | |||