3 次程式碼提交

作者 SHA1 備註 提交日期
  Adwaith Rao 481c37b21a Add other name registration endpoints 3 年之前
  Adwaith Rao 890271cd70 Add a register name service 3 年之前
  Adwaith Rao e1877048c1 Make notifications responsive 3 年之前
共有 14 個檔案被更改,包括 198 行新增84 行删除
統一視圖
  1. +5
    -2
      package.json
  2. +2
    -0
      src/app/app.module.ts
  3. +9
    -1
      src/app/layout/navbar/navbar.component.ts
  4. +1
    -1
      src/app/layout/notifications/notifications-list/notifications-list.component.html
  5. +5
    -1
      src/app/layout/notifications/notifications-list/notifications-list.component.ts
  6. +15
    -3
      src/app/layout/tabs/tabs.component.ts
  7. +3
    -1
      src/app/pages/investigate-business-entities-and-individuals/investigate-business-entities-and-individuals.component.ts
  8. +3
    -1
      src/app/pages/login/login.component.ts
  9. +2
    -2
      src/app/pages/register-business/register-business.component.html
  10. +46
    -70
      src/app/pages/register-business/register-business.component.ts
  11. +14
    -0
      src/app/services/login.service.ts
  12. +4
    -2
      src/app/services/notification.service.ts
  13. +16
    -0
      src/app/services/register-business-name.service.spec.ts
  14. +73
    -0
      src/app/services/register-business-name.service.ts

+ 5
- 2
package.json 查看文件

@@ -8,8 +8,11 @@
"watch": "ng build --watch --configuration development", "watch": "ng build --watch --configuration development",
"test": "ng test", "test": "ng test",


"docker-build": "docker build -t b2rs-multi-stage-image .",
"docker-create": "docker run --name b2rs-app-container -d -p 80:80 b2rs-multi-stage-image",
"docker-build": "docker build -t b2rs-front-end-image .",
"docker-tag": "docker tag b2rs-front-end-image:latest 834628752744.dkr.ecr.ap-southeast-1.amazonaws.com/b2rs-front-end-image:latest",
"docker-push": "docker push 834628752744.dkr.ecr.ap-southeast-1.amazonaws.com/b2rs-front-end-image:latest",
"docker-create": "docker run --name b2rs-app-container -d -p 80:80 b2rs-front-end-image",
"docker-destroy": "docker container rm b2rs-app-container", "docker-destroy": "docker container rm b2rs-app-container",


"docker-start": "docker start b2rs-app-container", "docker-start": "docker start b2rs-app-container",


+ 2
- 0
src/app/app.module.ts 查看文件

@@ -34,6 +34,7 @@ import { DashboardComponent } from './pages/dashboard/dashboard.component';
import { FilterViewCardComponent } from './pages/dashboard/filter-view-card/filter-view-card.component'; import { FilterViewCardComponent } from './pages/dashboard/filter-view-card/filter-view-card.component';
import { NavbarComponent } from './layout/navbar/navbar.component'; import { NavbarComponent } from './layout/navbar/navbar.component';
import { NotificationsListComponent } from './layout/notifications/notifications-list/notifications-list.component'; import { NotificationsListComponent } from './layout/notifications/notifications-list/notifications-list.component';
import { HttpClientModule } from '@angular/common/http';


