Skip to content

Commit

Permalink
Merge pull request #2079 from bcgov/feature/ALCS-2226
Browse files Browse the repository at this point in the history
ALCS-2226: Add flagging to apps/NOI's
  • Loading branch information
trslater authored Jan 23, 2025
2 parents cef6116 + 245272f commit d78553a
Show file tree
Hide file tree
Showing 37 changed files with 1,040 additions and 138 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,24 @@ <h5>Res #{{ decision.resolutionNumber }}/{{ decision.resolutionYear }}</h5>
<app-application-type-pill [type]="releasedDecisionLabel"></app-application-type-pill>
</ng-container>
</div>

<div class="flag-button-container">
<button
type="button"
(click)="decision.isFlagged ? unflag(decision) : flag(decision, false)"
class="flag-button"
[class.flagged]="decision.isFlagged"
[matTooltip]="decision.isFlagged ? 'Click to unflag' : ''"
>
<mat-icon svgIcon="personal_places"></mat-icon>
Flag{{ decision.isFlagged ? 'ged' : '' }} for Condition Follow Up
</button>
</div>

<ng-container *ngIf="decision.isDraft">
<button mat-flat-button color="primary" (click)="onEdit(decision)">Edit Draft</button>
<button class="edit-decision-button" mat-flat-button color="primary" (click)="onEdit(decision)">
Edit Draft
</button>
</ng-container>

<div
Expand Down Expand Up @@ -183,6 +199,28 @@ <h5>Res #{{ decision.resolutionNumber }}/{{ decision.resolutionYear }}</h5>
</button>
</div>
</div>

<ng-container *ngIf="decision.isFlagged">
<section class="flag-details">
<div class="flag-details-header">
<div class="flag-details-flagger">
<mat-icon svgIcon="personal_places"></mat-icon><strong>{{ decision.flaggedBy?.prettyName }}</strong>
</div>
<div><strong>Follow-Up Date:</strong> {{ formatDate(decision.followUpAt) || 'No Data' }}</div>
</div>

<div class="flag-details-body">
<strong>Flagged for condition follow-up because:</strong> {{ decision.reasonFlagged }}
</div>

<div class="flag-details-footer">
<div class="flag-details-edited-details">
{{ formatDate(decision.flagEditedAt, true) }} (Last Edited by {{ decision.flagEditedBy?.prettyName }})
</div>
<button mat-button type="button" (click)="flag(decision, true)">Edit</button>
</div>
</section>
</ng-container>
</section>
<ng-container *ngIf="isSummary">
<!-- Components -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,20 @@ hr {
}

