Skip to content

Commit

Permalink
Merge pull request #959 from bcgov/feature/ALCS-1032
Browse files Browse the repository at this point in the history
Add Required Errors to Soil and Structure Tables
  • Loading branch information
dhaselhan authored Sep 8, 2023
2 parents 985eb6a + 0f88b00 commit 097a7d8
Show file tree
Hide file tree
Showing 5 changed files with 231 additions and 132 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,58 +60,85 @@ <h6>Documents needed for this step:</h6>
</mat-hint>
</div>
<div class="full-row">
<label for="purpose">Enter your proposed lot areas (ha)</label>
<table mat-table [dataSource]="lotsSource">
<ng-container matColumnDef="index">
<th mat-header-cell *matHeaderCellDef>#</th>
<td mat-cell *matCellDef="let i = index">{{ i + 1 }}</td>
</ng-container>
<form [formGroup]="lotsForm">
<label for="purpose">Enter your proposed lot areas (ha)</label>
<table class="proposed-lots" mat-table [dataSource]="lotsSource">
<ng-container matColumnDef="index">
<th mat-header-cell *matHeaderCellDef>#</th>
<td mat-cell *matCellDef="let i = index">{{ i + 1 }}</td>
</ng-container>

<ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef>Type</th>
<td mat-cell *matCellDef="let element; let i = index">
<mat-form-field appearance="outline">
<mat-select [value]="element.type" placeholder="Please select" (valueChange)="onChangeLotType(i, $event)">
<mat-option value="Lot"> Lot </mat-option>
<mat-option value="Road Dedication"> Road Dedication </mat-option>
</mat-select>
</mat-form-field>
</td>
</ng-container>
<ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef>Type</th>
<td mat-cell *matCellDef="let element; let i = index">
<mat-form-field appearance="outline">
<mat-select
placeholder="Please select"
required
[formControlName]="i + '-type'"
(valueChange)="onChangeLotType(i, $event)"
>
<mat-option value="Lot"> Lot </mat-option>
<mat-option value="Road Dedication"> Road Dedication </mat-option>
</mat-select>
</mat-form-field>
<div
*ngIf="
lotsForm.controls[i + '-type']!.invalid &&
(lotsForm.controls[i + '-type']!.dirty || lotsForm.controls[i + '-type']!.touched)
"
class="field-error"
>
<mat-icon>warning</mat-icon>
<div *ngIf="lotsForm.controls[i + '-type']!.errors?.['required']">This field is required</div>
</div>
</td>
</ng-container>

<ng-container matColumnDef="size">
<th mat-header-cell *matHeaderCellDef>Size</th>
<td mat-cell *matCellDef="let element; let i = index">
<mat-form-field appearance="outline">
<input
[(ngModel)]="element.size"
type="text"
matInput
thousandSeparator=","
mask="separator.2"
separatorLimit="9999999999"
min="0.01"
placeholder="Type size in hectares"
[ngModelOptions]="{ standalone: true }"
(change)="onChangeLotSize()"
/>
<span *ngIf="element.size" matTextSuffix>ha</span>
</mat-form-field>
</td>
</ng-container>
<ng-container matColumnDef="size">
<th mat-header-cell *matHeaderCellDef>Size</th>
<td mat-cell *matCellDef="let element; let i = index">
<mat-form-field appearance="outline">
<input
type="text"
matInput
thousandSeparator=","
mask="separator.2"
separatorLimit="9999999999"
min="0.01"
required
placeholder="Type size in hectares"
[formControlName]="i + '-size'"
(change)="onChangeLotSize()"
/>
<span *ngIf="element.size" matTextSuffix>ha</span>
</mat-form-field>
<div
*ngIf="
lotsForm.controls[i + '-size']!.invalid &&
(lotsForm.controls[i + '-size']!.dirty || lotsForm.controls[i + '-size']!.touched)
"
class="field-error"
>
<mat-icon>warning</mat-icon>
<div *ngIf="lotsForm.controls[i + '-size']!.errors?.['required']">This field is required</div>
</div>
</td>
</ng-container>

<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>