@NgModule({ @NgModule({
declarations: [ declarations: [
@@ -73,6 +74,7 @@ import { NotificationsListComponent } from './layout/notifications/notifications
AppRoutingModule, AppRoutingModule,
FormsModule, FormsModule,
FileUploadModule, FileUploadModule,
HttpClientModule,
], ],
providers: [], providers: [],
bootstrap: [AppComponent] bootstrap: [AppComponent]


+ 9
- 1
src/app/layout/navbar/navbar.component.ts 查看文件

@@ -13,12 +13,16 @@ export class NavbarComponent implements OnInit, OnDestroy {
showLogout: boolean = false; showLogout: boolean = false;


isShowingNotificationsSubscription: Subscription; isShowingNotificationsSubscription: Subscription;
loginRoleSubscription: Subscription;


loginName: string = ''; loginName: string = '';
notificationsCount: number = 0; notificationsCount: number = 0;


constructor(loginService: LoginService, private notificationService: NotificationService) { constructor(loginService: LoginService, private notificationService: NotificationService) {
this.loginName = loginService.getLoginName();
this.loginRoleSubscription = loginService.getLoginRoleObservable().subscribe(loginRole => {
this.loginName = loginService.getLoginName();
});

this.notificationsCount = notificationService.getAllowedNotifications().length; this.notificationsCount = notificationService.getAllowedNotifications().length;


this.isShowingNotificationsSubscription = this.notificationService.getIsShowingNotificationsObservable().subscribe(isShowingNotifications => this.isShowingNotifications = isShowingNotifications); this.isShowingNotificationsSubscription = this.notificationService.getIsShowingNotificationsObservable().subscribe(isShowingNotifications => this.isShowingNotifications = isShowingNotifications);
@@ -35,6 +39,10 @@ export class NavbarComponent implements OnInit, OnDestroy {
if (this.isShowingNotificationsSubscription) { if (this.isShowingNotificationsSubscription) {
this.isShowingNotificationsSubscription.unsubscribe(); this.isShowingNotificationsSubscription.unsubscribe();
} }

if (this.loginRoleSubscription) {
this.loginRoleSubscription.unsubscribe();
}
} }


} }

+ 1
- 1
src/app/layout/notifications/notifications-list/notifications-list.component.html 查看文件

@@ -1,6 +1,6 @@
<ul> <ul>
<li *ngFor="let notification of allowedNotifications"> <li *ngFor="let notification of allowedNotifications">
<a *ngIf="notification.redirectionUrl" [routerLink]="notification.redirectionUrl">
<a *ngIf="notification.redirectionUrl" (click)="closeNotifications()" [routerLink]="notification.redirectionUrl">
<h5> {{ notification.text }} </h5> <h5> {{ notification.text }} </h5>
<p *ngIf="notification.description"> {{ notification.description }} </p> <p *ngIf="notification.description"> {{ notification.description }} </p>
<span class="time-stamp"> {{ notification.timeStamp }} </span> <span class="time-stamp"> {{ notification.timeStamp }} </span>


+ 5
- 1
src/app/layout/notifications/notifications-list/notifications-list.component.ts 查看文件

@@ -9,11 +9,15 @@ import { Notification, NotificationService } from 'src/app/services/notification
export class NotificationsListComponent implements OnInit { export class NotificationsListComponent implements OnInit {
allowedNotifications: Array<Notification> = []; allowedNotifications: Array<Notification> = [];


constructor(notificationService: NotificationService) {
constructor(private notificationService: NotificationService) {
this.allowedNotifications = notificationService.getAllowedNotifications(); this.allowedNotifications = notificationService.getAllowedNotifications();
} }


ngOnInit(): void { ngOnInit(): void {
} }


closeNotifications() {
this.notificationService.setIsShowingNotifications(false);
}

} }

+ 15
- 3
src/app/layout/tabs/tabs.component.ts 查看文件

@@ -1,4 +1,5 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { LoginService } from 'src/app/services/login.service'; import { LoginService } from 'src/app/services/login.service';
import { NotificationService } from 'src/app/services/notification.service'; import { NotificationService } from 'src/app/services/notification.service';


@@ -7,19 +8,30 @@ import { NotificationService } from 'src/app/services/notification.service';
templateUrl: './tabs.component.html', templateUrl: './tabs.component.html',
styleUrls: ['./tabs.component.scss'] styleUrls: ['./tabs.component.scss']
}) })
export class TabsComponent implements OnInit {
export class TabsComponent implements OnInit, OnDestroy {
showNotifications: boolean = false; showNotifications: boolean = false;
showLogout: boolean = false; showLogout: boolean = false;


loginRoleSubscription: Subscription;

loginName: string = ''; loginName: string = '';
notificationsCount: number = 0; notificationsCount: number = 0;


constructor(loginService: LoginService, notificationService: NotificationService) { constructor(loginService: LoginService, notificationService: NotificationService) {
this.loginName = loginService.getLoginName();
this.loginRoleSubscription = loginService.getLoginRoleObservable().subscribe(loginRole => {
this.loginName = loginService.getLoginName();
});

this.notificationsCount = notificationService.getAllowedNotifications().length; this.notificationsCount = notificationService.getAllowedNotifications().length;
} }


ngOnInit(): void { ngOnInit(): void {
} }


ngOnDestroy(): void {
if (this.loginRoleSubscription) {
this.loginRoleSubscription.unsubscribe();
}
}

} }

