Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
import { Component, EventEmitter, input, Output, ViewChild, effect, inject, signal } from '@angular/core';
import { MatTable, MatTableDataSource } from '@angular/material/table';
import { MatPaginator } from '@angular/material/paginator';
import { MatDialog } from '@angular/material/dialog';
import { MatSort } from '@angular/material/sort';
import { Router } from '@angular/router';

import { SubSink } from 'subsink';
import { Observable, tap } from 'rxjs';

import { Budget, BudgetRecord } from '@app/model/finance/planning/budgets';

import { ShareBudgetModalComponent } from '../share-budget-modal/share-budget-modal.component';
Expand All @@ -22,10 +19,15 @@ import { ChildBudgetsModalComponent } from '../../modals/child-budgets-modal/chi

export class BudgetTableComponent {

private _sbS = new SubSink();
// REFACTORED: Use inject() instead of constructor injection
private _router$$ = inject(Router);
private _dialog = inject(MatDialog);

@Input() budgets$: Observable<{overview: BudgetRecord[], budgets: any[]}>;
@Input() canPromote = false;
// REFACTORED: Use signal-based input instead of @Input() with Observable
budgets$ = input<{overview: BudgetRecord[], budgets: any[]}>({ overview: [], budgets: [] });

// REFACTORED: Convert @Input to signal-based input
canPromote = input(false);

@Output() doPromote: EventEmitter<void> = new EventEmitter();

Expand All @@ -36,25 +38,25 @@ export class BudgetTableComponent {
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild('sort', { static: true }) sort: MatSort;

overviewBudgets: BudgetRecord[] = [];

constructor(private _router$$: Router,
private _dialog: MatDialog,
) { }
// REFACTORED: Use signal for overviewBudgets
overviewBudgets = signal<BudgetRecord[]>([]);

ngOnInit(): void {
this._sbS.sink = this.budgets$.pipe(tap((o) => {
this.overviewBudgets = o.overview;
this.dataSource.data = o.budgets;
})).subscribe();
// REFACTORED: Use effect instead of ngOnInit subscription
constructor() {
// Effect runs automatically when budgets$ signal changes
effect(() => {
const budgetsData = this.budgets$();
this.overviewBudgets.set(budgetsData.overview);
this.dataSource.data = budgetsData.budgets;
});
}

/**
* Checks whether the user has access to a certain feature.
*
* @TODO @IanOdhiambo9 - Please put proper access control architecture in place.
*/
access(requested:any)
access(requested: any)
{
switch (requested) {
case 'view':
Expand All @@ -81,7 +83,7 @@ export class BudgetTableComponent {
}

promote() {
if (this.canPromote)
if (this.canPromote())
this.doPromote.emit();
}

Expand All @@ -104,9 +106,10 @@ export class BudgetTableComponent {
});
}

openChildBudgetDialog(parent : Budget): void
openChildBudgetDialog(parent: Budget): void
{
let children: any = this.overviewBudgets.find((budget) => budget.budget.id === parent.id)!?.children;
// REFACTORED: Access signal value with ()
let children: any = this.overviewBudgets().find((budget) => budget.budget.id === parent.id)!?.children;
children = children?.map((child) => child.budget)
this._dialog.open(ChildBudgetsModalComponent, {
height: 'fit-content',
Expand Down Expand Up @@ -137,4 +140,4 @@ export class BudgetTableComponent {
return '';
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@
</kujali-finance-search-header-card>
</kujali-finance-toolbar>

<div *ngIf="showFilter" class="filter-section">
<div *ngIf="showFilter()" class="filter-section">
<!-- <kujali-invoices-filter (filterChanged)='fieldsFilter($event)'>
</kujali-invoices-filter> -->
</div>

<div class="table-container">
<app-budget-table [budgets$]="allBudgets$"></app-budget-table>
<app-budget-table [budgets$]="allBudgets"></app-budget-table>
</div>
</div>
</app-page>
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { Component, OnInit, ViewChild, signal, computed, effect, inject } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { MatDialog } from '@angular/material/dialog';

import { cloneDeep as ___cloneDeep, flatMap as __flatMap } from 'lodash';
Expand All @@ -22,33 +23,71 @@ import { CreateBudgetModalComponent } from '../../components/create-budget-modal
/** List of all active budgets on the system. */
export class SelectBudgetPageComponent implements OnInit
{
/** Overview which contains all budgets of an organisation */
overview$!: Observable<OrgBudgetsOverview>;
sharedBudgets$: Observable<any[]>;

showFilter = false;
// REFACTORED: Use inject() instead of constructor injection
private _orgBudgets$$ = inject(OrgBudgetsStore);
private _budgets$$ = inject(BudgetsStore);
private _dialog = inject(MatDialog);
private _logger = inject(Logger);

// budgetsLoaded: boolean = false;

allBudgets$: Observable<{overview: BudgetRecord[], budgets: any[]}>;
// REFACTORED: Convert Observables to Signals using toSignal()
/** Overview which contains all budgets of an organisation */
overview = toSignal(this._orgBudgets$$.get(), {
initialValue: null as OrgBudgetsOverview | null
});

sharedBudgets = toSignal(this._budgets$$.get(), {
initialValue: [] as any[]
});

// REFACTORED: Convert combined observable to signal
allBudgets = toSignal(
combineLatest([this._orgBudgets$$.get(), this._budgets$$.get()])
.pipe(
map(([overview, budgets]) => {
return {
overview: __flatMap(overview),
budgets: __flatMap(budgets)
}
}),
map((overview) => {
const trBudgets = overview.budgets.map((budget: any) => {
budget['endYear'] = budget.startYear + budget.duration - 1;
return budget;
});
return {
overview: overview.overview,
budgets: trBudgets
}
})
),
{
initialValue: { overview: [], budgets: [] }
}
);

// REFACTORED: Convert to signal
showFilter = signal(false);

// REFACTORED: Use effects instead of subscriptions
constructor() {
// Effect for logging when overview loads
effect(() => {
const overview = this.overview();
if (overview) {
this._logger.log(() => `Overview loaded with data`);
}
});

constructor(private _orgBudgets$$: OrgBudgetsStore,
private _budgets$$: BudgetsStore,
private _dialog: MatDialog,
private _logger: Logger)
{ }
// Effect for logging when budgets change
effect(() => {
const budgets = this.allBudgets();
this._logger.log(() => `All budgets updated. Count: ${budgets.budgets.length}`);
});
}

ngOnInit() {
this.overview$ = this._orgBudgets$$.get();
this.sharedBudgets$ = this._budgets$$.get();

this.allBudgets$ = combineLatest([this.overview$, this._budgets$$.get()])
.pipe(map(([overview, budgets]) => {return {overview: __flatMap(overview), budgets: __flatMap(budgets)}}),
map((overview) => {
const trBudgets = overview.budgets.map((budget: any) => {budget['endYear'] = budget.startYear + budget.duration - 1; return budget;})
// this.budgetsLoaded = true;
return {overview: overview.overview, budgets: trBudgets}
}));
// REFACTORED: No longer need to manually subscribe - signals handle this automatically
// The toSignal() calls in the property declarations handle the subscriptions
}

applyFilter(event: Event) {
Expand All @@ -60,11 +99,12 @@ export class SelectBudgetPageComponent implements OnInit
// this.filter$$.next(value);
}

toogleFilter(value) {
// this.showFilter = value
toogleFilter(value: boolean) {
// REFACTORED: Use signal.set() instead of direct assignment
this.showFilter.set(value);
}

openDialog(parent : Budget | false): void
openDialog(parent: Budget | false): void
{
const dialog = this._dialog.open(CreateBudgetModalComponent, {
height: 'fit-content',
Expand Down