Browse Source

Add tags support in accounts

pull/7242/head
Thomas Kaul 1 week ago
parent
commit
90270dbcd5
  1. 15
      apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts
  2. 1
      apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html
  3. 22
      libs/ui/src/lib/tags-selector/tags-selector.component.html
  4. 31
      libs/ui/src/lib/tags-selector/tags-selector.component.ts

15
apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts

@ -77,7 +77,7 @@ import {
swapVerticalOutline, swapVerticalOutline,
walletOutline walletOutline
} from 'ionicons/icons'; } from 'ionicons/icons';
import { isNumber, round } from 'lodash'; import { isNumber, round, uniqBy } from 'lodash';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { switchMap } from 'rxjs/operators'; import { switchMap } from 'rxjs/operators';
@ -179,6 +179,7 @@ export class GfHoldingDetailDialogComponent implements OnInit {
protected sortColumn = 'date'; protected sortColumn = 'date';
protected sortDirection: SortDirection = 'desc'; protected sortDirection: SortDirection = 'desc';
protected tagsAvailable: Tag[]; protected tagsAvailable: Tag[];
protected tagsOfAccounts: Tag[];
protected readonly translate = translate; protected readonly translate = translate;
protected user: User; protected user: User;
protected value: number; protected value: number;
@ -265,6 +266,18 @@ export class GfHoldingDetailDialogComponent implements OnInit {
.subscribe(({ accounts }) => { .subscribe(({ accounts }) => {
this.accounts = accounts; this.accounts = accounts;
this.tagsOfAccounts = uniqBy(
accounts.flatMap(({ tags }) => {
return tags ?? [];
}),
'id'
).map((tag) => {
return {
...tag,
name: translate(tag.name)
};
});
this.changeDetectorRef.markForCheck(); this.changeDetectorRef.markForCheck();
}); });

1
apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html

@ -427,6 +427,7 @@
[hasPermissionToCreateTag]="hasPermissionToCreateOwnTag" [hasPermissionToCreateTag]="hasPermissionToCreateOwnTag"
[readonly]="!data.hasPermissionToUpdateActivity" [readonly]="!data.hasPermissionToUpdateActivity"
[tagsAvailable]="tagsAvailable" [tagsAvailable]="tagsAvailable"
[tagsReadOnly]="tagsOfAccounts"
/> />
</form> </form>

22
libs/ui/src/lib/tags-selector/tags-selector.component.html

@ -2,10 +2,19 @@
<div class="col"> <div class="col">
@if (readonly) { @if (readonly) {
<div class="h5" i18n>Tags</div> <div class="h5" i18n>Tags</div>
@if (tags && tags.length > 0) { @if (
(tags && tags.length > 0) || (tagsReadOnly && tagsReadOnly.length > 0)
) {
<mat-chip-listbox> <mat-chip-listbox>
@for (tag of tags; track tag) { @if (tagsReadOnly) {
<mat-chip-option disabled>{{ tag.name }}</mat-chip-option> @for (tag of tagsReadOnly; track tag) {
<mat-chip-option disabled>{{ tag.name }}</mat-chip-option>
}
}
@if (tags) {
@for (tag of tags; track tag) {
<mat-chip-option disabled>{{ tag.name }}</mat-chip-option>
}
} }
</mat-chip-listbox> </mat-chip-listbox>
} @else { } @else {
@ -15,6 +24,13 @@
<mat-form-field appearance="outline" class="w-100 without-hint"> <mat-form-field appearance="outline" class="w-100 without-hint">
<mat-label i18n>Tags</mat-label> <mat-label i18n>Tags</mat-label>
<mat-chip-grid #tagsChipList> <mat-chip-grid #tagsChipList>
@if (tagsReadOnly) {
@for (tag of tagsReadOnly; track tag.id) {
<mat-chip-row disabled [removable]="false">
{{ tag.name }}
</mat-chip-row>
}
}
@for (tag of tagsSelected(); track tag.id) { @for (tag of tagsSelected(); track tag.id) {
<mat-chip-row <mat-chip-row
matChipRemove matChipRemove

31
libs/ui/src/lib/tags-selector/tags-selector.component.ts

@ -9,6 +9,7 @@ import {
OnChanges, OnChanges,
OnInit, OnInit,
signal, signal,
SimpleChanges,
viewChild viewChild
} from '@angular/core'; } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
@ -27,7 +28,6 @@ import { MatChipsModule } from '@angular/material/chips';
import { MatFormFieldModule } from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { IonIcon } from '@ionic/angular/standalone'; import { IonIcon } from '@ionic/angular/standalone';
import { Tag } from '@prisma/client';
import { addIcons } from 'ionicons'; import { addIcons } from 'ionicons';
import { addCircleOutline, closeOutline } from 'ionicons/icons'; import { addCircleOutline, closeOutline } from 'ionicons/icons';
import { BehaviorSubject, Subject } from 'rxjs'; import { BehaviorSubject, Subject } from 'rxjs';
@ -65,6 +65,7 @@ export class GfTagsSelectorComponent
@Input() readonly = false; @Input() readonly = false;
@Input() tags: SelectedTag[]; @Input() tags: SelectedTag[];
@Input() tagsAvailable: SelectedTag[]; @Input() tagsAvailable: SelectedTag[];
@Input() tagsReadOnly: SelectedTag[];
public readonly filteredOptions: Subject<SelectedTag[]> = new BehaviorSubject( public readonly filteredOptions: Subject<SelectedTag[]> = new BehaviorSubject(
[] []
@ -87,12 +88,15 @@ export class GfTagsSelectorComponent
} }
public ngOnInit() { public ngOnInit() {
this.tagsSelected.set(this.tags); this.tagsSelected.set(this.tags ?? []);
this.updateFilters(); this.updateFilters();
} }
public ngOnChanges() { public ngOnChanges(changes: SimpleChanges) {
this.tagsSelected.set(this.tags); if (changes.tags) {
this.tagsSelected.set(this.tags ?? []);
}
this.updateFilters(); this.updateFilters();
} }
@ -123,7 +127,7 @@ export class GfTagsSelectorComponent
this.tagInputControl.setValue(null); this.tagInputControl.setValue(null);
} }
public onRemoveTag(tag: Tag) { public onRemoveTag(tag: SelectedTag) {
this.tagsSelected.update((tags) => { this.tagsSelected.update((tags) => {
return tags.filter(({ id }) => { return tags.filter(({ id }) => {
return id !== tag.id; return id !== tag.id;
@ -159,15 +163,20 @@ export class GfTagsSelectorComponent
private filterTags(query: string = ''): SelectedTag[] { private filterTags(query: string = ''): SelectedTag[] {
const tags = this.tagsSelected() ?? []; const tags = this.tagsSelected() ?? [];
const tagIds = tags.map(({ id }) => { const tagIds = [...tags, ...(this.tagsReadOnly ?? [])].map(({ id }) => {
return id; return id;
}); });
return this.tagsAvailable.filter(({ id, name }) => { return this.tagsAvailable
return ( .filter(({ id, name }) => {
!tagIds.includes(id) && name.toLowerCase().includes(query.toLowerCase()) return (
); !tagIds.includes(id) &&
}); name.toLowerCase().includes(query.toLowerCase())
);
})
.sort((a, b) => {
return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
});
} }
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars

Loading…
Cancel
Save