소스 검색

uploads list works.

tags/2.037
Patrick Sun 4 년 전
부모
커밋
83abade9e5
35개의 변경된 파일1064개의 추가작업 그리고 73개의 파일을 삭제
  1. +5
    -1
      src/app/app-routing.module.ts
  2. +10
    -5
      src/app/app.component.scss
  3. +15
    -1
      src/app/app.module.ts
  4. +43
    -1
      src/app/lender-uploads/lender-uploads.component.html
  5. +68
    -0
      src/app/lender-uploads/lender-uploads.component.scss
  6. +93
    -3
      src/app/lender-uploads/lender-uploads.component.ts
  7. +34
    -0
      src/app/lender-uploads/upload-status.interceptor.ts
  8. +1
    -0
      src/app/list-all-people/list-all-people.component.scss
  9. +4
    -5
      src/app/list-all-people/list-all-people.component.ts
  10. +1
    -0
      src/app/list-all-rewards/list-all-rewards.component.scss
  11. +37
    -0
      src/app/list-income/list-income.component.html
  12. +7
    -0
      src/app/list-income/list-income.component.scss
  13. +25
    -0
      src/app/list-income/list-income.component.spec.ts
  14. +21
    -0
      src/app/list-income/list-income.component.ts
  15. +16
    -16
      src/app/loan-edit/trail-income/trail-income.component.ts
  16. +2
    -0
      src/app/main-menu-items.ts
  17. +18
    -0
      src/app/models/Pay.In.AAA.Row.model.ts
  18. +15
    -0
      src/app/models/funder.aaa.trail.model.ts
  19. +2
    -26
      src/app/models/loan.model.ts
  20. +27
    -13
      src/app/models/pay-in.model.ts
  21. +50
    -0
      src/app/models/upload.analysis.model.ts
  22. +22
    -0
      src/app/models/upload.model.ts
  23. +91
    -1
      src/app/pay-in/pay-in.component.html
  24. +9
    -0
      src/app/pay-in/pay-in.component.scss
  25. +124
    -1
      src/app/pay-in/pay-in.component.ts
  26. +14
    -0
      src/app/pipe/safe.url.pipe.ts
  27. +38
    -0
      src/app/service/upload.attach.service.ts
  28. +25
    -0
      src/app/upload-cards/upload-cards.component.html
  29. +73
    -0
      src/app/upload-cards/upload-cards.component.scss
  30. +25
    -0
      src/app/upload-cards/upload-cards.component.spec.ts
  31. +22
    -0
      src/app/upload-cards/upload-cards.component.ts
  32. +17
    -0
      src/app/upload-detail/upload-detail.component.html
  33. +22
    -0
      src/app/upload-detail/upload-detail.component.scss
  34. +25
    -0
      src/app/upload-detail/upload-detail.component.spec.ts
  35. +63
    -0
      src/app/upload-detail/upload-detail.component.ts

+ 5
- 1
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({

+ 10
- 5
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;
}

+ 15
- 1
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]

+ 43
- 1
src/app/lender-uploads/lender-uploads.component.html 파일 보기

@@ -1 +1,43 @@
<p>lender-uploads works!</p>
<div class="workarea">
<div class="file-manager-bar">
<div class="upload-area">
<kendo-upload class="uploadfiles" [concurrent]="false" [restrictions]="myRestrictions"
(success)="onSuccess($event)"
(upload)="onUpload($event)"
(complete)="onComplete()"
(uploadProgress)="uploadProgress($event)"
[showFileList]="false"
[saveUrl]="uploadSaveUrl">
<ng-template kendoUploadFileInfoTemplate let-files let map="map">
<div *ngIf="files!==undefined && files!== null && files[0] !== null">
<div (click)="onClick(files)">Name: {{ files[0].name }}</div>
<div *ngIf="files[0].validationErrors !== undefined"> Cannot upload this file {{files[0]}}</div>
<div *ngIf="map.get(files[0].uid) !== undefined"> fuck all {{map.get(files[0].uid).response.body.Funder}} </div>
</div>
</ng-template>
</kendo-upload>
</div>
<div class="search-area">
<kendo-textbox class='search-people' [placeholder]="'Type to search/filter'" (valueChange)="onFilterUploads($event)" > </kendo-textbox>
<kendo-icon name="search" size="medium"></kendo-icon>
</div>
</div>
<bkp-divider-shadow-bottom></bkp-divider-shadow-bottom>
<div class="container">
<div class="row justify-content-start">
<div class="col-lg-3 text-center" *ngFor="let p of displayedUploads">
<app-upload-cards [uploadId]="p"></app-upload-cards>
</div>
</div>
<div class="vertical-spacer"></div>
</div>

<kendo-datapager
class="bottom-pager"
[style.width.%]="100"
[pageSize]="pageSize"
[skip]="skip"
[total]="total"
(pageChange)="onPageChange($event)">
</kendo-datapager>
</div>

+ 68
- 0
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;
}


