@@ -31,6 +31,9 @@ import { ClosingRemarksComponent } from './pages/investigate-business-entities-a | |||
import { PreparePreliminaryLetterComponent } from './pages/investigate-business-entities-and-individuals/prepare-preliminary-letter/prepare-preliminary-letter.component'; | |||
import { RespondToPreliminaryLetterComponent } from './pages/investigate-business-entities-and-individuals/respond-to-preliminary-letter/respond-to-preliminary-letter.component'; | |||
import { DashboardComponent } from './pages/dashboard/dashboard.component'; | |||
import { FilterViewCardComponent } from './pages/dashboard/filter-view-card/filter-view-card.component'; | |||
import { NavbarComponent } from './layout/navbar/navbar.component'; | |||
import { NotificationsListComponent } from './layout/notifications/notifications-list/notifications-list.component'; | |||
@NgModule({ | |||
declarations: [ | |||
@@ -60,7 +63,10 @@ import { DashboardComponent } from './pages/dashboard/dashboard.component'; | |||
ClosingRemarksComponent, | |||
PreparePreliminaryLetterComponent, | |||
RespondToPreliminaryLetterComponent, | |||
DashboardComponent | |||
DashboardComponent, | |||
FilterViewCardComponent, | |||
NavbarComponent, | |||
NotificationsListComponent | |||
], | |||
imports: [ | |||
BrowserModule, | |||
@@ -0,0 +1,38 @@ | |||
<section class="navbar"> | |||
<figure class="logo"> | |||
<img src="assets/icons/logo.svg" alt="logo image"> | |||
</figure> | |||
<nav> | |||
<a *ngIf="loginName === 'Officer'" [routerLink]="['/tabs/dashboard']"> Dashboard </a> | |||
<a [routerLink]="['/tabs/e-services']"> E-Services </a> | |||
</nav> | |||
<div class="search-input"> | |||
<input type="text" placeholder="Search for Business Entities"> | |||
<img src="assets/icons/search.svg" alt="search icon"> | |||
</div> | |||
<button class="notification-button" (click)="showNotifications()" | |||
[ngClass]="{'active' : isShowingNotifications}"> | |||
<img src="assets/icons/bell.svg" alt="bell icon"> | |||
<span class="badge"> {{ notificationsCount }} </span> | |||
</button> | |||
<section class="profile-actions" (mouseover)="showLogout=true" (mouseout)="showLogout=false"> | |||
<ng-container *ngIf="!showLogout"> | |||
<img src="assets/icons/user.svg" alt="user icon"> | |||
<span> Hi, {{ loginName }} </span> | |||
<img src="assets/icons/chevron-down.svg" alt="chevron down image"> | |||
</ng-container> | |||
<ng-container *ngIf="showLogout"> | |||
<a [routerLink]="['/login']"> | |||
<img src="assets/icons/logout.svg" class="logout-icon" alt="logout icon"> | |||
<span> Log me out </span> | |||
<img src="assets/icons/chevron-down.svg" alt="chevron down image"> | |||
</a> | |||
</ng-container> | |||
</section> | |||
</section> |
@@ -0,0 +1,200 @@ | |||
$header-height: 10rem; | |||
.navbar { | |||
display: flex; | |||
width: 100%; | |||
height: $header-height; | |||
align-items: center; | |||
justify-content: flex-start; | |||
.logo { | |||
width: 12rem; | |||
margin: 0 2rem; | |||
img { | |||
width: 100%; | |||
height: 100%; | |||
} | |||
} | |||
nav { | |||
margin: 0 2rem; | |||
@media print { | |||
display: none; | |||
} | |||
a { | |||
font-size: 1.6rem; | |||
letter-spacing: 0.5px; | |||
color: var(--dark-grey); | |||
margin-right: 2rem; | |||
&.active { | |||
text-decoration: underline; | |||
color: var(--highlight); | |||
} | |||
&:hover { | |||
text-decoration: underline; | |||
} | |||
} | |||
} | |||
.search-input { | |||
position: relative; | |||
margin-left: auto; | |||
@media print { | |||
display: none; | |||
} | |||
input { | |||
display: block; | |||
height: 5rem; | |||
border: 1px solid var(--border-grey); | |||
border-radius: 4rem; | |||
padding: 0 2.5rem; | |||
width: 35rem; | |||
font-size: 1.5rem; | |||
font-weight: 300; | |||
&::placeholder { | |||
color: var(--dark-grey); | |||
opacity: 0.6; | |||
} | |||
} | |||
img { | |||
position: absolute; | |||
width: 1.8rem; | |||
top: 1.5rem; | |||
right: 1.8rem; | |||
} | |||
} | |||
.notification-button { | |||
width: 5rem; | |||
height: 5rem; | |||
border-radius: 50%; | |||
border: none; | |||
position: relative; | |||
background-color: white; | |||
margin-left: 2rem; | |||
@media print { | |||
display: none; | |||
} | |||
&.active { | |||
box-shadow: 0px 0px 10px -3px var(--primary); | |||
img { | |||
filter: brightness(500%); | |||
} | |||
.badge { | |||
transform: scale(0); | |||
} | |||
&::before { | |||
background-color: var(--highlight); | |||
opacity: 1; | |||
filter: none; | |||
} | |||
} | |||
&:hover { | |||
box-shadow: 0px 0px 10px -3px var(--primary); | |||
} | |||
.badge { | |||
background-color: var(--highlight); | |||
color: white; | |||
font-size: 1.1rem; | |||
border-radius: 7px; | |||
position: absolute; | |||
right: 0; | |||
top: -0.5rem; | |||
width: 2rem; | |||
height: 2rem; | |||
border-radius: 50%; | |||
display: flex; | |||
align-items: center; | |||
justify-content: center; | |||
font-weight: 600; | |||
transition: transform 0.1s; | |||
} | |||
&::before { | |||
content: ''; | |||
position: absolute; | |||
left: 0; | |||
top: 0; | |||
width: 100%; | |||
height: 100%; | |||
background-color: var(--secondary); | |||
opacity: 0.3; | |||
filter: brightness(110%); | |||
border-radius: 50%; | |||
} | |||
& > * { | |||
position: relative; | |||
} | |||
img { | |||
width: 40%; | |||
height: 40%; | |||
} | |||
} | |||
.profile-actions { | |||
margin: 0 2rem; | |||
display: flex; | |||
align-items: center; | |||
justify-content: center; | |||
height: 5rem; | |||
border-radius: 4rem; | |||
padding: 0 2rem; | |||
position: relative; | |||
overflow: hidden; | |||
width: 20rem; | |||
cursor: pointer; | |||
@media print { | |||
display: none; | |||
} | |||
&::before { | |||
content: ''; | |||
position: absolute; | |||
left: 0; | |||
top: 0; | |||
width: 100%; | |||
height: 100%; | |||
background-color: var(--secondary); | |||
opacity: 0.3; | |||
filter: brightness(110%); | |||
} | |||
& > * { | |||
position: relative; | |||
} | |||
img { | |||
width: 1.5rem; | |||
&.logout-icon { | |||
transform: scale(1.5); | |||
} | |||
} | |||
span { | |||
margin: 0 auto; | |||
color: var(--primary); | |||
font-size: 1.4rem; | |||
} | |||
} | |||
} |
@@ -0,0 +1,25 @@ | |||
import { ComponentFixture, TestBed } from '@angular/core/testing'; | |||
import { NavbarComponent } from './navbar.component'; | |||
describe('NavbarComponent', () => { | |||
let component: NavbarComponent; | |||
let fixture: ComponentFixture<NavbarComponent>; | |||
beforeEach(async () => { | |||
await TestBed.configureTestingModule({ | |||
declarations: [ NavbarComponent ] | |||
}) | |||
.compileComponents(); | |||
}); | |||
beforeEach(() => { | |||
fixture = TestBed.createComponent(NavbarComponent); | |||
component = fixture.componentInstance; | |||
fixture.detectChanges(); | |||
}); | |||
it('should create', () => { | |||
expect(component).toBeTruthy(); | |||
}); | |||
}); |
@@ -0,0 +1,40 @@ | |||
import { Component, OnDestroy, OnInit } from '@angular/core'; | |||
import { Subscription } from 'rxjs'; | |||
import { LoginService } from 'src/app/services/login.service'; | |||
import { NotificationService } from 'src/app/services/notification.service'; | |||
@Component({ | |||
selector: 'app-navbar', | |||
templateUrl: './navbar.component.html', | |||
styleUrls: ['./navbar.component.scss'] | |||
}) | |||
export class NavbarComponent implements OnInit, OnDestroy { | |||
isShowingNotifications = false; | |||
showLogout: boolean = false; | |||
isShowingNotificationsSubscription: Subscription; | |||
loginName: string = ''; | |||
notificationsCount: number = 0; | |||
constructor(loginService: LoginService, private notificationService: NotificationService) { | |||
this.loginName = loginService.getLoginName(); | |||
this.notificationsCount = notificationService.getAllowedNotifications().length; | |||
this.isShowingNotificationsSubscription = this.notificationService.getIsShowingNotificationsObservable().subscribe(isShowingNotifications => this.isShowingNotifications = isShowingNotifications); | |||
} | |||
showNotifications() { | |||
this.notificationService.setIsShowingNotifications(true); | |||
} | |||
ngOnInit(): void { | |||
} | |||
ngOnDestroy(): void { | |||
if (this.isShowingNotificationsSubscription) { | |||
this.isShowingNotificationsSubscription.unsubscribe(); | |||
} | |||
} | |||
} |
@@ -0,0 +1,14 @@ | |||
<ul> | |||
<li *ngFor="let notification of allowedNotifications"> | |||
<a *ngIf="notification.redirectionUrl" [routerLink]="notification.redirectionUrl"> | |||
<h5> {{ notification.text }} </h5> | |||
<p *ngIf="notification.description"> {{ notification.description }} </p> | |||
<span class="time-stamp"> {{ notification.timeStamp }} </span> | |||
</a> | |||
<ng-container *ngIf="!notification.redirectionUrl"> | |||
<h5> {{ notification.text }} </h5> | |||
<p *ngIf="notification.description"> {{ notification.description }} </p> | |||
<span class="time-stamp"> {{ notification.timeStamp }} </span> | |||
</ng-container> | |||
</li> | |||
</ul> |
@@ -0,0 +1,44 @@ | |||
ul { | |||
list-style: none; | |||
height: 100%; | |||
overflow: auto; | |||
min-height: 10rem; | |||
max-height: 40rem; | |||
li { | |||
display: block; | |||
width: calc(100% - 2rem); | |||
padding: 1.5rem; | |||
cursor: pointer; | |||
position: relative; | |||
margin: 1rem auto; | |||
border: 1px solid var(--border-grey); | |||
border-radius: 1rem; | |||
line-height: 1.5; | |||
&:hover { | |||
box-shadow: 0px 0px 10px -4px var(--dark-grey); | |||
} | |||
h5 { | |||
font-size: 1.4rem; | |||
margin: 0 0 0.5rem; | |||
font-weight: 500; | |||
color: var(--highlight); | |||
filter: brightness(80%); | |||
} | |||
p { | |||
color: var(--dark-grey); | |||
font-size: 1.3rem; | |||
} | |||
.time-stamp { | |||
display: block; | |||
margin: 1rem 0 0; | |||
font-size: 3rem; | |||
font-size: 1.3rem; | |||
color: var(--dark-grey); | |||
} | |||
} | |||
} |
@@ -0,0 +1,25 @@ | |||
import { ComponentFixture, TestBed } from '@angular/core/testing'; | |||
import { NotificationsListComponent } from './notifications-list.component'; | |||
describe('NotificationsListComponent', () => { | |||
let component: NotificationsListComponent; | |||
let fixture: ComponentFixture<NotificationsListComponent>; | |||
beforeEach(async () => { | |||
await TestBed.configureTestingModule({ | |||
declarations: [ NotificationsListComponent ] | |||
}) | |||
.compileComponents(); | |||
}); | |||
beforeEach(() => { | |||
fixture = TestBed.createComponent(NotificationsListComponent); | |||
component = fixture.componentInstance; | |||
fixture.detectChanges(); | |||
}); | |||
it('should create', () => { | |||
expect(component).toBeTruthy(); | |||
}); | |||
}); |
@@ -0,0 +1,19 @@ | |||
import { Component, OnInit } from '@angular/core'; | |||
import { Notification, NotificationService } from 'src/app/services/notification.service'; | |||
@Component({ | |||
selector: 'app-notifications-list', | |||
templateUrl: './notifications-list.component.html', | |||
styleUrls: ['./notifications-list.component.scss'] | |||
}) | |||
export class NotificationsListComponent implements OnInit { | |||
allowedNotifications: Array<Notification> = []; | |||
constructor(notificationService: NotificationService) { | |||
this.allowedNotifications = notificationService.getAllowedNotifications(); | |||
} | |||
ngOnInit(): void { | |||
} | |||
} |
@@ -1,14 +1,8 @@ | |||
<ul> | |||
<li *ngFor="let notification of allowedNotifications"> | |||
<a *ngIf="notification.redirectionUrl" [routerLink]="notification.redirectionUrl"> | |||
<h5> {{ notification.text }} </h5> | |||
<p *ngIf="notification.description"> {{ notification.description }} </p> | |||
<span class="time-stamp"> {{ notification.timeStamp }} </span> | |||
</a> | |||
<ng-container *ngIf="!notification.redirectionUrl"> | |||
<h5> {{ notification.text }} </h5> | |||
<p *ngIf="notification.description"> {{ notification.description }} </p> | |||
<span class="time-stamp"> {{ notification.timeStamp }} </span> | |||
</ng-container> | |||
</li> | |||
</ul> | |||
<div class="notifications-window" *ngIf="isShowingNotifications"> | |||
<div class="backdrop" (click)="hideNotifications()"></div> | |||
<header> | |||
<h4> Notifications </h4> | |||
</header> | |||
<app-notifications-list></app-notifications-list> | |||
</div> |
@@ -1,44 +1,54 @@ | |||
ul { | |||
list-style: none; | |||
height: 100%; | |||
overflow: auto; | |||
min-height: 10rem; | |||
max-height: 40rem; | |||
$header-height: 10rem; | |||
li { | |||
display: block; | |||
.notifications-window { | |||
position: fixed; | |||
top: calc(#{$header-height} - 1rem); | |||
background-color: white; | |||
width: 40rem; | |||
box-shadow: 0px 0px 15px -3px var(--dark-grey); | |||
z-index: 2; | |||
right: 26rem; | |||
border-radius: 1.5rem; | |||
overflow: hidden; | |||
header { | |||
height: 5rem; | |||
padding: 0 2rem; | |||
display: flex; | |||
align-items: center; | |||
justify-content: flex-start; | |||
width: calc(100% - 2rem); | |||
padding: 1.5rem; | |||
cursor: pointer; | |||
position: relative; | |||
margin: 1rem auto; | |||
border: 1px solid var(--border-grey); | |||
border-radius: 1rem; | |||
line-height: 1.5; | |||
margin: 1rem auto 0; | |||
position: relative; | |||
overflow: hidden; | |||
&:hover { | |||
box-shadow: 0px 0px 10px -4px var(--dark-grey); | |||
&::before { | |||
content: ''; | |||
position: absolute; | |||
left: 0; | |||
top: 0; | |||
width: 100%; | |||
height: 100%; | |||
background-color: var(--border-grey); | |||
opacity: 0.7; | |||
} | |||
h5 { | |||
font-size: 1.4rem; | |||
margin: 0 0 0.5rem; | |||
h4{ | |||
position: relative; | |||
font-size: 1.7rem; | |||
color: var(--primary); | |||
font-weight: 500; | |||
color: var(--highlight); | |||
filter: brightness(80%); | |||
} | |||
p { | |||
color: var(--dark-grey); | |||
font-size: 1.3rem; | |||
} | |||
} | |||
.time-stamp { | |||
display: block; | |||
margin: 1rem 0 0; | |||
font-size: 3rem; | |||
font-size: 1.3rem; | |||
color: var(--dark-grey); | |||
} | |||
.backdrop { | |||
position: fixed; | |||
left: 0; | |||
top: 0; | |||
width: 100vw; | |||
height: 100vw; | |||
z-index: 0; | |||
} | |||
} |
@@ -1,4 +1,5 @@ | |||
import { Component, OnInit } from '@angular/core'; | |||
import { Component, OnDestroy, OnInit } from '@angular/core'; | |||
import { Subscription } from 'rxjs'; | |||
import { Notification, NotificationService } from 'src/app/services/notification.service'; | |||
@Component({ | |||
@@ -6,14 +7,25 @@ import { Notification, NotificationService } from 'src/app/services/notification | |||
templateUrl: './notifications.component.html', | |||
styleUrls: ['./notifications.component.scss'] | |||
}) | |||
export class NotificationsComponent implements OnInit { | |||
allowedNotifications: Array<Notification> = []; | |||
export class NotificationsComponent implements OnInit, OnDestroy { | |||
isShowingNotifications = false; | |||
isShowingNotificationsSubscription: Subscription; | |||
constructor(notificationService: NotificationService) { | |||
this.allowedNotifications = notificationService.getAllowedNotifications(); | |||
constructor(private notificationService: NotificationService) { | |||
this.isShowingNotificationsSubscription = this.notificationService.getIsShowingNotificationsObservable().subscribe(isShowingNotifications => this.isShowingNotifications = isShowingNotifications); | |||
} | |||
hideNotifications() { | |||
this.notificationService.setIsShowingNotifications(false); | |||
} | |||
ngOnInit(): void { | |||
} | |||
ngOnDestroy(): void { | |||
if (this.isShowingNotificationsSubscription) { | |||
this.isShowingNotificationsSubscription.unsubscribe(); | |||
} | |||
} | |||
} |
@@ -1,50 +1,5 @@ | |||
<section class="navbar"> | |||
<figure class="logo"> | |||
<img src="assets/icons/logo.svg" alt="logo image"> | |||
</figure> | |||
<nav> | |||
<a *ngIf="loginName === 'Officer'" [routerLink]="['/tabs/dashboard']"> Dashboard </a> | |||
<a [routerLink]="['/tabs/e-services']"> E-Services </a> | |||
</nav> | |||
<div class="search-input"> | |||
<input type="text" placeholder="Search for Business Entities"> | |||
<img src="assets/icons/search.svg" alt="search icon"> | |||
</div> | |||
<button class="notification-button" (click)="showNotifications = true" | |||
[ngClass]="{'active' : showNotifications}"> | |||
<img src="assets/icons/bell.svg" alt="bell icon"> | |||
<span class="badge"> {{ notificationsCount }} </span> | |||
</button> | |||
<section class="profile-actions" (mouseover)="showLogout=true" (mouseout)="showLogout=false"> | |||
<ng-container *ngIf="!showLogout"> | |||
<img src="assets/icons/user.svg" alt="user icon"> | |||
<span> Hi, {{ loginName }} </span> | |||
<img src="assets/icons/chevron-down.svg" alt="chevron down image"> | |||
</ng-container> | |||
<ng-container *ngIf="showLogout"> | |||
<a [routerLink]="['/login']"> | |||
<img src="assets/icons/logout.svg" class="logout-icon" alt="logout icon"> | |||
<span> Log me out </span> | |||
<img src="assets/icons/chevron-down.svg" alt="chevron down image"> | |||
</a> | |||
</ng-container> | |||
</section> | |||
</section> | |||
<div class="notifications-window" *ngIf="showNotifications"> | |||
<div class="backdrop" (click)="showNotifications = false"></div> | |||
<header> | |||
<h4> Notifications </h4> | |||
</header> | |||
<app-notifications></app-notifications> | |||
</div> | |||
<app-navbar></app-navbar> | |||
<app-notifications></app-notifications> | |||
<div class="page" [ngClass]="{'blur' : showNotifications}"> | |||
<router-outlet></router-outlet> |
@@ -1,204 +1,5 @@ | |||
$header-height: 10rem; | |||
.navbar { | |||
display: flex; | |||
width: 100%; | |||
height: $header-height; | |||
align-items: center; | |||
justify-content: flex-start; | |||
.logo { | |||
width: 12rem; | |||
margin: 0 2rem; | |||
img { | |||
width: 100%; | |||
height: 100%; | |||
} | |||
} | |||
nav { | |||
margin: 0 2rem; | |||
@media print { | |||
display: none; | |||
} | |||
a { | |||
font-size: 1.6rem; | |||
letter-spacing: 0.5px; | |||
color: var(--dark-grey); | |||
margin-right: 2rem; | |||
&.active { | |||
text-decoration: underline; | |||
color: var(--highlight); | |||
} | |||
&:hover { | |||
text-decoration: underline; | |||
} | |||
} | |||
} | |||
.search-input { | |||
position: relative; | |||
margin-left: auto; | |||
@media print { | |||
display: none; | |||
} | |||
input { | |||
display: block; | |||
height: 5rem; | |||
border: 1px solid var(--border-grey); | |||
border-radius: 4rem; | |||
padding: 0 2.5rem; | |||
width: 35rem; | |||
font-size: 1.5rem; | |||
font-weight: 300; | |||
&::placeholder { | |||
color: var(--dark-grey); | |||
opacity: 0.6; | |||
} | |||
} | |||
img { | |||
position: absolute; | |||
width: 1.8rem; | |||
top: 1.5rem; | |||
right: 1.8rem; | |||
} | |||
} | |||
.notification-button { | |||
width: 5rem; | |||
height: 5rem; | |||
border-radius: 50%; | |||
border: none; | |||
position: relative; | |||
background-color: white; | |||
margin-left: 2rem; | |||
@media print { | |||
display: none; | |||
} | |||
&.active { | |||
box-shadow: 0px 0px 10px -3px var(--primary); | |||
img { | |||
filter: brightness(500%); | |||
} | |||
.badge { | |||
transform: scale(0); | |||
} | |||
&::before { | |||
background-color: var(--highlight); | |||
opacity: 1; | |||
filter: none; | |||
} | |||
} | |||
&:hover { | |||
box-shadow: 0px 0px 10px -3px var(--primary); | |||
} | |||
.badge { | |||
background-color: var(--highlight); | |||
color: white; | |||
font-size: 1.1rem; | |||
border-radius: 7px; | |||
position: absolute; | |||
right: 0; | |||
top: -0.5rem; | |||
width: 2rem; | |||
height: 2rem; | |||
border-radius: 50%; | |||
display: flex; | |||
align-items: center; | |||
justify-content: center; | |||
font-weight: 600; | |||
transition: transform 0.1s; | |||
} | |||
&::before { | |||
content: ''; | |||
position: absolute; | |||
left: 0; | |||
top: 0; | |||
width: 100%; | |||
height: 100%; | |||
background-color: var(--secondary); | |||
opacity: 0.3; | |||
filter: brightness(110%); | |||
border-radius: 50%; | |||
} | |||
& > * { | |||
position: relative; | |||
} | |||
img { | |||
width: 40%; | |||
height: 40%; | |||
} | |||
} | |||
.profile-actions { | |||
margin: 0 2rem; | |||
display: flex; | |||
align-items: center; | |||
justify-content: center; | |||
height: 5rem; | |||
border-radius: 4rem; | |||
padding: 0 2rem; | |||
position: relative; | |||
overflow: hidden; | |||
width: 20rem; | |||
cursor: pointer; | |||
@media print { | |||
display: none; | |||
} | |||
&::before { | |||
content: ''; | |||
position: absolute; | |||
left: 0; | |||
top: 0; | |||
width: 100%; | |||
height: 100%; | |||
background-color: var(--secondary); | |||
opacity: 0.3; | |||
filter: brightness(110%); | |||
} | |||
& > * { | |||
position: relative; | |||
} | |||
img { | |||
width: 1.5rem; | |||
&.logout-icon { | |||
transform: scale(1.5); | |||
} | |||
} | |||
span { | |||
margin: 0 auto; | |||
color: var(--primary); | |||
font-size: 1.4rem; | |||
} | |||
} | |||
} | |||
.notifications-window { | |||
position: fixed; | |||
top: calc(#{$header-height} - 1rem); | |||
@@ -4,83 +4,164 @@ | |||
</h2> | |||
</header> | |||
<header class="page-heading"> | |||
<h1> Non compliance - COM/LLPs </h1> | |||
<p> A search module to filter down non compliant entities </p> | |||
</header> | |||
<div class="content-holder"> | |||
<section class="sidebar"> | |||
<div class="filter-card-holder"> | |||
<app-filter-view-card | |||
text="1 outstanding AR and no late filings for the past 5 years" | |||
[count]="10" | |||
(click)="updateSearchOptions('Green', 'All')" | |||
></app-filter-view-card> | |||
</div> | |||
<div class="filter-card-holder"> | |||
<app-filter-view-card | |||
text="1st Enforcement Letter generated" | |||
[count]="5" | |||
(click)="updateSearchOptions('Green', '1st Enforcement Letter')" | |||
></app-filter-view-card> | |||
</div> | |||
<div class="filter-card-holder"> | |||
<app-filter-view-card | |||
text="2nd Enforcement Letter generated" | |||
[count]="5" | |||
(click)="updateSearchOptions('Green', '2nd Enforcement Letter')" | |||
></app-filter-view-card> | |||
</div> | |||
<div class="form-holder"> | |||
<div class="two-column-holder"> | |||
<app-select-input | |||
label="Entity type" | |||
[options]="entityTypeOptions" | |||
></app-select-input> | |||
<app-select-input | |||
label="Category" | |||
[value]="selectedCategory" | |||
[options]="categoryOptions" | |||
<div class="filter-card-holder"> | |||
<app-filter-view-card | |||
text="2 outstanding AR and at least 1 late filings" | |||
[count]="3" | |||
type="AMBER" | |||
(click)="updateSearchOptions('Amber', 'All')" | |||
></app-filter-view-card> | |||
</div> | |||
<div class="filter-card-holder"> | |||
<app-filter-view-card | |||
text="1st Enforcement Letter generated" | |||
[count]="2" | |||
type="AMBER" | |||
(click)="updateSearchOptions('Amber', '1st Enforcement Letter')" | |||
></app-filter-view-card> | |||
</div> | |||
<div class="filter-card-holder"> | |||
<app-filter-view-card | |||
text="2nd Enforcement Letter generated" | |||
[count]="2" | |||
type="AMBER" | |||
(click)="updateSearchOptions('Amber', '2nd Enforcement Letter')" | |||
></app-filter-view-card> | |||
</div> | |||
(onChange)="updateSelectedCategory($event)" | |||
></app-select-input> | |||
<app-generic-input | |||
type="text" | |||
label="UEN" | |||
></app-generic-input> | |||
<app-select-input | |||
label="Enforcment status" | |||
[options]="enforcementStatusOptions" | |||
></app-select-input> | |||
<app-date-input | |||
label="AR/AD From date" | |||
></app-date-input> | |||
<app-date-input | |||
label="AR/AD To date" | |||
></app-date-input> | |||
</div> | |||
<div class="form-action-buttons"> | |||
<button class="common-button" (click)="submitSearch()"> | |||
Submit | |||
</button> | |||
<button class="common-button neutral" (click)="resetSearch()"> | |||
Reset | |||
</button> | |||
</div> | |||
<div class="filter-card-holder"> | |||
<app-filter-view-card | |||
text="2 or more outstanding AR" | |||
[count]="4" | |||
type="RED" | |||
(click)="updateSearchOptions('Red', 'All')" | |||
></app-filter-view-card> | |||
</div> | |||
<div class="filter-card-holder"> | |||
<app-filter-view-card | |||
text="1st Enforcement Letter generated" | |||
[count]="1" | |||
type="RED" | |||
(click)="updateSearchOptions('Red', '1st Enforcement Letter')" | |||
></app-filter-view-card> | |||
</div> | |||
<div class="filter-card-holder"> | |||
<app-filter-view-card | |||
text="2nd Enforcement Letter generated" | |||
[count]="2" | |||
type="RED" | |||
(click)="updateSearchOptions('Red', '2nd Enforcement Letter')" | |||
></app-filter-view-card> | |||
</div> | |||
</section> | |||
<main> | |||
<section class="table" *ngIf="isShowingResults"> | |||
<header> | |||
<div class="cell"> S/N </div> | |||
<div class="cell"> UEN </div> | |||
<div class="cell"> Compliance ID </div> | |||
<div class="cell"> Entity name </div> | |||
<div class="cell"> Last FYE </div> | |||
<div class="cell"> Enforcment status </div> | |||
<div class="cell"> Actions </div> | |||
<header class="page-heading"> | |||
<h1> Non compliance - COM/LLPs </h1> | |||
<p> A search module to filter down non compliant entities </p> | |||
</header> | |||
<ul> | |||
<li> | |||
<div class="cell"> 1 </div> | |||
<div class="cell"> 001 </div> | |||
<div class="cell"> 20190027N </div> | |||
<div class="cell"> ABC PTE.LTD </div> | |||
<div class="cell"> 01/01/2021 </div> | |||
<div class="cell"> Closed </div> | |||
<div class="cell"> | |||
<button [routerLink]="['/tabs/investigate-business-entities-and-individuals']"> Initiate Enforcment </button> | |||
</div> | |||
</li> | |||
<li> | |||
<div class="cell"> 2 </div> | |||
<div class="cell"> 002 </div> | |||
<div class="cell"> 20190027M </div> | |||
<div class="cell"> DEF PTE.LTD </div> | |||
<div class="cell"> 01/01/2020 </div> | |||
<div class="cell"> 1st EF letter </div> | |||
<div class="cell"> | |||
<button> Supress </button> | |||
</div> | |||
</li> | |||
</ul> | |||
</section> | |||
</div> | |||
<div class="form-holder"> | |||
<div class="two-column-holder"> | |||
<app-select-input | |||
label="Entity type" | |||
[options]="entityTypeOptions" | |||
></app-select-input> | |||
<app-select-input | |||
label="Category" | |||
[value]="selectedCategory" | |||
[options]="categoryOptions" | |||
(onChange)="updateSelectedCategory($event)" | |||
></app-select-input> | |||
<app-generic-input | |||
type="text" | |||
label="UEN" | |||
></app-generic-input> | |||
<app-select-input | |||
label="Enforcment status" | |||
[value]="selectedEnforcementStatus" | |||
[options]="enforcementStatusOptions" | |||
(onChange)="updateSelectedEnforcementStatus($event)" | |||
></app-select-input> | |||
<app-date-input | |||
label="AR/AD From date" | |||
></app-date-input> | |||
<app-date-input | |||
label="AR/AD To date" | |||
></app-date-input> | |||
</div> | |||
<div class="form-action-buttons"> | |||
<button class="common-button" (click)="submitSearch()"> | |||
Submit | |||
</button> | |||
<button class="common-button neutral" (click)="resetSearch()"> | |||
Reset | |||
</button> | |||
</div> | |||
<section class="table" *ngIf="isShowingResults"> | |||
<header> | |||
<div class="cell"> S/N </div> | |||
<div class="cell"> UEN </div> | |||
<div class="cell"> Compliance ID </div> | |||
<div class="cell"> Entity name </div> | |||
<div class="cell"> Last FYE </div> | |||
<div class="cell"> Enforcment status </div> | |||
<div class="cell"> Actions </div> | |||
</header> | |||
<ul> | |||
<li> | |||
<div class="cell"> 1 </div> | |||
<div class="cell"> 001 </div> | |||
<div class="cell"> 20190027N </div> | |||
<div class="cell"> ABC PTE.LTD </div> | |||
<div class="cell"> 01/01/2021 </div> | |||
<div class="cell"> Closed </div> | |||
<div class="cell"> | |||
<button [routerLink]="['/tabs/investigate-business-entities-and-individuals']"> Initiate Enforcment </button> | |||
</div> | |||
</li> | |||
<li> | |||
<div class="cell"> 2 </div> | |||
<div class="cell"> 002 </div> | |||
<div class="cell"> 20190027M </div> | |||
<div class="cell"> DEF PTE.LTD </div> | |||
<div class="cell"> 01/01/2020 </div> | |||
<div class="cell"> 1st EF letter </div> | |||
<div class="cell"> | |||
<button> Supress </button> | |||
</div> | |||
</li> | |||
</ul> | |||
</section> | |||
</div> | |||
</main> | |||
</div> |
@@ -1,3 +1,26 @@ | |||
.content-holder { | |||
position: relative; | |||
display: flex; | |||
width: calc(80% - 2rem); | |||
margin: 0 auto; | |||
.sidebar { | |||
position: sticky; | |||
top: 30px; | |||
flex-basis: 250px; | |||
margin-right: 30px; | |||
height: 80vh; | |||
} | |||
main { | |||
flex-grow: 1; | |||
} | |||
} | |||
.filter-card-holder { | |||
margin-bottom: 5px; | |||
} | |||
.page-heading { | |||
text-align: center; | |||
line-height: 1.5; | |||
@@ -21,7 +44,6 @@ | |||
} | |||
.form-holder { | |||
width: calc(70% - 2rem); | |||
padding: 4rem; | |||
margin: 0 auto; | |||
} | |||
@@ -15,18 +15,21 @@ export class DashboardComponent implements OnInit { | |||
]; | |||
categoryOptions = [ | |||
'All', | |||
'Green', | |||
'Amber', | |||
'Red', | |||
]; | |||
enforcementStatusOptions = [ | |||
'All', | |||
'1st Enforcement Letter', | |||
'2nd Enforcement Letter', | |||
'Suppressed', | |||
]; | |||
selectedCategory = ''; | |||
selectedEnforcementStatus = ''; | |||
constructor() { } | |||
@@ -38,6 +41,8 @@ export class DashboardComponent implements OnInit { | |||
} | |||
resetSearch() { | |||
this.selectedCategory = ''; | |||
this.selectedEnforcementStatus = ''; | |||
this.isShowingResults = false; | |||
} | |||
@@ -45,4 +50,14 @@ export class DashboardComponent implements OnInit { | |||
this.selectedCategory = selectedCategory; | |||
} | |||
updateSelectedEnforcementStatus(selectedEnforcementStatus: string) { | |||
this.selectedEnforcementStatus = selectedEnforcementStatus; | |||
} | |||
updateSearchOptions(selectedCategory: string, selectedEnforcementStatus: string) { | |||
this.selectedCategory = selectedCategory; | |||
this.selectedEnforcementStatus = selectedEnforcementStatus; | |||
this.isShowingResults = true; | |||
} | |||
} |
@@ -0,0 +1,6 @@ | |||
<section class="card" [ngClass]="{'green': type === 'GREEN', 'amber': type === 'AMBER', 'red': type === 'RED'}"> | |||
<div class="content"> | |||
<div class="text">{{ text }}</div> | |||
<div class="count">{{ count }}</div> | |||
</div> | |||
</section> |
@@ -0,0 +1,52 @@ | |||
$red: hsl(0, 100%, 73%); | |||
$amber: hsl(55, 60%, 73%); | |||
$green: hsl(120, 100%, 73%); | |||
.card { | |||
padding: 15px; | |||
background-color: #e7e7e7; | |||
&.green { | |||
background-color: lighten($green, 22%); | |||
.content { | |||
border-color: $green; | |||
} | |||
} | |||
&.amber { | |||
background-color: lighten($amber, 22%); | |||
.content { | |||
border-color: $amber; | |||
} | |||
} | |||
&.red { | |||
background-color: lighten($red, 22%); | |||
.content { | |||
border-color: $red; | |||
} | |||
} | |||
} | |||
.content { | |||
display: flex; | |||
border-left: 3px solid black; | |||
padding: 2px 0 2px 10px; | |||
font-weight: 300; | |||
line-height: 1.4; | |||
align-items: center; | |||
.text { | |||
font-size: 1.3rem; | |||
flex-grow: 1; | |||
margin-right: 20px; | |||
} | |||
.count { | |||
font-size: 1.4rem; | |||
font-weight: bold; | |||
} | |||
} |
@@ -0,0 +1,25 @@ | |||
import { ComponentFixture, TestBed } from '@angular/core/testing'; | |||
import { FilterViewCardComponent } from './filter-view-card.component'; | |||
describe('FilterViewCardComponent', () => { | |||
let component: FilterViewCardComponent; | |||
let fixture: ComponentFixture<FilterViewCardComponent>; | |||
beforeEach(async () => { | |||
await TestBed.configureTestingModule({ | |||
declarations: [ FilterViewCardComponent ] | |||
}) | |||
.compileComponents(); | |||
}); | |||
beforeEach(() => { | |||
fixture = TestBed.createComponent(FilterViewCardComponent); | |||
component = fixture.componentInstance; | |||
fixture.detectChanges(); | |||
}); | |||
it('should create', () => { | |||
expect(component).toBeTruthy(); | |||
}); | |||
}); |
@@ -0,0 +1,18 @@ | |||
import { Component, Input, OnInit } from '@angular/core'; | |||
@Component({ | |||
selector: 'app-filter-view-card', | |||
templateUrl: './filter-view-card.component.html', | |||
styleUrls: ['./filter-view-card.component.scss'] | |||
}) | |||
export class FilterViewCardComponent implements OnInit { | |||
@Input() type: 'GREEN'|'AMBER'|'RED' = 'GREEN'; | |||
@Input() text = ''; | |||
@Input() count = 0; | |||
constructor() { } | |||
ngOnInit(): void { | |||
} | |||
} |
@@ -7,323 +7,4 @@ | |||
margin-right: 2rem; | |||
} | |||
} | |||
} | |||
.form { | |||
display: grid; | |||
grid-template-columns: 1fr 1fr; | |||
width: calc(70% - 2rem); | |||
padding: 4rem; | |||
margin: 0 auto; | |||
.input-holder { | |||
width: calc(100% - 2rem); | |||
} | |||
} | |||
.acknowledgement { | |||
width: 100%; | |||
margin: 0 auto; | |||
h2 { | |||
font-size: 2rem; | |||
color: var(--dark-grey); | |||
filter: brightness(80%); | |||
font-weight: 500; | |||
margin: 2rem 2rem 3rem; | |||
} | |||
.container { | |||
width: calc(70% - 2rem); | |||
margin: 2rem auto; | |||
@media print { | |||
width: calc(100% - 2rem); | |||
} | |||
} | |||
.bill-container { | |||
width: 70%; | |||
box-shadow: 0 0 10px var(--shadow-grey); | |||
border-radius: 1rem; | |||
overflow: hidden; | |||
margin: 0 auto 5rem; | |||
@media print { | |||
width: 100%; | |||
} | |||
} | |||
.check-icon { | |||
display: block; | |||
width: 58px; | |||
height: auto; | |||
margin: 3rem auto 2rem; | |||
} | |||
h3 { | |||
font-size: 3rem; | |||
font-weight: normal; | |||
text-align: center; | |||
color: var(--success); | |||
} | |||
.bill-breakup { | |||
margin-top: 3rem; | |||
display: grid; | |||
grid-template-columns: 1fr 1fr; | |||
list-style: none; | |||
li { | |||
margin: 1.8rem; | |||
width: 100%; | |||
} | |||
label { | |||
display: block; | |||
color: var(--dark-grey); | |||
font-size: 1.6rem; | |||
filter: brightness(80%); | |||
} | |||
.value { | |||
display: block; | |||
color: var(--dark-grey); | |||
opacity: 0.8; | |||
font-size: 1.6rem; | |||
letter-spacing: 0.5px; | |||
line-height: 1.6; | |||
margin-top: 1rem; | |||
&.active { | |||
color: var(--highlight); | |||
font-weight: normal; | |||
} | |||
} | |||
} | |||
.form-action-buttons { | |||
margin: 2rem 1.5rem; | |||
@media print { | |||
display: none; | |||
} | |||
} | |||
.total-amount { | |||
text-align: center; | |||
overflow: hidden; | |||
padding: 1rem; | |||
position: relative; | |||
&::before { | |||
content: ''; | |||
position: absolute; | |||
left: 0; | |||
top: 0; | |||
width: 100%; | |||
height: 100%; | |||
background-color: var(--footer-grey); | |||
opacity: 0.4; | |||
} | |||
& > * { | |||
position: relative; | |||
} | |||
label { | |||
font-size: 2rem; | |||
color: var(--dark-grey); | |||
} | |||
span { | |||
margin-left: 1rem; | |||
font-size: 2.4rem; | |||
color: var(--highlight); | |||
} | |||
} | |||
.message-board { | |||
padding: 0 2rem; | |||
list-style: none; | |||
@media print { | |||
display: none; | |||
} | |||
h5 { | |||
font-size: 1.6rem; | |||
color: var(--dark-grey); | |||
filter: brightness(80%); | |||
font-weight: 500; | |||
} | |||
li { | |||
margin: 1.5rem 0; | |||
line-height: 1.7; | |||
letter-spacing: 0.5px; | |||
font-size: 1.4rem; | |||
color: var(--dark-grey); | |||
opacity: 0.8; | |||
a { | |||
color: var(--highlight); | |||
font-weight: 500; | |||
} | |||
} | |||
} | |||
} | |||
.receipt { | |||
width: calc(100% - 4rem); | |||
margin: 0 auto; | |||
h2 { | |||
font-size: 2rem; | |||
color: var(--dark-grey); | |||
filter: brightness(80%); | |||
font-weight: 500; | |||
margin: 2rem 0; | |||
} | |||
.bill-breakup { | |||
display: grid; | |||
grid-template-columns: 1fr 1fr; | |||
list-style: none; | |||
li { | |||
margin-bottom: 1rem; | |||
width: 100%; | |||
display: flex; | |||
align-items: center; | |||
justify-content: flex-start; | |||
} | |||
label { | |||
display: block; | |||
color: var(--dark-grey); | |||
font-size: 1.4rem; | |||
} | |||
.value { | |||
display: block; | |||
color: var(--dark-grey); | |||
opacity: 0.8; | |||
font-size: 1.6rem; | |||
letter-spacing: 0.5px; | |||
line-height: 1.6; | |||
margin-left: 1rem; | |||
} | |||
} | |||
.table { | |||
margin: 2rem auto; | |||
width: 100%; | |||
border-radius: 1rem; | |||
overflow: auto; | |||
border: 2px solid var(--border-grey); | |||
min-height: 10rem; | |||
header { | |||
background: linear-gradient(90deg, var(--secondary) 0%, var(--primary)); | |||
color: white; | |||
font-size: 1.6rem; | |||
display: flex; | |||
align-items: center; | |||
justify-content: flex-start; | |||
height: 5.5rem; | |||
font-weight: 300; | |||
letter-spacing: 0.5px; | |||
} | |||
.cell { | |||
width: calc(100% / 6); | |||
@media print { | |||
word-break: break-all; | |||
} | |||
&:nth-child(1) { | |||
text-align: center; | |||
width: 10rem; | |||
} | |||
&:nth-child(2) { | |||
width: calc(20% + (10% - 10rem)); | |||
} | |||
&:nth-child(3) { | |||
width: 20%; | |||
} | |||
&:nth-child(4) { | |||
width: 20%; | |||
} | |||
&:nth-child(5) { | |||
width: 10%; | |||
} | |||
&:nth-child(3) { | |||
width: 20%; | |||
} | |||
} | |||
ul { | |||
list-style: none; | |||
} | |||
li { | |||
display: flex; | |||
align-items: flex-start; | |||
justify-content: flex-start; | |||
padding: 2rem 0; | |||
&:nth-child(even) { | |||
background-color: var(--border-grey); | |||
} | |||
.cell { | |||
font-size: 1.4rem; | |||
color: var(--dark-grey); | |||
line-height: 1.7; | |||
} | |||
} | |||
} | |||
.message-board { | |||
width: 100%; | |||
margin: 4rem 0; | |||
list-style: none; | |||
h5 { | |||
font-size: 1.6rem; | |||
color: var(--dark-grey); | |||
filter: brightness(80%); | |||
font-weight: 500; | |||
margin-bottom: 1rem; | |||
} | |||
li { | |||
margin: 0.5rem 0; | |||
line-height: 1.7; | |||
letter-spacing: 0.5px; | |||
font-size: 1.4rem; | |||
color: var(--dark-grey); | |||
opacity: 0.8; | |||
a { | |||
color: var(--highlight); | |||
font-weight: 500; | |||
} | |||
} | |||
} | |||
.form-action-buttons { | |||
text-align: left; | |||
@media print { | |||
display: none; | |||
} | |||
} | |||
} |
@@ -1,4 +1,5 @@ | |||
import { Injectable } from '@angular/core'; | |||
import { BehaviorSubject } from 'rxjs'; | |||
import { LoginService, Role } from './login.service'; | |||
export interface Notification { | |||
@@ -14,6 +15,8 @@ export interface Notification { | |||
}) | |||
export class NotificationService { | |||
private isShowingNotificationsSubject = new BehaviorSubject(false); | |||
private notifications: Array<Notification> = [{ | |||
text: 'New name application has been submitted', | |||
description: 'A new Applicant in the company name Kimao has applied for an appeal', | |||
@@ -64,7 +67,7 @@ export class NotificationService { | |||
timeStamp: '1 hour ago', | |||
redirectionUrl: '/tabs/investigate-business-entities-and-individuals', | |||
}]; | |||
private allowedNotifications: Array<Notification> = []; | |||
constructor(loginService: LoginService) { | |||
@@ -75,4 +78,12 @@ export class NotificationService { | |||
getAllowedNotifications() { | |||
return this.allowedNotifications; | |||
} | |||
getIsShowingNotificationsObservable() { | |||
return this.isShowingNotificationsSubject.asObservable(); | |||
} | |||
setIsShowingNotifications(isShowingNotifications: boolean) { | |||
this.isShowingNotificationsSubject.next(isShowingNotifications); | |||
} | |||
} |