diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index 5f59f22..cebffca 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -24,6 +24,8 @@ import {PeopleAddComponent} from './people-add/people-add.component';
import {SettingsComponent} from './settings/settings.component';
import {ProfileComponent} from './profile/profile.component';
import {ListAllPeopleComponent} from './list-all-people/list-all-people.component';
+import {ListIncomeComponent} from './list-income/list-income.component';
+import {UploadDetailComponent} from './upload-detail/upload-detail.component';
const routes: Routes = [
@@ -54,7 +56,9 @@ const routes: Routes = [
{path : 'people-add', component: PeopleAddComponent, canActivate: [AuthGuard] },
{path : 'profile', component: ProfileComponent, canActivate: [AuthGuard] },
{path : 'profile/:id', component: ProfileComponent, canActivate: [AuthGuard] },
- {path : 'e403', component: E403Component, },
+ {path : 'upload-details/:id', component: UploadDetailComponent, canActivate: [AuthGuard] },
+ {path : 'list-income', component: ListIncomeComponent, canActivate: [AuthGuard] },
+ {path : 'e403', component: E403Component },
];
@NgModule({
diff --git a/src/app/app.component.scss b/src/app/app.component.scss
index 5446797..0e67a0e 100644
--- a/src/app/app.component.scss
+++ b/src/app/app.component.scss
@@ -25,16 +25,21 @@
}
#topBar .main-menu-item , #topBar .k-icon, #topBar .k-menu-item {
- color:black !important;
+ color:black !important;
}
.k-menu:not(.k-context-menu) > .k-item > .k-state-active {
- font-weight: bold;
- background-color: lightblue;
+ font-weight: bold;
+ background-color: lightblue;
}
.k-popup.k-menu-popup .k-menu-item:hover {
color: black;
- font-weight: bold;
- background-color: lightblue;
+ font-weight: bold;
+ background-color: lightblue;
+}
+
+
+.upload-details div[role="tabpanel"]{
+ padding:0px;
}
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 1ede24a..5c8736d 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -88,6 +88,11 @@ import { AdminProfileComponent } from './profile/admin-profile/admin-profile.com
import { ChangePasswordComponent } from './profile/change-password/change-password.component';
import { ProgressBarModule } from '@progress/kendo-angular-progressbar';
import { PagerModule } from '@progress/kendo-angular-pager';
+import { ListIncomeComponent } from './list-income/list-income.component';
+import { UploadCardsComponent } from './upload-cards/upload-cards.component';
+import {UploadInterceptor} from './lender-uploads/upload-status.interceptor';
+import { UploadDetailComponent } from './upload-detail/upload-detail.component';
+import {SafeUrlPipe} from './pipe/safe.url.pipe';
@@ -146,7 +151,11 @@ import { PagerModule } from '@progress/kendo-angular-pager';
MessageBoxComponent,
UserProfileComponent,
AdminProfileComponent,
- ChangePasswordComponent
+ ChangePasswordComponent,
+ ListIncomeComponent,
+ UploadCardsComponent,
+ UploadDetailComponent,
+ SafeUrlPipe
],
imports: [
BrowserModule,
@@ -193,6 +202,11 @@ import { PagerModule } from '@progress/kendo-angular-pager';
provide: HTTP_INTERCEPTORS,
useClass: AuthHttpInterceptor,
multi: true
+ },
+ {
+ provide: HTTP_INTERCEPTORS,
+ useClass: UploadInterceptor,
+ multi: true
}
],
bootstrap: [AppComponent]
diff --git a/src/app/lender-uploads/lender-uploads.component.html b/src/app/lender-uploads/lender-uploads.component.html
index 34551fa..fdf3839 100644
--- a/src/app/lender-uploads/lender-uploads.component.html
+++ b/src/app/lender-uploads/lender-uploads.component.html
@@ -1 +1,43 @@
-
lender-uploads works!
+
+
+
+
+
+
+
Name: {{ files[0].name }}
+
Cannot upload this file {{files[0]}}
+
fuck all {{map.get(files[0].uid).response.body.Funder}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/app/lender-uploads/lender-uploads.component.scss b/src/app/lender-uploads/lender-uploads.component.scss
index e69de29..e898e2d 100644
--- a/src/app/lender-uploads/lender-uploads.component.scss
+++ b/src/app/lender-uploads/lender-uploads.component.scss
@@ -0,0 +1,68 @@
+div.workarea{
+ height: calc(100vh - 48px);
+ position:relative;
+ background-color: #46495b;
+}
+
+div.file-manager-bar{
+ position: relative;
+ height: 48px;
+ div.upload-area{
+ width: 60%;
+ display: inline-block;
+ position:absolute;
+ }
+
+ div.search-area{
+ position:absolute;
+ right:0;
+ top:0;
+ width: 40%;
+ display: inline-block;
+ height: 48px;
+ background-color:grey;
+ border-left: 5px solid darkgrey;
+ border-right: 5px solid darkgrey;
+ .search-people{
+ width: 100%;
+ bottom: 0px;
+ position: absolute;
+ height: 100%;
+ border:0px;
+ padding-right: 48px;
+ padding-left: 10px;
+ background-color: lightgoldenrodyellow;
+ }
+ .search-people:focus {
+ outline:none;
+ border:0px;
+ }
+ kendo-icon{
+ position: absolute;
+ right:10px;
+ margin: 5px;
+ color: lightgrey;
+ }
+ kendo-icon:hover{
+ color: darkgreen;
+ }
+ }
+
+ .contact-image {
+ width: 22px;
+ height: 22px;
+ margin-right: 8px;
+ border-radius: 50%;
+ }
+
+}
+
+.vertical-spacer{
+ height: 150px;
+}
+
+.bottom-pager {
+ position: fixed;
+ bottom: 0px;
+}
+
diff --git a/src/app/lender-uploads/lender-uploads.component.ts b/src/app/lender-uploads/lender-uploads.component.ts
index b0441da..25c53a3 100644
--- a/src/app/lender-uploads/lender-uploads.component.ts
+++ b/src/app/lender-uploads/lender-uploads.component.ts
@@ -1,15 +1,105 @@
-import { Component, OnInit } from '@angular/core';
+import {AfterViewInit, Component, ElementRef, EventEmitter, OnInit, Output, ViewChild, ViewEncapsulation} from '@angular/core';
+import {FileInfo, FileRestrictions, SuccessEvent, UploadComponent, UploadEvent, UploadProgressEvent} from '@progress/kendo-angular-upload';
+import {AuthService} from '../service/auth.service';
+import {range} from '@progress/kendo-angular-dateinputs/dist/es2015/util';
+import {Router} from '@angular/router';
+import {PageChangeEvent} from '@progress/kendo-angular-pager';
@Component({
selector: 'app-lender-uploads',
templateUrl: './lender-uploads.component.html',
- styleUrls: ['./lender-uploads.component.scss']
+ styleUrls: ['./lender-uploads.component.scss'],
})
export class LenderUploadsComponent implements OnInit {
+ @Output() success: EventEmitter = new EventEmitter();
+ @Output() click: EventEmitter = new EventEmitter();
+ @Output() complete: EventEmitter = new EventEmitter();
+ @Output() upload: EventEmitter = new EventEmitter();
+
+
+ private uploads: SuccessEvent[] = [];
+ public value = 0 ;
+ public map: Map = new Map();
+
+ uploadSaveUrl = 'https://svr2021.lawipac.com:8080/api/v1/lender-upload/'; // should represent an actual API endpoint
+ uploadRemoveUrl = 'https://svr2021.lawipac.com:8080/api/v1/lender-upload-remove/'; // should represent an actual API endpoint
+
+ public allUploads = [...range(30, 44 )];
+ public displayedUploads: any[] = [];
+ public filteredUploads: any[] = [];
+
+
+ public skip = 0;
+ public pageSize = 12;
+ public total = 0;
+
+ myRestrictions: FileRestrictions = {
+ allowedExtensions: ['.pdf', '.xls', '.xlsx']
+ };
+
+ constructor(private auth: AuthService, private router: Router) {
+ }
- constructor() { }
ngOnInit(): void {
+ this.uploadSaveUrl = this.auth.getUrl('lender-upload/');
+ this.uploadRemoveUrl = this.auth.getUrl('lender-upload-remove/');
+ this.loadDisplayedUploads();
+ }
+
+
+
+ public onClick( files: any): void{
+ this.click.emit(files[0]);
+ }
+
+ public onSuccess(ss: SuccessEvent ): void {
+ this.uploads.push(ss);
+ this.map.set(ss.files[0].uid, ss);
+ this.success.emit(ss);
+ this.allUploads.unshift(this.allUploads.length + 100);
}
+ public onUpload(ss: UploadEvent ): void {
+ this.upload.emit(true);
+ }
+
+ public onComplete(): void {
+ this.upload.emit(false);
+ }
+
+ public hasResp(uid): boolean {
+ let found = false;
+ this.uploads.every(v => {
+ if ( v.files[0].uid === uid ) {
+ found = true;
+ return false; // stop search
+ }
+ });
+ return found;
+ }
+
+ public uploadProgress(prog: UploadProgressEvent): void {
+ this.value = prog.percentComplete.valueOf();
+ }
+ public show( i: number): void{
+ this.router.navigate(['/upload-details/' + i]);
+ }
+
+
+ public onPageChange(e: PageChangeEvent): void {
+ this.skip = e.skip;
+ this.pageSize = e.take;
+ this.loadDisplayedUploads();
+ }
+
+ private loadDisplayedUploads(): void {
+ this.filteredUploads = this.allUploads ;
+ this.displayedUploads = this.filteredUploads.slice(this.skip, this.skip + this.pageSize);
+ this.total = this.displayedUploads.length;
+ }
+
+ public onFilterUploads(hint: string): void {
+ this.loadDisplayedUploads();
+ }
}
diff --git a/src/app/lender-uploads/upload-status.interceptor.ts b/src/app/lender-uploads/upload-status.interceptor.ts
new file mode 100644
index 0000000..e565962
--- /dev/null
+++ b/src/app/lender-uploads/upload-status.interceptor.ts
@@ -0,0 +1,34 @@
+import { Injectable } from '@angular/core';
+import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpProgressEvent, HttpEventType, HttpResponse } from '@angular/common/http';
+import { Observable, of, concat } from 'rxjs';
+import {AuthService} from '../service/auth.service';
+import {delay, tap} from 'rxjs/operators';
+
+/*
+ Mocked backend service.
+ For further details, check
+ https://angular.io/guide/http#writing-an-interceptor
+*/
+
+@Injectable()
+export class UploadInterceptor implements HttpInterceptor {
+ constructor(private auth: AuthService){}
+ intercept(req: HttpRequest, next: HttpHandler): Observable> {
+ if (req.url === this.auth.getUrl('lender-upload')) {
+ return next.handle(req).pipe(
+ tap(event => {
+ // console.log(event);
+ if (event.type === HttpEventType.UploadProgress){
+ console.log('progress', event);
+ }
+ })
+ );
+ }
+
+ if (req.url === this.auth.getUrl('lender-upload-remove')) {
+ // ok, not processng anything
+ console.log('lender-upload-remove');
+ }
+ return next.handle(req);
+ }
+}
diff --git a/src/app/list-all-people/list-all-people.component.scss b/src/app/list-all-people/list-all-people.component.scss
index a51a349..6a6d1f9 100644
--- a/src/app/list-all-people/list-all-people.component.scss
+++ b/src/app/list-all-people/list-all-people.component.scss
@@ -1,6 +1,7 @@
div.workarea{
height: calc(100vh - 48px);
position:relative;
+ background-color: #46495b;
}
kendo-multicolumncombobox{
diff --git a/src/app/list-all-people/list-all-people.component.ts b/src/app/list-all-people/list-all-people.component.ts
index e5dd2e5..895acf8 100644
--- a/src/app/list-all-people/list-all-people.component.ts
+++ b/src/app/list-all-people/list-all-people.component.ts
@@ -1,15 +1,14 @@
-import {Component, OnInit, ViewChild} from '@angular/core';
-import {PeopleModel, RelevantPeopleModel} from '../models/people.model';
+import {Component, OnInit, ViewEncapsulation} from '@angular/core';
+import {PeopleModel} from '../models/people.model';
import {PeopleService} from '../service/people.service';
import {AuthService} from '../service/auth.service';
import {ClonerService} from '../service/clone.service';
-import {ComboBoxComponent, PopupSettings, VirtualizationSettings} from '@progress/kendo-angular-dropdowns';
-import { PageChangeEvent } from '@progress/kendo-angular-pager';
+import {PageChangeEvent} from '@progress/kendo-angular-pager';
@Component({
selector: 'app-list-all-people',
templateUrl: './list-all-people.component.html',
- styleUrls: ['./list-all-people.component.scss']
+ styleUrls: ['./list-all-people.component.scss'],
})
export class ListAllPeopleComponent implements OnInit {
diff --git a/src/app/list-all-rewards/list-all-rewards.component.scss b/src/app/list-all-rewards/list-all-rewards.component.scss
index a0aebbc..409d76a 100644
--- a/src/app/list-all-rewards/list-all-rewards.component.scss
+++ b/src/app/list-all-rewards/list-all-rewards.component.scss
@@ -7,6 +7,7 @@
kendo-grid{
flex: 0 1 auto;
+ height: 100%;
}
diff --git a/src/app/list-income/list-income.component.html b/src/app/list-income/list-income.component.html
new file mode 100644
index 0000000..4b9a1fb
--- /dev/null
+++ b/src/app/list-income/list-income.component.html
@@ -0,0 +1,37 @@
+
+
+
+
+
+
Outer splitter / Middle pane
+
Resizable only.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Type: {{u.files[0].extension}}
+ Name: {{u.files[0].name}}
+ Funder: Name: {{u.response.body.Funder}}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/app/list-income/list-income.component.scss b/src/app/list-income/list-income.component.scss
new file mode 100644
index 0000000..e7d3929
--- /dev/null
+++ b/src/app/list-income/list-income.component.scss
@@ -0,0 +1,7 @@
+div.income-container {
+ height: calc(100vh - 48px);
+}
+
+div.pane-content{
+ height:100%;
+}
diff --git a/src/app/list-income/list-income.component.spec.ts b/src/app/list-income/list-income.component.spec.ts
new file mode 100644
index 0000000..f7f8382
--- /dev/null
+++ b/src/app/list-income/list-income.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ListIncomeComponent } from './list-income.component';
+
+describe('ListIncomeComponent', () => {
+ let component: ListIncomeComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ ListIncomeComponent ]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ListIncomeComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/list-income/list-income.component.ts b/src/app/list-income/list-income.component.ts
new file mode 100644
index 0000000..0ed3a87
--- /dev/null
+++ b/src/app/list-income/list-income.component.ts
@@ -0,0 +1,21 @@
+import { Component, OnInit } from '@angular/core';
+import {SuccessEvent} from '@progress/kendo-angular-upload';
+
+@Component({
+ selector: 'app-list-income',
+ templateUrl: './list-income.component.html',
+ styleUrls: ['./list-income.component.scss']
+})
+export class ListIncomeComponent implements OnInit {
+ public uploads: SuccessEvent[] = [];
+
+ constructor() { }
+
+ ngOnInit(): void {
+ }
+
+ public onSuccess(e: SuccessEvent): void {
+ this.uploads.push (e);
+ console.log(e);
+ }
+}
diff --git a/src/app/loan-edit/trail-income/trail-income.component.ts b/src/app/loan-edit/trail-income/trail-income.component.ts
index 441e49b..770b76d 100644
--- a/src/app/loan-edit/trail-income/trail-income.component.ts
+++ b/src/app/loan-edit/trail-income/trail-income.component.ts
@@ -47,7 +47,7 @@ export class TrailIncomeComponent implements OnInit {
let balance = -1;
let offsetBalance = -1;
if ( this.Loan.PayIn.length > 0) {
- const idx = this.Loan.PayIn.length -1;
+ const idx = this.Loan.PayIn.length - 1;
balance = this.Loan.PayIn[idx].Balance;
offsetBalance = this.Loan.PayIn[idx].OffsetBalance;
}
@@ -60,7 +60,7 @@ export class TrailIncomeComponent implements OnInit {
Trail: 168,
Ts: new Date(),
Balance: balance,
- OffsetBalance: offsetBalance
+ OffsetBalance: offsetBalance,
});
sender.addRow(this.formGroup);
@@ -98,19 +98,19 @@ export class TrailIncomeComponent implements OnInit {
if ( !this.showBalance) { v.Balance = -1; }
if ( !this.showOffsetBalance) { v.OffsetBalance = -1; }
- const pi = new PayInModel(
- v.Id,
- this.Loan.Amount,
- v.Balance,
- this.Loan.Lender,
- this.Loan.Id,
- this.Loan.LenderLoanNumber,
- v.OffsetBalance,
- this.Loan.Settlement,
- v.Trail,
- v.Ts,
- 0,
- );
+ const pi = new PayInModel({});
+ pi.Id = v.Id;
+ pi.Amount = this.Loan.Amount;
+ pi.Balance = v.Balance;
+ pi.Lender = this.Loan.Lender;
+ pi.LoanId = this.Loan.Id;
+ pi.LoanNumber = this.Loan.LenderLoanNumber;
+ pi.OffsetBalance = v.OffsetBalance;
+ pi.Settlement = this.Loan.Settlement;
+ pi.Trail = v.Trail;
+ pi.Ts = new Date(v.Ts);
+ pi.UploadId = v.UploadId;
+
console.log('saving PayIn', pi);
this.ls.savePayIn(pi, isNew).subscribe(
@@ -152,7 +152,7 @@ export class TrailIncomeComponent implements OnInit {
}
public visitUploads(pi: PayInModel): void {
- this.router.navigate(['./uploads/' + pi.Uploads]);
+ this.router.navigate(['./uploads/' + pi.UploadId]);
}
}
diff --git a/src/app/main-menu-items.ts b/src/app/main-menu-items.ts
index 27fe433..035fabf 100644
--- a/src/app/main-menu-items.ts
+++ b/src/app/main-menu-items.ts
@@ -23,6 +23,8 @@ export const mainMenuItems: any[] = [
{ text: 'Income', icon: 'dollar', url: './#pay-in' },
{ text: '--', separator: 'true' },
{ text: 'Uploads', icon: 'dollar', url: './#lender-uploads' },
+ { text: 'Uploads by Id', icon: 'dollar', url: './#upload-details/30' },
+ { text: 'list income', icon: 'dollar', url: './#list-income' },
]
},
{
diff --git a/src/app/models/Pay.In.AAA.Row.model.ts b/src/app/models/Pay.In.AAA.Row.model.ts
new file mode 100644
index 0000000..49a5ace
--- /dev/null
+++ b/src/app/models/Pay.In.AAA.Row.model.ts
@@ -0,0 +1,18 @@
+
+
+export class PayInAAARowModel {
+
+ public LoanNumber: string;
+ public Settlement: Date;
+ public LoanAmount: number;
+ public Balance: number;
+ public InTrail: number;
+
+ constructor(payload: Partial){
+ this.LoanNumber = payload.LoanNumber || '';
+ this.Settlement = new Date(payload.Settlement);
+ this.LoanAmount = payload.LoanAmount || 0;
+ this.Balance = payload.Balance || 0;
+ this.InTrail = payload.InTrail || 0;
+ }
+}
diff --git a/src/app/models/funder.aaa.trail.model.ts b/src/app/models/funder.aaa.trail.model.ts
new file mode 100644
index 0000000..820411f
--- /dev/null
+++ b/src/app/models/funder.aaa.trail.model.ts
@@ -0,0 +1,15 @@
+import {PayInAAARowModel} from './Pay.In.AAA.Row.model';
+
+export class FunderAaaTrailModel{
+ public Period: Date; // valid only year, and month
+ public Rows: PayInAAARowModel[];
+ constructor(payload: Partial) {
+ this.Period = new Date(payload.Period);
+ this.Rows = [];
+ if ( payload.Rows ){
+ payload.Rows.forEach( v => {
+ this.Rows.push (new PayInAAARowModel(v));
+ });
+ }
+ }
+}
diff --git a/src/app/models/loan.model.ts b/src/app/models/loan.model.ts
index 8c8fa03..c92d126 100644
--- a/src/app/models/loan.model.ts
+++ b/src/app/models/loan.model.ts
@@ -89,19 +89,7 @@ export class LoanModel {
private setPayIn(v: any[]): void{
this.PayIn = [];
v.forEach( pi =>{
- this.PayIn.push(new PayInModel(
- pi.Id,
- pi.Amount,
- pi.Balance,
- pi.Lender,
- pi.LoanId,
- pi.LoanNumber,
- pi.OffsetBalance,
- new Date(pi.Settlement),
- pi.Trail,
- new Date(pi.Ts),
- pi.Uploads,
- ));
+ this.PayIn.push(new PayInModel(pi));
});
}
@@ -111,19 +99,7 @@ export class LoanModel {
const na = this.PayIn.filter(v => v.Id !== pi.Id );
// add the incoming one
na.unshift(
- new PayInModel(
- pi.Id,
- pi.Amount,
- pi.Balance,
- pi.Lender,
- pi.LoanId,
- pi.LoanNumber,
- pi.OffsetBalance,
- new Date(pi.Settlement),
- pi.Trail,
- new Date(pi.Ts),
- pi.Uploads,
- )
+ new PayInModel(pi)
);
// update array element
this.PayIn = na;
diff --git a/src/app/models/pay-in.model.ts b/src/app/models/pay-in.model.ts
index a49a568..e8be8d1 100644
--- a/src/app/models/pay-in.model.ts
+++ b/src/app/models/pay-in.model.ts
@@ -1,16 +1,30 @@
export class PayInModel {
- constructor(
- public Id: number,
- public Amount: number,
- public Balance: number,
- public Lender: string,
- public LoanId: string,
- public LoanNumber: string,
- public OffsetBalance: number,
- public Settlement: Date,
- public Trail: number,
- public Ts: Date,
- public Uploads: number
- ){}
+ public Id: number;
+ public Amount: number;
+ public Balance: number;
+ public Lender: string;
+ public LoanId: string;
+ public LoanNumber: string;
+ public OffsetBalance: number;
+ public Settlement: Date;
+ public Trail: number;
+ public Ts: Date;
+ public UploadId: number;
+ constructor(payload: Partial){
+ if ( payload === null ) {
+ payload = {};
+ }
+ this.Id = payload.Id || 0;
+ this.Amount = payload.Amount || 0;
+ this.Balance = payload.Balance || 0;
+ this.Lender = payload.Lender || '';
+ this.LoanId = payload.LoanId || '' ;
+ this.LoanNumber = payload.LoanNumber || '';
+ this.OffsetBalance = payload.OffsetBalance || 0;
+ this.Settlement = new Date(payload.Settlement);
+ this.Trail = payload.Trail || 0 ;
+ this.Ts = new Date(payload.Ts);
+ this.UploadId = payload.UploadId;
+ }
}
diff --git a/src/app/models/upload.analysis.model.ts b/src/app/models/upload.analysis.model.ts
new file mode 100644
index 0000000..1514f1d
--- /dev/null
+++ b/src/app/models/upload.analysis.model.ts
@@ -0,0 +1,50 @@
+import {UploadModel} from './upload.model';
+import {PayInModel} from './pay-in.model';
+import {FunderAaaTrailModel} from './funder.aaa.trail.model';
+import {PayInAAARowModel} from './Pay.In.AAA.Row.model';
+
+export class UploadAnalysisModel {
+ public Id: number;
+ public Funder: string;
+ public Mime: string;
+ public PayIn: PayInModel[];
+
+ public AAA?: FunderAaaTrailModel[];
+
+ public IsDuplicate: boolean;
+ public Uid?: string; // client side unique id when upload
+ public Upload?: UploadModel;
+
+ constructor(payload: Partial){
+ this.Id = payload.Id || 0 ;
+ this.Funder = payload.Funder || '';
+ this.Mime = payload.Mime || '';
+ if ( payload.PayIn && payload.PayIn.length > 0 ) {
+ this.PayIn = [];
+ }else{
+ this.PayIn = [];
+ if ( payload.PayIn ) {
+ payload.PayIn.forEach(
+ v => {
+ const pi = new PayInModel(v);
+ this.PayIn.push(pi);
+ }
+ );
+ }
+ }
+
+ this.AAA = [];
+ if ( payload.AAA ) {
+
+ payload.AAA.forEach( v => {
+ const r = new FunderAaaTrailModel(v);
+ this.AAA.push(r);
+ });
+ }
+
+ this.IsDuplicate = payload.IsDuplicate || false;
+ this.Uid = payload.Uid || '' ;
+ this.Upload = new UploadModel(payload.Upload || {});
+ }
+
+}
diff --git a/src/app/models/upload.model.ts b/src/app/models/upload.model.ts
new file mode 100644
index 0000000..0cb33f1
--- /dev/null
+++ b/src/app/models/upload.model.ts
@@ -0,0 +1,22 @@
+
+export class UploadModel {
+ public Id: number;
+ public Mime: string;
+ public FileName: string;
+ public Ts: Date;
+ public By: string;
+ public LastModified: Date;
+ public Size: number;
+ public Sha256: string;
+
+ constructor(payload: Partial) {
+ this.Id = payload.Id || 0;
+ this.Mime = payload.Mime || '';
+ this.FileName = payload.FileName || '';
+ this.Ts = new Date (payload.Ts || new Date());
+ this.By = payload.By || '';
+ this.LastModified = new Date(payload.LastModified || new Date());
+ this.Size = payload.Size || 0;
+ this.Sha256 = payload.Sha256 || '';
+ }
+}
diff --git a/src/app/pay-in/pay-in.component.html b/src/app/pay-in/pay-in.component.html
index b25a474..b3e760a 100644
--- a/src/app/pay-in/pay-in.component.html
+++ b/src/app/pay-in/pay-in.component.html
@@ -1 +1,91 @@
-pay-in works!
+
+
+
+ Show Uploads
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ dataItem.Ts | date: 'yyyy-MM-dd' }}
+
+
+
+
+
+ =0 "> {{ dataItem.Balance | currency}}
+ unknown
+
+
+
+ =0"
+ name="showBalance" [(ngModel)]="showBalance"
+ ngModelOptions="{standalone: true}"
+ [onLabel]="'Yes'"
+ [offLabel]="'No'"
+ >
+
+
+
+
+
+
+
+
+
+
+
+ =0 "> {{ dataItem.OffsetBalance | currency}}
+ unknown
+
+
+
+ =0"
+ name="showOffsetBalance" [(ngModel)]="showOffsetBalance"
+ ngModelOptions="{standalone: true}"
+ [onLabel]="'Yes'"
+ [offLabel]="'No'"
+ >
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
diff --git a/src/app/pay-in/pay-in.component.scss b/src/app/pay-in/pay-in.component.scss
index e69de29..ba606f0 100644
--- a/src/app/pay-in/pay-in.component.scss
+++ b/src/app/pay-in/pay-in.component.scss
@@ -0,0 +1,9 @@
+kendo-grid {
+ height: calc(100vh - 48px);
+}
+
+.balance {
+ display: inline-block;
+ margin-left: 0px !important;
+ width: calc(100% - 60px) !important;
+}
diff --git a/src/app/pay-in/pay-in.component.ts b/src/app/pay-in/pay-in.component.ts
index bf22de7..6c28fa2 100644
--- a/src/app/pay-in/pay-in.component.ts
+++ b/src/app/pay-in/pay-in.component.ts
@@ -1,4 +1,15 @@
-import { Component, OnInit } from '@angular/core';
+import {Component, Input, OnInit} from '@angular/core';
+import {PayInModel} from '../models/pay-in.model';
+import {FormControl, FormGroup, Validators} from '@angular/forms';
+
+const createFormGroup = dataItem => new FormGroup({
+ Id: new FormControl({value: dataItem.Id, disabled: true}, Validators.required),
+ Trail : new FormControl(dataItem.Trail, Validators.required),
+ Ts: new FormControl(dataItem.Ts, Validators.required),
+ Balance: new FormControl(dataItem.Balance, Validators.required),
+ OffsetBalance: new FormControl(dataItem.OffsetBalance, Validators.required),
+});
+
@Component({
selector: 'app-pay-in',
@@ -6,10 +17,122 @@ import { Component, OnInit } from '@angular/core';
styleUrls: ['./pay-in.component.scss']
})
export class PayInComponent implements OnInit {
+ @Input() public AllPayIn: PayInModel[] = [];
+ public formGroup: FormGroup;
+ private editedRowIndex: number;
+
+ public trailIncome: FormGroup;
+ public showBalance = true;
+ public showOffsetBalance = true;
+
+ public splitButtonItems: Array = [{
+ text: 'Keep Text Only',
+ icon: 'paste-plain-text',
+ click: () => { console.log('Keep Text Only click handler'); }
+ }, {
+ text: 'Paste as HTML',
+ icon: 'paste-as-html'
+ }, {
+ text: 'Paste Markdown',
+ icon: 'paste-markdown'
+ }, {
+ text: 'Set Default Paste'
+ }];
constructor() { }
ngOnInit(): void {
}
+
+ public addHandler({ sender }): void {
+ this.closeEditor(sender);
+
+ let balance = -1;
+ let offsetBalance = -1;
+ // if ( this.Loan.PayIn.length > 0) {
+ // const idx = this.Loan.PayIn.length -1;
+ // balance = this.Loan.PayIn[idx].Balance;
+ // offsetBalance = this.Loan.PayIn[idx].OffsetBalance;
+ // }
+
+ // this.showBalance = balance >= 0 ;
+ // this.showOffsetBalance = offsetBalance >= 0 ;
+
+ this.formGroup = createFormGroup({
+ Id: 0,
+ Trail: 168,
+ Ts: new Date(),
+ Balance: balance,
+ OffsetBalance: offsetBalance
+ });
+
+ sender.addRow(this.formGroup);
+ }
+
+ public editHandler({ sender, rowIndex, dataItem }): void {
+ this.closeEditor(sender);
+
+ this.showBalance = dataItem.Balance >= 0 ;
+ this.showOffsetBalance = dataItem.OffsetBalance >= 0 ;
+ this.formGroup = createFormGroup(dataItem);
+ this.editedRowIndex = rowIndex;
+ sender.editRow(rowIndex, this.formGroup);
+
+ }
+
+ public cancelHandler({ sender, rowIndex }): void {
+ console.log(sender);
+ this.closeEditor(sender, rowIndex);
+ }
+
+ public saveHandler({ sender, rowIndex, formGroup, isNew }): void {
+ const v = formGroup.getRawValue();
+
+ if ( !this.showBalance) { v.Balance = -1; }
+ if ( !this.showOffsetBalance) { v.OffsetBalance = -1; }
+
+ // const pi = new PayInModel(
+ // v.Id,
+ // this.Loan.Amount,
+ // v.Balance,
+ // this.Loan.Lender,
+ // this.Loan.Id,
+ // this.Loan.LenderLoanNumber,
+ // v.OffsetBalance,
+ // this.Loan.Settlement,
+ // v.Trail,
+ // v.Ts,
+ // 0,
+ // );
+
+ //console.log('saving PayIn', pi);
+ // this.ls.savePayIn(pi, isNew).subscribe(
+ // (resp: PayInModel) => {
+ // this.Loan.cuPayIn(resp);
+ // },
+ // err => {
+ // this.errorOccurred.emit('Error saving Income');
+ // }
+ // );
+
+ sender.closeRow(rowIndex);
+ }
+
+ public removeHandler({ dataItem }): void {
+ console.log(dataItem);
+
+ // const na = this.Loan.PayIn.filter(v => {
+ // return v.Id !== dataItem.Id;
+ // });
+ //
+ // this.Loan.PayIn = na;
+ // this.ls.removePayIn(dataItem.Id);
+ }
+
+ private closeEditor(grid, rowIndex = this.editedRowIndex): void{
+ grid.closeRow(rowIndex);
+ this.editedRowIndex = undefined;
+ this.formGroup = undefined;
+ }
}
diff --git a/src/app/pipe/safe.url.pipe.ts b/src/app/pipe/safe.url.pipe.ts
new file mode 100644
index 0000000..38188f8
--- /dev/null
+++ b/src/app/pipe/safe.url.pipe.ts
@@ -0,0 +1,14 @@
+import { Pipe, PipeTransform } from '@angular/core';
+import {DomSanitizer, SafeResourceUrl} from '@angular/platform-browser';
+
+@Pipe({
+ name: 'safeUrl'
+})
+export class SafeUrlPipe implements PipeTransform {
+
+ constructor(private sanitizer: DomSanitizer) { }
+ public transform(url): SafeResourceUrl {
+ return this.sanitizer.bypassSecurityTrustResourceUrl(url);
+ }
+
+}
diff --git a/src/app/service/upload.attach.service.ts b/src/app/service/upload.attach.service.ts
new file mode 100644
index 0000000..a5c58f0
--- /dev/null
+++ b/src/app/service/upload.attach.service.ts
@@ -0,0 +1,38 @@
+import {Injectable} from '@angular/core';
+import {HttpClient} from '@angular/common/http';
+import {AuthService} from './auth.service';
+import {Observable} from 'rxjs';
+import {UploadModel} from '../models/upload.model';
+import {UploadAnalysisModel} from '../models/upload.analysis.model';
+
+
+@Injectable({providedIn: 'root'})
+export class UploadAttachService {
+ constructor(private http: HttpClient, private auth: AuthService) {
+ }
+
+ public getUploadMeta(id: number): Observable {
+ return this.http.get(this.auth.getUrl('upload-meta/' + id));
+ }
+
+ public getUploadAnalysis(id: number): Observable {
+ return this.http.get(this.auth.getUrl('upload-analysis/' + id));
+ }
+
+ public getUploadAsJpgUrl(id: number): string {
+ return this.auth.getUrl('upload-as-image/' + id);
+ }
+
+ public getUploadAsPdfUrl(id: number): string {
+ const ts = Date.now();
+ return this.auth.getUrl('upload-as-pdf/' + id + '?date=' + ts);
+ }
+ public getUploadAsPdfUrlForDownload(id: number): string {
+ return this.auth.getUrl('upload-as-pdf/' + id + '?download=force');
+ }
+
+ public getUploadAsThumbnailUrl(id: number): string {
+ return this.auth.getUrl('upload-as-thumbnail/' + id );
+ }
+
+}
diff --git a/src/app/upload-cards/upload-cards.component.html b/src/app/upload-cards/upload-cards.component.html
new file mode 100644
index 0000000..18ec02e
--- /dev/null
+++ b/src/app/upload-cards/upload-cards.component.html
@@ -0,0 +1,25 @@
+
+
+
+
+
+
card.headerTitle
+
card.headerSubtitle
+
+
+
+ upload-cards works!
+ this is upload id {{ uploadId }}
+
+
+ footer
+
+
+
+
+
+
diff --git a/src/app/upload-cards/upload-cards.component.scss b/src/app/upload-cards/upload-cards.component.scss
new file mode 100644
index 0000000..386bcc5
--- /dev/null
+++ b/src/app/upload-cards/upload-cards.component.scss
@@ -0,0 +1,73 @@
+div.card-wrapper{
+ width:260px;
+ margin-bottom:20px;
+ width: 100%;
+ height: 100%;
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ justify-content: center;
+
+ .upload-card-content {
+ &:before {
+ content: "";
+ position: absolute;
+// z-index: -1;
+ top: -16px;
+ right: -16px;
+ background: #00838d;
+ height: 32px;
+ width: 32px;
+ border-radius: 32px;
+ transform: scale(1);
+ transform-origin: 50% 50%;
+ transition: transform 0.25s ease-out;
+ }
+
+ kendo-card-header,
+ kendo-card-body,
+ kendo-card-footer{
+ z-index:2;
+ } ;
+
+ &:hover:before {
+ transform: scale(21);
+ }
+
+ &:hover {
+ p {
+ z-index: 100;
+ transition: all 0.3s ease-out;
+ color: rgba(255, 255, 255, 0.8);
+ }
+ h1 {
+ transition: all 0.3s ease-out;
+ color: #fcfcfc;
+ }
+ }
+
+ }
+
+
+ .go-corner {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: absolute;
+ width: 32px;
+ height: 32px;
+ overflow: hidden;
+ top: 0;
+ right: 0;
+ background-color: #00838d;
+ border-radius: 0 4px 0 32px;
+ }
+
+ .go-arrow {
+ margin-top: -4px;
+ margin-right: -4px;
+ color: white;
+ font-family: courier, sans;
+ }
+}
+
diff --git a/src/app/upload-cards/upload-cards.component.spec.ts b/src/app/upload-cards/upload-cards.component.spec.ts
new file mode 100644
index 0000000..26f4615
--- /dev/null
+++ b/src/app/upload-cards/upload-cards.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { UploadCardsComponent } from './upload-cards.component';
+
+describe('UploadCardsComponent', () => {
+ let component: UploadCardsComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ UploadCardsComponent ]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(UploadCardsComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/upload-cards/upload-cards.component.ts b/src/app/upload-cards/upload-cards.component.ts
new file mode 100644
index 0000000..d74becf
--- /dev/null
+++ b/src/app/upload-cards/upload-cards.component.ts
@@ -0,0 +1,22 @@
+import {Component, Input, OnInit} from '@angular/core';
+import {Router} from '@angular/router';
+
+@Component({
+ selector: 'app-upload-cards',
+ templateUrl: './upload-cards.component.html',
+ styleUrls: ['./upload-cards.component.scss']
+})
+export class UploadCardsComponent implements OnInit {
+ @Input() uploadId: number;
+
+ @Input() public card: any;
+
+ constructor(private router: Router) { }
+
+ ngOnInit(): void {
+ }
+
+ public onNavigateTo(id: number ): void{
+ this.router.navigate(['/upload-details/' + id]);
+ }
+}
diff --git a/src/app/upload-detail/upload-detail.component.html b/src/app/upload-detail/upload-detail.component.html
new file mode 100644
index 0000000..2da00ce
--- /dev/null
+++ b/src/app/upload-detail/upload-detail.component.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
No data
+
+
+
+
+
+ pane 2
+
+
+
+
diff --git a/src/app/upload-detail/upload-detail.component.scss b/src/app/upload-detail/upload-detail.component.scss
new file mode 100644
index 0000000..ea2009f
--- /dev/null
+++ b/src/app/upload-detail/upload-detail.component.scss
@@ -0,0 +1,22 @@
+div.workspace {
+ height: calc(100vh - 48px);
+}
+
+.fullheight-tab{
+ height:100%;
+}
+
+.main-content{
+ min-height:100%;
+ margin:0;
+ box-shadow: 1px 1px 10px black;
+}
+
+.dark-panel {
+ width:100%;
+ height:100%;
+ background-color: darkgrey;
+ padding: 10px 10px 10px 10px;
+ scroll-behavior: auto;
+ overflow: hidden;
+}
diff --git a/src/app/upload-detail/upload-detail.component.spec.ts b/src/app/upload-detail/upload-detail.component.spec.ts
new file mode 100644
index 0000000..afa66e0
--- /dev/null
+++ b/src/app/upload-detail/upload-detail.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { UploadDetailComponent } from './upload-detail.component';
+
+describe('UploadDetailComponent', () => {
+ let component: UploadDetailComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ UploadDetailComponent ]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(UploadDetailComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/upload-detail/upload-detail.component.ts b/src/app/upload-detail/upload-detail.component.ts
new file mode 100644
index 0000000..2a9d517
--- /dev/null
+++ b/src/app/upload-detail/upload-detail.component.ts
@@ -0,0 +1,63 @@
+import {Component, Input, OnInit, ViewEncapsulation} from '@angular/core';
+import {ActivatedRoute, Router} from '@angular/router';
+import {UploadAttachService} from '../service/upload.attach.service';
+import {UploadAnalysisModel} from '../models/upload.analysis.model';
+import {UploadModel} from '../models/upload.model';
+import {range} from '@progress/kendo-angular-dateinputs/dist/es2015/util';
+
+
+
+@Component({
+ selector: 'app-upload-detail',
+ templateUrl: './upload-detail.component.html',
+ styleUrls: ['./upload-detail.component.scss']
+})
+export class UploadDetailComponent implements OnInit {
+ @Input() uploadId: number;
+ @Input() ua: UploadAnalysisModel = new UploadAnalysisModel({});
+ // 'http://africau.edu/images/default/sample.pdf';
+ public uploadAsPicUrl = 'https://svr2021.lawipac.com:8080/api/v1/upload-as-pdf/default';
+ public uploadAsPdfUrl = '';
+
+
+
+ constructor(private us: UploadAttachService, private actRoute: ActivatedRoute, private router: Router) { }
+
+ ngOnInit(): void {
+ const id = this.actRoute.snapshot.params.id;
+ if ( id !== undefined && id > 0 ) {
+ this.uploadId = id;
+ }
+
+ this.ua.Id = this.uploadId;
+ this.uploadAsPicUrl = this.us.getUploadAsJpgUrl(this.ua.Id);
+ this.uploadAsPdfUrl = this.us.getUploadAsPdfUrl(this.ua.Id);
+
+ this.loadUploadMeta();
+ // this.loadUploadAnalysis();
+ }
+
+ private loadUploadAnalysis(): void {
+ this.us.getUploadAnalysis(this.uploadId).subscribe(
+ resp => {
+ this.ua = new UploadAnalysisModel(resp);
+ this.uploadId = this.ua.Id;
+ this.uploadAsPicUrl = this.us.getUploadAsJpgUrl(this.ua.Id);
+ this.uploadAsPdfUrl = this.us.getUploadAsPdfUrl(this.ua.Id);
+ console.log(this);
+ }
+ );
+ }
+ private loadUploadMeta(): void {
+ this.us.getUploadMeta(this.uploadId).subscribe(
+ resp => {
+ this.ua.Upload = new UploadModel(resp);
+ console.log(resp, this);
+ // this.ua.Upload = new UploadModel(resp);
+ // this.loadUploadAnalysis();
+ }
+ );
+ }
+
+
+}