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

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

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

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

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

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

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

Loading…
Cancel
Save