.header {
display: flex;
justify-content: space-between;
display: grid;
grid-template-columns: auto auto auto;
grid-template-rows: auto auto;
row-gap: 10px;
column-gap: 28px;
margin-bottom: 36px;

.title {
display: flex;
align-items: center;
justify-content: space-between;
gap: 28px;
grid-row: 1/2;
grid-column: 1/2;

.days {
display: inline-block;
Expand All @@ -78,6 +83,11 @@ hr {
}
}

.edit-decision-button {
grid-row: 1/2;
grid-column: 3/4;
}

.loading-overlay {
position: absolute;
z-index: 2;
Expand Down Expand Up @@ -187,3 +197,85 @@ hr {
color: colors.$link-color;
}
}

.flag-button-container {
justify-self: end;
grid-row: 2/3;
grid-column: 1/4;

@media screen and (min-width: 1440px) {
grid-row: 1/2;
grid-column: 2/3;
}
}

.flag-button {
display: flex;
align-items: center;
column-gap: 5px;

text-align: left;
font-weight: normal;
text-wrap: nowrap;

background-color: transparent;
padding: 5px;
border: none;
border-radius: 5px;
margin: 0;

&:hover {
background-color: colors.$grey-light;
}

mat-icon {
flex-shrink: 0;
}

&.flagged {
mat-icon {
color: blue;
}
}
}

.flag-details {
background-color: white;
display: flex;
flex-direction: column;
gap: 16px;

padding: 16px;
border: 1px solid colors.$grey;
border-radius: 4px;
}

.flag-details-header {
display: flex;
justify-content: space-between;
align-items: center;
}

.flag-details-flagger {
display: flex;
gap: 5px;

mat-icon {
color: blue;
}
}

.flag-details-body {
line-height: 1.5;
}

.flag-details-footer {
display: flex;
justify-content: space-between;
align-items: flex-end;
}

.flag-details-edited-details {
font-size: 12px;
color: colors.$grey;
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@ import {
import { ApplicationDecisionV2Service } from '../../../../services/application/decision/application-decision-v2/application-decision-v2.service';
import { ToastService } from '../../../../services/toast/toast.service';
import { ConfirmationDialogService } from '../../../../shared/confirmation-dialog/confirmation-dialog.service';

import { DecisionV2Component } from './decision-v2.component';
import { HttpClient } from '@angular/common/http';

describe('DecisionV2Component', () => {
let component: DecisionV2Component;
let fixture: ComponentFixture<DecisionV2Component>;
let mockApplicationDecisionService: DeepMocked<ApplicationDecisionV2Service>;
let mockAppDetailService: DeepMocked<ApplicationDetailService>;
let mockApplicationDecisionComponentService: DeepMocked<ApplicationDecisionComponentService>;
let mockHttpClient: DeepMocked<HttpClient>;

beforeEach(async () => {
mockApplicationDecisionService = createMock();
Expand All @@ -36,6 +37,8 @@ describe('DecisionV2Component', () => {

mockApplicationDecisionComponentService = createMock();

mockHttpClient = createMock();

await TestBed.configureTestingModule({
imports: [MatSnackBarModule, MatMenuModule],
declarations: [DecisionV2Component],
Expand Down Expand Up @@ -72,6 +75,10 @@ describe('DecisionV2Component', () => {
provide: ActivatedRoute,
useValue: {},
},
{
provide: HttpClient,
useValue: mockHttpClient,
},
],
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ import { formatDateForApi } from '../../../../shared/utils/api-date-formatter';
import { RevertToDraftDialogComponent } from './revert-to-draft-dialog/revert-to-draft-dialog.component';
import { ApplicationConditionWithStatus, getEndDate } from '../../../../shared/utils/decision-methods';
import { openFileInline } from '../../../../shared/utils/file';
import { UserService } from '../../../../services/user/user.service';
import { UserDto } from '../../../../services/user/user.dto';
import { FlagDialogComponent, FlagDialogIO } from '../../../../shared/flag-dialog/flag-dialog.component';
import { UpdateApplicationDecisionDto } from '../../../../services/application/decision/application-decision-v2/application-decision-v2.dto';
import moment from 'moment';

type LoadingDecision = ApplicationDecisionWithLinkedResolutionDto & {
loading: boolean;
Expand Down Expand Up @@ -67,6 +72,7 @@ export class DecisionV2Component implements OnInit, OnDestroy {
isSummary = false;

conditions: Record<string, ApplicationConditionWithStatus[]> = {};
profile: UserDto | undefined;

constructor(
public dialog: MatDialog,
Expand All @@ -78,6 +84,7 @@ export class DecisionV2Component implements OnInit, OnDestroy {
private router: Router,
private activatedRouter: ActivatedRoute,
private elementRef: ElementRef,
private userService: UserService,
) {}

ngOnInit(): void {
Expand All @@ -90,6 +97,10 @@ export class DecisionV2Component implements OnInit, OnDestroy {
this.application = application;
}
});

this.userService.$userProfile.pipe(takeUntil(this.$destroy)).subscribe((profile) => {
this.profile = profile;
});
}

async loadDecisions(fileNumber: string) {
Expand Down Expand Up @@ -324,4 +335,81 @@ export class DecisionV2Component implements OnInit, OnDestroy {
return DECISION_CONDITION_ONGOING_LABEL;
}
}

async flag(decision: ApplicationDecisionWithLinkedResolutionDto, isEditing: boolean) {
this.dialog
.open(FlagDialogComponent, {
minWidth: '800px',
maxWidth: '800px',
maxHeight: '80vh',
width: '90%',
autoFocus: false,
data: {
isEditing,
decisionNumber: decision.index,
reasonFlagged: decision.reasonFlagged,
followUpAt: decision.followUpAt,
},
})
.beforeClosed()
.subscribe(async ({ isEditing, reasonFlagged, followUpAt, isSaving }: FlagDialogIO) => {
if (isSaving) {
const updateDto: UpdateApplicationDecisionDto = {
isDraft: decision.isDraft,
isFlagged: true,
reasonFlagged,
flagEditedByUuid: this.profile?.uuid,
flagEditedAt: moment().toDate().getTime(),
};

if (!isEditing) {
updateDto.flaggedByUuid = this.profile?.uuid;
}

if (followUpAt !== undefined) {
updateDto.followUpAt = followUpAt;
}

await this.decisionService.update(decision.uuid, updateDto);
await this.loadDecisions(this.fileNumber);
}
});
}

async unflag(decision: ApplicationDecisionWithLinkedResolutionDto) {
this.confirmationDialogService
.openDialog({
title: `Unflag Decision #${decision.index}`,
body: `<strong>Warning:</strong> Only remove if flagged in error.
<br>
<br>
This action will also remove the follow-up date and explanatory text
associated with the flag and cannot be undone.
<br>
<br>
Are you sure you want to remove the flag?`,
})
.subscribe(async (confirmed) => {
if (confirmed) {
await this.decisionService.update(decision.uuid, {
isDraft: decision.isDraft,
isFlagged: false,
reasonFlagged: null,
followUpAt: null,
flaggedByUuid: null,
flagEditedByUuid: null,
flagEditedAt: null,
});
await this.loadDecisions(this.fileNumber);
}
});
}

formatDate(timestamp?: number | null, includeTime = false): string {
if (timestamp === undefined || timestamp === null) {
return '';
}

return moment(new Date(timestamp)).format(`YYYY-MMM-DD ${includeTime ? 'hh:mm:ss A' : ''}`);
}
}
1 change: 1 addition & 0 deletions alcs-frontend/src/app/features/board/board.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,7 @@ export class BoardComponent implements OnInit, OnDestroy {
dateReceived: 0,
isExpired,
isPastDue,
decisionIsFlagged: applicationDecisionCondition.decisionIsFlagged,
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ <h3 class="card-title">
[type]="getStatusPill('RECONSIDERATION')"
></app-application-type-pill>
<app-application-type-pill [type]="getStatusPill('CONDITION')"></app-application-type-pill>

<mat-icon *ngIf="decision.isFlagged" svgIcon="personal_places" class="flag-icon"></mat-icon>
</div>
<div class="header-row">
<div class="left">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,15 @@
.pill-row {
display: flex;
flex-direction: row;
align-items: flex-end;
gap: 1px;
}

.no-data {
color: colors.$grey;
font-weight: 400;
}

.flag-icon {
color: blue;
}
Loading

0 comments on commit d78553a

Please sign in to comment.