<tr class="mat-row no-data" *matNoDataRow>
<td class="text-center" colspan="7">No Proposed Lots Entered</td>
</tr>
</table>
<div>Total area of the proposed lots: {{ totalAcres }} ha</div>
<div *ngIf="totalAcres !== '0' && totalAcres !== totalTargetAcres" class="field-error">
<mat-icon>warning</mat-icon>
<div>The total lot area proposed must match {{ totalTargetAcres }} hectares as provided in Step 1</div>
</div>
<tr class="mat-row no-data" *matNoDataRow>
<td class="text-center" colspan="7">No Proposed Lots Entered</td>
</tr>
</table>
<div>Total area of the proposed lots: {{ totalAcres }} ha</div>
<div *ngIf="totalAcres !== '0' && totalAcres !== totalTargetAcres" class="field-error">
<mat-icon>warning</mat-icon>
<div>The total lot area proposed must match {{ totalTargetAcres }} hectares as provided in Step 1</div>
</div>
</form>
</div>
<div class="full-row">
<label for="purpose">What is the purpose of the proposal?</label>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ section {
.toggle-button {
min-width: rem(170);
}

.proposed-lots {
margin-bottom: rem(16);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@ import { ApplicationDocumentDto } from '../../../../../services/application-docu
import { ApplicationDocumentService } from '../../../../../services/application-document/application-document.service';
import { PARCEL_TYPE } from '../../../../../services/application-parcel/application-parcel.dto';
import { ApplicationParcelService } from '../../../../../services/application-parcel/application-parcel.service';
import { ApplicationSubmissionUpdateDto } from '../../../../../services/application-submission/application-submission.dto';
import {
ApplicationSubmissionUpdateDto,
ProposedLot,
} from '../../../../../services/application-submission/application-submission.dto';
import { ApplicationSubmissionService } from '../../../../../services/application-submission/application-submission.service';
import { DOCUMENT_TYPE } from '../../../../../shared/dto/document.dto';
import { EditApplicationSteps } from '../../edit-submission.component';
import { FilesStepComponent } from '../../files-step.partial';

type ProposedLot = { type: 'Lot' | 'Road Dedication' | null; size: string | null };
type FormProposedLot = { type: 'Lot' | 'Road Dedication' | null; size: string | null };

@Component({
selector: 'app-subd-proposal',
Expand All @@ -35,7 +38,7 @@ export class SubdProposalComponent extends FilesStepComponent implements OnInit,

totalTargetAcres = '0';
totalAcres = '0';
proposedLots: ProposedLot[] = [];
proposedLots: FormProposedLot[] = [];
lotsSource = new MatTableDataSource(this.proposedLots);
displayedColumns = ['index', 'type', 'size'];

Expand All @@ -46,6 +49,7 @@ export class SubdProposalComponent extends FilesStepComponent implements OnInit,
agriculturalSupport: this.agriculturalSupport,
isHomeSiteSeverance: this.isHomeSiteSeverance,
});
lotsForm = new FormGroup({} as any);
private submissionUuid = '';

constructor(
Expand Down Expand Up @@ -81,6 +85,14 @@ export class SubdProposalComponent extends FilesStepComponent implements OnInit,
size: lot.size ? lot.size.toString(10) : null,
}));
this.lotsSource = new MatTableDataSource(this.proposedLots);

const newForm = new FormGroup({});
for (const [index, lot] of applicationSubmission.subdProposedLots.entries()) {
newForm.addControl(`${index}-type`, new FormControl(lot.type, [Validators.required]));
newForm.addControl(`${index}-size`, new FormControl(lot.size, [Validators.required]));
}
this.lotsForm = newForm;

this.calculateLotSize();

if (this.showErrors) {
Expand All @@ -102,21 +114,28 @@ export class SubdProposalComponent extends FilesStepComponent implements OnInit,
}

protected async save() {
if (this.fileId && this.form.dirty) {
if (this.fileId && (this.form.dirty || this.lotsForm.dirty)) {
const purpose = this.purpose.getRawValue();
const subdSuitability = this.suitability.getRawValue();
const subdAgricultureSupport = this.agriculturalSupport.getRawValue();
const subdIsHomeSiteSeverance = this.isHomeSiteSeverance.getRawValue();

const updatedStructures: ProposedLot[] = [];
for (const [index, lot] of this.proposedLots.entries()) {
const lotType = this.lotsForm.controls[`${index}-type`].value;
const lotSize = this.lotsForm.controls[`${index}-size`].value;
updatedStructures.push({
type: lotType,
size: lotSize ? parseFloat(lotSize) : null,
});
}

const updateDto: ApplicationSubmissionUpdateDto = {
purpose,
subdSuitability,
subdAgricultureSupport,
subdIsHomeSiteSeverance: subdIsHomeSiteSeverance !== null ? subdIsHomeSiteSeverance === 'true' : null,
subdProposedLots: this.proposedLots.map((lot) => ({
...lot,
size: lot.size ? parseFloat(lot.size) : null,
})),
subdProposedLots: updatedStructures,
};

const updatedApp = await this.applicationService.updatePending(this.submissionUuid, updateDto);
Expand All @@ -128,12 +147,21 @@ export class SubdProposalComponent extends FilesStepComponent implements OnInit,
const targetString = (event.target as HTMLInputElement).value;
const targetCount = parseInt(targetString);

for (let index = this.proposedLots.length; index > targetCount; index--) {
this.lotsForm.removeControl(`${index}-type`);
this.lotsForm.removeControl(`${index}-size`);
}

this.proposedLots = this.proposedLots.slice(0, targetCount);
while (this.proposedLots.length < targetCount) {
this.proposedLots.push({
size: '0',
type: null,
});

const index = this.proposedLots.length - 1;
this.lotsForm.addControl(`${index}-type`, new FormControl(null, [Validators.required]));
this.lotsForm.addControl(`${index}-size`, new FormControl(null, [Validators.required]));
}
this.lotsSource = new MatTableDataSource(this.proposedLots);
this.calculateLotSize();
Expand Down
Loading

0 comments on commit 097a7d8

Please sign in to comment.