+ 3
- 1
src/app/pages/investigate-business-entities-and-individuals/investigate-business-entities-and-individuals.component.ts 查看文件

@@ -1,7 +1,7 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';


type State = 'VIEW INITIAL DETAILS'|'ENTER MORE DETAILS'|'ASSIGN COMMITTEE'|'REVIEW NON COMPLIANCE'|'CONCUR COMPLIANCE REVIEW'|'CLOSING REMARKS'|'PREPARE PRELIMINARY LETTER'|'RESPOND TO PRELIMINARY LETTER'; type State = 'VIEW INITIAL DETAILS'|'ENTER MORE DETAILS'|'ASSIGN COMMITTEE'|'REVIEW NON COMPLIANCE'|'CONCUR COMPLIANCE REVIEW'|'CLOSING REMARKS'|'PREPARE PRELIMINARY LETTER'|'RESPOND TO PRELIMINARY LETTER';
type Role = 'Investigator'|'Hod'|'Panel'|'Customer';
type Role = 'Investigator'|'Hod'|'Panel'|'Customer'|'Officer';


@Component({ @Component({
selector: 'app-investigate-business-entities-and-individuals', selector: 'app-investigate-business-entities-and-individuals',
@@ -41,6 +41,8 @@ export class InvestigateBusinessEntitiesAndIndividualsComponent implements OnIni
this.loginRole = 'Panel'; this.loginRole = 'Panel';
} else if (loginEmail && loginEmail.toLocaleLowerCase().startsWith('customer')) { } else if (loginEmail && loginEmail.toLocaleLowerCase().startsWith('customer')) {
this.loginRole = 'Customer'; this.loginRole = 'Customer';
} else if (loginEmail && loginEmail.toLocaleLowerCase().startsWith('officer')) {
this.loginRole = 'Officer';
} else { } else {
this.loginRole = 'Investigator'; this.loginRole = 'Investigator';
} }


+ 3
- 1
src/app/pages/login/login.component.ts 查看文件

@@ -1,4 +1,5 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { LoginService } from 'src/app/services/login.service';


@Component({ @Component({
selector: 'app-login', selector: 'app-login',
@@ -8,7 +9,7 @@ import { Component, OnInit } from '@angular/core';
export class LoginComponent implements OnInit { export class LoginComponent implements OnInit {
email = ''; email = '';
constructor() { }
constructor(private loginService: LoginService) { }


ngOnInit(): void { ngOnInit(): void {
} }
@@ -17,6 +18,7 @@ export class LoginComponent implements OnInit {
this.email = email; this.email = email;


localStorage.setItem('loginEmail', email); localStorage.setItem('loginEmail', email);
this.loginService.updateLoginRole();
} }


} }

+ 2
- 2
src/app/pages/register-business/register-business.component.html 查看文件

@@ -77,7 +77,7 @@
<button class="common-button neutral" (click)="formState = 'INIT_REGISTER'"> <button class="common-button neutral" (click)="formState = 'INIT_REGISTER'">
Back Back
</button> </button>
<button class="common-button" (click)="formState = 'SELECT_PLAN'">
<button class="common-button" (click)="registerName()">
Proceed Proceed
</button> </button>
</div> </div>
@@ -150,7 +150,7 @@
<button class="common-button outline" (click)="print()"> <button class="common-button outline" (click)="print()">
Print Print
</button> </button>
<button class="common-button" (click)="formState = 'RECEIPT'">
<button class="common-button" (click)="goToReceipt()">
View Receipt View Receipt
</button> </button>
</div> </div>


+ 46
- 70
src/app/pages/register-business/register-business.component.ts 查看文件

@@ -1,7 +1,17 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { DateInputProperties } from 'src/app/widgets/form/date-input/date-input.component';
import { GenericInputProperties } from 'src/app/widgets/form/generic-input/generic-input.component';
import { SelectInputProperties } from 'src/app/widgets/form/select-input/select-input.component';
import { RegisterBusinessNameService } from 'src/app/services/register-business-name.service';

export interface AcknowledgementRow {
name: string,
value: string | number,
amount?: number,
highlight?: boolean,
};

export interface ReceiptRow {
name: string,
value: string | number,
};


@Component({ @Component({
selector: 'app-register-business', selector: 'app-register-business',
@@ -50,64 +60,11 @@ export class RegisterBusinessComponent implements OnInit {
dropSuffixOptions = ['YES', 'NO']; dropSuffixOptions = ['YES', 'NO'];




acknowledgementDetails: Array<{
name: string,
value: string | number,
amount?: number,
highlight?: boolean,
}> = [{
name: 'UEM',
value: '---'
}, {
name: 'Entity Name',
value: this.nameToCheck
}, {
name: 'Transaction Number',
value: '39047729362923293',
highlight: true,
}, {
name: 'Receipt Number',
value: 'ACRA38293',
highlight: true
}, {
name: 'EP Reference No.',
value: '20910038829384470'
}, {
name: 'Payment Date',
value: '06/11/2021 11:28:01'
}, {
name: 'Description',
value: 'Application for Business Name',
amount: 15
}];

receiptDetails: Array<{
name: string,
value: string | number,
}> = [{
name: 'Receipt Number',
value: 'ACRA38293',
}, {
name: 'ARN',
value: 'ARN2021110294038',
}, {
name: 'EP Reference No.',
value: '20910038829384470'
}, {
name: 'Tax ID',
value: 'M9-0C038921',
}, {
name: 'Paid By',
value: 'KOH YA TING',
}, {
name: 'Payment Date',
value: '06/11/2021 11:28:01'
}, {
name: 'Paid Via',
value: 'Net Banking',
}];

constructor() { }
acknowledgementDetails: Array<AcknowledgementRow> = [];

receiptDetails: Array<ReceiptRow> = [];

constructor(private registerBusinessNameService: RegisterBusinessNameService) { }


ngOnInit(): void { ngOnInit(): void {
} }
@@ -151,33 +108,52 @@ export class RegisterBusinessComponent implements OnInit {
payForReservation() { payForReservation() {
this.paymentChild = window.open('/mock', '_blank', 'toolbar=0,status=0,width=626,height=436'); this.paymentChild = window.open('/mock', '_blank', 'toolbar=0,status=0,width=626,height=436');


this.childCheck = window.setInterval(() => {
this.childCheck = window.setInterval(async () => {
if (this.paymentChild && this.paymentChild.closed) { if (this.paymentChild && this.paymentChild.closed) {
this.formState = 'ACKNOWLEDGEMENT'; this.formState = 'ACKNOWLEDGEMENT';
window.clearInterval(this.childCheck); window.clearInterval(this.childCheck);
this.childCheck = undefined; this.childCheck = undefined;
this.acknowledgementDetails = await this.registerBusinessNameService.getAcknowledgement();
} }
}, 1000); }, 1000);
} }


checkName() {
async goToReceipt() {
this.formState = 'RECEIPT';
this.receiptDetails = await this.registerBusinessNameService.getReceipt();
}

async checkName() {
this.formState = 'INIT_REGISTER'; this.formState = 'INIT_REGISTER';


if (this.nameToCheck === `A'DROIT MANAGEMENT SERVICES`) {
this.error = {
message: this.nameToCheck + ' is unavailable. Entity with identical name exists',
isUnique: false,
isInvalid: false,
};
} else {
const nameCheckResponse = await this.registerBusinessNameService.checkName(this.nameToCheck);

if (nameCheckResponse.status === `success`) {
this.error = { this.error = {
message: this.nameToCheck + ' is available', message: this.nameToCheck + ' is available',
isUnique: true, isUnique: true,
isInvalid: false isInvalid: false
}; };
} else {
this.error = {
message: this.nameToCheck + ' is unavailable. ' + nameCheckResponse.status,
isUnique: false,
isInvalid: false,
};
} }
} }


async registerName() {
await this.registerBusinessNameService.registerName(
this.nameToCheck,
this.selectedEntityType,
this.selectedCompanyCategory,
this.selectedCompanySuffix,
this.selectedDropSuffix,
);
this.formState = 'SELECT_PLAN';
}

print() { print() {
window.print(); window.print();
} }


+ 14
- 0
src/app/services/login.service.ts 查看文件

@@ -1,4 +1,5 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';


export type Role = 'Officer'|'Investigator'|'Hod'|'Panel'|'Customer'; export type Role = 'Officer'|'Investigator'|'Hod'|'Panel'|'Customer';


@@ -7,8 +8,15 @@ export type Role = 'Officer'|'Investigator'|'Hod'|'Panel'|'Customer';
}) })
export class LoginService { export class LoginService {
private loginRole: Role; private loginRole: Role;
private loginRoleSubject: BehaviorSubject<string>;


constructor() { constructor() {
this.loginRole = 'Customer';
this.loginRoleSubject = new BehaviorSubject('');
this.updateLoginRole();
}

updateLoginRole() {
const loginEmail = localStorage.getItem('loginEmail'); const loginEmail = localStorage.getItem('loginEmail');


if (loginEmail && loginEmail.toLocaleLowerCase().startsWith('hod')) { if (loginEmail && loginEmail.toLocaleLowerCase().startsWith('hod')) {
@@ -22,6 +30,8 @@ export class LoginService {
} else { } else {
this.loginRole = 'Officer'; this.loginRole = 'Officer';
} }

this.loginRoleSubject.next(this.loginRole);
} }


getLoginName() { getLoginName() {
@@ -34,6 +44,10 @@ export class LoginService {
} }
} }


getLoginRoleObservable() {
return this.loginRoleSubject.asObservable();
}

getLoginRole() { getLoginRole() {
return this.loginRole; return this.loginRole;
} }


+ 4
- 2
src/app/services/notification.service.ts 查看文件

@@ -71,8 +71,10 @@ export class NotificationService {
private allowedNotifications: Array<Notification> = []; private allowedNotifications: Array<Notification> = [];


constructor(loginService: LoginService) { constructor(loginService: LoginService) {
const loginRole = loginService.getLoginRole();
this.allowedNotifications = this.notifications.filter(notification => notification.roles.includes(loginRole));
loginService.getLoginRoleObservable().subscribe(loginRoleObserved => {
const loginRole = loginService.getLoginRole();
this.allowedNotifications = this.notifications.filter(notification => notification.roles.includes(loginRole));
});
} }


getAllowedNotifications() { getAllowedNotifications() {


+ 16
- 0
src/app/services/register-business-name.service.spec.ts 查看文件

@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';

import { RegisterBusinessNameService } from './register-business-name.service';

describe('RegisterBusinessNameService', () => {
let service: RegisterBusinessNameService;

beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(RegisterBusinessNameService);
});

it('should be created', () => {
expect(service).toBeTruthy();
});
});

+ 73
- 0
src/app/services/register-business-name.service.ts 查看文件

@@ -0,0 +1,73 @@
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError, retry } from 'rxjs/operators';
import { AcknowledgementRow, ReceiptRow } from '../pages/register-business/register-business.component';

export interface NameCheckRequest {
name: string;
}

export interface NameCheckResponse {
status: string;
}

export interface NameRegisterRequest {
name: string;
entityType: string;
companyCategory: string;
companySuffix: string;
dropSuffix: string;
}

export interface NameRegisterResponse {
status: string;
}

@Injectable({
providedIn: 'root'
})
export class RegisterBusinessNameService {

constructor(private http: HttpClient) {

}

checkName(name: string) {
const nameCheckRequest: NameCheckRequest = {
name,
};

return new Promise<NameCheckResponse>((resolve, reject) => resolve({status: 'success'}));

return this.http.post<NameCheckResponse>('http://localhost:10000/name-check/', nameCheckRequest).toPromise();
}

registerName(
name: string,
entityType: string,
companyCategory: string,
companySuffix: string,
dropSuffix: string,
) {
const nameRegisterRequest: NameRegisterRequest = {
name,
entityType,
companyCategory,
companySuffix,
dropSuffix,
};

return new Promise<NameCheckResponse>((resolve, reject) => resolve({status: 'success'}));

return this.http.post<NameRegisterResponse>('http://localhost:8080/name-register/', nameRegisterRequest).toPromise();
}

getAcknowledgement() {
return this.http.get<Array<AcknowledgementRow>>('http://localhost:8080/acknowledgement/').toPromise();
}

getReceipt() {
return this.http.get<Array<ReceiptRow>>('http://localhost:8080/receipt/').toPromise();
}
}

Loading…
取消
儲存