+ 93
- 3
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<SuccessEvent> = new EventEmitter<SuccessEvent>();
@Output() click: EventEmitter<FileInfo> = new EventEmitter<FileInfo>();
@Output() complete: EventEmitter<FileInfo> = new EventEmitter<FileInfo>();
@Output() upload: EventEmitter<boolean> = new EventEmitter<boolean>();


private uploads: SuccessEvent[] = [];
public value = 0 ;
public map: Map<string, SuccessEvent> = new Map<string, SuccessEvent>();

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();
}
}

+ 34
- 0
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<any>, next: HttpHandler): Observable<HttpEvent<any>> {
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);
}
}

+ 1
- 0
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{

+ 4
- 5
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 {


+ 1
- 0
src/app/list-all-rewards/list-all-rewards.component.scss 파일 보기

@@ -7,6 +7,7 @@

kendo-grid{
flex: 0 1 auto;
height: 100%;
}



+ 37
- 0
src/app/list-income/list-income.component.html 파일 보기

@@ -0,0 +1,37 @@
<div class="income-container">
<kendo-splitter orientation="vertical" style="height: 100%;">

<kendo-splitter-pane [collapsible]="false">
<div class="pane-content">
<h3>Outer splitter / Middle pane</h3>
<p>Resizable only.</p>
</div>
</kendo-splitter-pane>


<kendo-splitter-pane [collapsible]="true" size="50%">
<kendo-splitter class="full-height">

<kendo-splitter-pane size="300px">
<div class="pane-content">
<app-lender-uploads (success)="onSuccess($event)"></app-lender-uploads>
</div>
</kendo-splitter-pane>

<kendo-splitter-pane >
<div class="pane-content">
<div *ngFor="let u of uploads" class="aaaa">
Type: {{u.files[0].extension}}
Name: {{u.files[0].name}}
Funder: Name: {{u.response.body.Funder}}
</div>
</div>
</kendo-splitter-pane>
</kendo-splitter>




</kendo-splitter-pane>
</kendo-splitter>
</div>

+ 7
- 0
src/app/list-income/list-income.component.scss 파일 보기

@@ -0,0 +1,7 @@
div.income-container {
height: calc(100vh - 48px);
}

div.pane-content{
height:100%;
}

+ 25
- 0
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<ListIncomeComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ListIncomeComponent ]
})
.compileComponents();
});

beforeEach(() => {
fixture = TestBed.createComponent(ListIncomeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});

+ 21
- 0
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);
}
}

+ 16
- 16
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]);
}

}

+ 2
- 0
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' },
]
},
{

+ 18
- 0
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<PayInAAARowModel>){
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;
}
}

+ 15
- 0
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<FunderAaaTrailModel>) {
this.Period = new Date(payload.Period);
this.Rows = [];
if ( payload.Rows ){
payload.Rows.forEach( v => {
this.Rows.push (new PayInAAARowModel(v));
});
}
}
}

+ 2
- 26
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;

+ 27
- 13
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<PayInModel>){
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;
}
}

+ 50
- 0
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<UploadAnalysisModel>){
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 || {});
}

}

+ 22
- 0
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<UploadModel>) {
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 || '';
}
}

+ 91
- 1
src/app/pay-in/pay-in.component.html 파일 보기

@@ -1 +1,91 @@
<p>pay-in works!</p>
<kendo-grid [data]="AllPayIn"
(add)="addHandler($event)"
(cancel)="cancelHandler($event)"
(save)="saveHandler($event)"
(edit)="editHandler($event)"
(remove)="removeHandler($event)"
>
<ng-template kendoGridToolbarTemplate>
<button kendoGridAddCommand icon="plus" >Add new Income</button>
&nbsp; Show Uploads &nbsp; <kendo-switch></kendo-switch>
</ng-template>

<kendo-grid-command-column title="command" width="100">
<ng-template kendoGridCellTemplate let-isNew="isNew" let-dataItem>
<button kendoGridEditCommand *ngIf="!dataItem.Uploads !== 0" icon="edit"></button>
<button kendoGridRemoveCommand *ngIf="!dataItem.Uploads !== 0" icon="delete"></button>
<button kendoGridSaveCommand [disabled]="formGroup?.invalid" icon="save"></button>
<button kendoGridCancelCommand icon="cancel"></button>
</ng-template>
</kendo-grid-command-column>

<kendo-grid-column field="Id" title="Id" width="50" editable="false">
</kendo-grid-column>

<kendo-grid-column field="Trail" title="Trail Received" width="200" format="{0:c}" editor="numeric">
</kendo-grid-column>

<kendo-grid-column field="Ts" title="Trail Date" editor="date">
<ng-template kendoGridCellTemplate let-dataItem>
{{ dataItem.Ts | date: 'yyyy-MM-dd' }}
</ng-template>
</kendo-grid-column>

<kendo-grid-column field="Balance" title="Balance" width="220">
<ng-template kendoGridCellTemplate let-dataItem>
<div *ngIf="dataItem.Balance >=0 "> {{ dataItem.Balance | currency}} </div>
<div *ngIf="dataItem.Balance < 0 "> unknown </div>
</ng-template>
<ng-template kendoGridEditTemplate
let-dataItem="dataItem"
let-formGroup="formGroup">

