Skip to content

Commit

Permalink
Implement AfterViewInit lifecycle interface
Browse files Browse the repository at this point in the history
  • Loading branch information
sainingo committed Nov 4, 2024
1 parent 8a32b23 commit c142cc6
Show file tree
Hide file tree
Showing 7 changed files with 474 additions and 13 deletions.
3 changes: 3 additions & 0 deletions src/app/hiv-care-lib/hiv-care-lib.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ import { AhdMonthlyReportPatientlistComponent } from './ahd-monthly-report/ahd-m
import { PlhivNcdV2ReportBaseComponent } from './plhiv-ncd-v2-report/plhiv-ncd-v2-report-base/plhiv-ncd-v2-report-base.component';
import { PlhivNcdV2ReportPatientListComponent } from './plhiv-ncd-v2-report/plhiv-ncd-v2-report-patient-list/plhiv-ncd-v2-report-patient-list.component';
import { PlhivNcdV2ReportViewComponent } from './plhiv-ncd-v2-report/plhiv-ncd-v2-report-view/plhiv-ncd-v2-report-view.component';
import { Moh731AirComponent } from './moh-731-report/moh-731-air.components';

@NgModule({
imports: [
Expand Down Expand Up @@ -184,6 +185,7 @@ import { PlhivNcdV2ReportViewComponent } from './plhiv-ncd-v2-report/plhiv-ncd-v
exports: [
Moh731TabularComponent,
Moh731PatientListComponent,
Moh731AirComponent,
Moh731ReportFiltersComponent,
DateTimePickerModule,
EtlApi,
Expand Down Expand Up @@ -258,6 +260,7 @@ import { PlhivNcdV2ReportViewComponent } from './plhiv-ncd-v2-report/plhiv-ncd-v
Moh731PatientListComponent,
Moh731ReportBaseComponent,
Moh731ReportFiltersComponent,
Moh731AirComponent,
MOHReportComponent,
HivSummaryIndicatorBaseComponent,
HivSummaryTabularComponent,
Expand Down
109 changes: 109 additions & 0 deletions src/app/hiv-care-lib/moh-731-report/moh-731-air.component.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/* moh-731-air.component.scss */
.panel {
margin: 20px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
}

.panel-heading {
background-color: #f5f5f5;
border-color: #ddd;

.panel-title {
margin-top: 7px;

.date-range {
font-size: 12px;
color: #777;
margin-left: 10px;
}
}
}

.table {
margin-bottom: 0;

th.sortable {
cursor: pointer;
user-select: none;

&:hover {
background-color: #f5f5f5;
}

.glyphicon {
font-size: 12px;
margin-left: 5px;
color: #777;
}
}
}

.label {
display: inline-block;
min-width: 60px;
padding: 5px 10px;
border-radius: 3px;
text-align: center;
}

.sortable {
cursor: pointer;
}

.label-success {
background-color: #5cb85c;
color: white;
}

.label-warning {
background-color: #f0ad4e;
color: white;
}

.label-danger {
background-color: #d9534f;
color: white;
}

.label-default {
background-color: #777;
color: white;
}

.loader {
padding: 20px;
text-align: center;
color: #666;

.fa-spinner {
margin-right: 10px;
}
}

.clickable {
cursor: pointer;

&:hover {
background-color: #f5f5f5;
}
}

.released-indicator {
color: #5cb85c;

.fa-check-circle {
margin-right: 5px;
}
}

@media (max-width: 768px) {
.panel-heading {
.panel-title {
margin-bottom: 10px;
}

.input-group {
margin-top: 10px;
}
}
}
122 changes: 122 additions & 0 deletions src/app/hiv-care-lib/moh-731-report/moh-731-air.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<!-- moh-731-air.component.html -->
<div class="panel panel-default">
<div class="row" style="margin-top: 4px; padding: 0px">
<button
type="button"
*ngIf="!parentIsBusy"
class="btn btn-success pull-right"
(click)="processDataToKHIS()"
>
Sync To KHIS
</button>
</div>
<div class="panel-heading">
<div class="row">
<div class="col-md-6">
<h3 class="panel-title">
AIR View
<span class="date-range" *ngIf="startDate && endDate">
({{ startDate | date }} - {{ endDate | date }})
</span>
</h3>
</div>
<div class="col-md-6">
<div class="input-group">
<span class="input-group-addon">
<i class="glyphicon glyphicon-search"></i>
</span>
<input
type="text"
class="form-control"
placeholder="Search..."
[(ngModel)]="searchTerm"
/>
</div>
</div>
</div>
</div>

<div class="panel-body">
<!-- Loading indicator -->
<div class="loader text-center" *ngIf="isLoading">
<i class="fa fa-spinner fa-spin"></i> Loading air data...
</div>

<!-- Table view -->
<div class="table-responsive" *ngIf="!isLoading">
<table class="table table-striped table-hover table-bordered">
<thead>
<tr>
<th
*ngFor="let def of sectionDefs"
(click)="sortBy(def.name)"
class="sortable"
>
{{ def.label }}
<span [class]="getSortIcon(def.name)"></span>
</th>
</tr>
</thead>
<tbody>
<tr
*ngFor="let item of filterData()"
(click)="onIndicatorClick(item)"
[class.clickable]="true"
>
<!-- Dynamically generate cells based on sectionDefs -->
<td *ngFor="let def of sectionDefs">
<span *ngIf="def.type !== 'status'">{{ item[def.name] }}</span>
<span
*ngIf="def.type === 'status'"
class="label"
[ngClass]="getStatusClass(item[def.name])"
>
{{ item[def.name] }}
</span>
<span *ngIf="def.type === 'action'">
<button
*ngIf="item.status === 'pending'"
class="btn btn-warning btn-sm"
(click)="retrySync(item)"
[disabled]="item.status === 'synced'"
>
Retry Sync
</button>
<button
*ngIf="item.status === 'error'"
class="btn btn-danger btn-sm"
(click)="resolveError(item)"
[disabled]="item.status === 'synced'"
>
Error
</button>
<span
*ngIf="item.status === 'synced'"
class="text-success disabled"
>
Synced
</span>
</span>
</td>
</tr>
<tr *ngIf="filterData().length === 0">
<td [attr.colspan]="sectionDefs.length" class="text-center">
No data found
</td>
</tr>
</tbody>
</table>
</div>
</div>

<div class="panel-footer">
<div class="row">
<div class="col-md-6">Showing {{ filterData().length }} entries</div>
<div class="col-md-6 text-right">
<span *ngIf="isReleased" class="released-indicator">
<i class="fa fa-check-circle"></i> Released
</span>
</div>
</div>
</div>
</div>
126 changes: 126 additions & 0 deletions src/app/hiv-care-lib/moh-731-report/moh-731-air.components.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';

interface TableData {
name: string;
age: number;
city: string;
status: string;
}

@Component({
selector: 'moh-731-air',
templateUrl: './moh-731-air.component.html',
styleUrls: ['./moh-731-air.component.css']
})
export class Moh731AirComponent implements OnInit {
@Input() rowData: any[] = [];
@Input() combinedData: any[] = [];
@Input() sectionDefs: any[] = [];
@Input() startDate: Date;
@Input() endDate: Date;
@Input() isReleased: boolean;
@Output() indicatorSelected = new EventEmitter();

sortField = 'name';
sortDirection: 'asc' | 'desc' = 'asc';
currentPage = 1;
itemsPerPage = 10;
searchTerm = '';
isLoading = false;
filteredData: any[] = [];

ngOnInit() {
this.processData();
}

public processDataToKHIS() {
console.log('process air data', this.combinedData);
}

processData() {
this.isLoading = true;
try {
if (this.rowData && this.sectionDefs) {
this.filteredData = [...this.rowData];
}
} catch (error) {
console.error('Error processing data:', error);
} finally {
this.isLoading = false;
}
}

filterData(): any[] {
let filtered = [...this.filteredData];

// Apply search filter if searchTerm exists
if (this.searchTerm) {
const searchLower = this.searchTerm.toLowerCase();
filtered = filtered.filter((item) => {
return this.sectionDefs.some((def) => {
const value = item[def.name];
return value && value.toString().toLowerCase().includes(searchLower);
});
});
}

// Apply sorting
filtered.sort((a, b) => {
const aValue = a[this.sortField];
const bValue = b[this.sortField];

if (typeof aValue === 'string') {
const comparison = aValue.localeCompare(bValue);
return this.sortDirection === 'asc' ? comparison : -comparison;
} else {
const comparison = aValue - bValue;
return this.sortDirection === 'asc' ? comparison : -comparison;
}
});

return filtered;
}

sortBy(field: string) {
if (this.sortField === field) {
this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc';
} else {
this.sortField = field;
this.sortDirection = 'asc';
}
}

getSortIcon(field: string): string {
if (this.sortField !== field) {
return 'fa fa-sort';
}
return this.sortDirection === 'asc' ? 'fa fa-sort-asc' : 'fa fa-sort-desc';
}

getStatusClass(status: string): string {
switch (status ? status.toLowerCase() : '') {
case 'synced':
return 'label-success';
case 'pending':
return 'label-warning';
case 'error':
return 'label-danger';
default:
return 'label-default';
}
}

retrySync(item: TableData) {
// Add logic to retry syncing
console.log('Retry sync for:', item);
}

resolveError(item: TableData) {
// Add logic to resolve the error
console.log('Resolve error for:', item);
}

onIndicatorClick(indicator: any) {
this.indicatorSelected.emit(indicator);
}
}
Loading

0 comments on commit c142cc6

Please sign in to comment.