<kendo-switch [checked]="dataItem.Balance >=0"
name="showBalance" [(ngModel)]="showBalance"
ngModelOptions="{standalone: true}"
[onLabel]="'Yes'"
[offLabel]="'No'"
>
</kendo-switch>

<kendo-numerictextbox *ngIf="showBalance" name="balance" [formControl]="formGroup.get('Balance')"
[min]="-1" [max]="999999999" [autoCorrect]="true" class="balance">
</kendo-numerictextbox>
</ng-template>

</kendo-grid-column>


<kendo-grid-column field="OffsetBalance" title="Offset" width="200" >
<ng-template kendoGridCellTemplate let-dataItem>
<div *ngIf="dataItem.OffsetBalance >=0 "> {{ dataItem.OffsetBalance | currency}} </div>
<div *ngIf="dataItem.OffsetBalance < 0 "> unknown </div>
</ng-template>
<ng-template kendoGridEditTemplate
let-dataItem="dataItem"
let-formGroup="formGroup">

<kendo-switch [checked]="dataItem.OffsetBalance >=0"
name="showOffsetBalance" [(ngModel)]="showOffsetBalance"
ngModelOptions="{standalone: true}"
[onLabel]="'Yes'"
[offLabel]="'No'"
>
</kendo-switch>

<kendo-numerictextbox *ngIf="showOffsetBalance" name="offsetBalance"
[formControl]="formGroup.get('OffsetBalance')"
[min]="-1" [max]="999999999" [autoCorrect]="true" class="balance">
</kendo-numerictextbox>
</ng-template>
</kendo-grid-column>

<kendo-grid-column field="Uploaded" title="Uploads" width="100" format="{0:c}" editable="false">
<ng-template kendoGridCellTemplate let-dataItem let-rowIndex="rowIndex" >
<button kendoButton *ngIf="dataItem.Uploads > 0" icon="attachment">
</button>
<p *ngIf="dataItem.Uploads <=0" align="center"> - </p>
</ng-template>
</kendo-grid-column>

</kendo-grid>

+ 9
- 0
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;
}

+ 124
- 1
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<any> = [{
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;
}
}

+ 14
- 0
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);
}

}

+ 38
- 0
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<UploadModel> {
return this.http.get<UploadModel>(this.auth.getUrl('upload-meta/' + id));
}

public getUploadAnalysis(id: number): Observable<UploadAnalysisModel> {
return this.http.get<UploadAnalysisModel>(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 );
}

}

+ 25
- 0
src/app/upload-cards/upload-cards.component.html 파일 보기

@@ -0,0 +1,25 @@
<div class="card-wrapper" >
<kendo-card class="upload-card-content"[width]="'260px'">
<kendo-card-header class="k-hbox">
<kendo-avatar width="40px" height="40px" [shape]="'circle'"></kendo-avatar>
<div>
<h1 kendoCardTitle> card.headerTitle </h1>
<p kendoCardSubtitle> card.headerSubtitle</p>
</div>
</kendo-card-header>
<kendo-card-body>
<p>upload-cards works!</p>
<p (click)="onNavigateTo(uploadId)">this is upload id {{ uploadId }}</p>
</kendo-card-body>
<kendo-card-footer>
<p> footer </p>
</kendo-card-footer>
<div class="go-corner" href="#">
<div class="go-arrow">
</div>
</div>
</kendo-card>


</div>

+ 73
- 0
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;
}
}


+ 25
- 0
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<UploadCardsComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ UploadCardsComponent ]
})
.compileComponents();
});

beforeEach(() => {
fixture = TestBed.createComponent(UploadCardsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});

+ 22
- 0
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]);
}
}

+ 17
- 0
src/app/upload-detail/upload-detail.component.html 파일 보기

@@ -0,0 +1,17 @@
<div class="workspace">
<kendo-tabstrip [tabPosition]="'left'" class="fullheight-tab upload-details">
<kendo-tabstrip-tab title="Content" [selected]="true" cssClass="uploads-panel">
<ng-template kendoTabContent class="dark-panel">
<div class="dark-panel text-center" >
<iframe class="main-content" [src]="uploadAsPdfUrl | safeUrl" width="100%"></iframe>
<H1 *ngIf="uploadAsPdfUrl === ''"> No data </H1>
</div>
</ng-template>
</kendo-tabstrip-tab>
<kendo-tabstrip-tab title="AI Analysis">
<ng-template kendoTabContent>
<p> pane 2</p>
</ng-template>
</kendo-tabstrip-tab>
</kendo-tabstrip>
</div>

+ 22
- 0
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;
}

+ 25
- 0
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<UploadDetailComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ UploadDetailComponent ]
})
.compileComponents();
});

beforeEach(() => {
fixture = TestBed.createComponent(UploadDetailComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});

+ 63
- 0
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();
}
);
}


}

Loading…
취소
저장