@sneat/space-components 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/esm2022/index.js +2 -0
  2. package/esm2022/index.js.map +1 -0
  3. package/esm2022/lib/avatar/avatar.component.js +15 -0
  4. package/esm2022/lib/avatar/avatar.component.js.map +1 -0
  5. package/esm2022/lib/index.js +13 -0
  6. package/esm2022/lib/index.js.map +1 -0
  7. package/esm2022/lib/space-base-component.directive.js +350 -0
  8. package/esm2022/lib/space-base-component.directive.js.map +1 -0
  9. package/esm2022/lib/space-component-base-params.service.js +22 -0
  10. package/esm2022/lib/space-component-base-params.service.js.map +1 -0
  11. package/esm2022/lib/space-item-page-base.component.js +121 -0
  12. package/esm2022/lib/space-item-page-base.component.js.map +1 -0
  13. package/esm2022/lib/space-items-base.component.js +8 -0
  14. package/esm2022/lib/space-items-base.component.js.map +1 -0
  15. package/esm2022/lib/space-menu/index.js +2 -0
  16. package/esm2022/lib/space-menu/index.js.map +1 -0
  17. package/esm2022/lib/space-menu/space-menu.component.js +119 -0
  18. package/esm2022/lib/space-menu/space-menu.component.js.map +1 -0
  19. package/esm2022/lib/space-module-base.component.js +28 -0
  20. package/esm2022/lib/space-module-base.component.js.map +1 -0
  21. package/esm2022/lib/space-page-base-component.service.js +11 -0
  22. package/esm2022/lib/space-page-base-component.service.js.map +1 -0
  23. package/esm2022/lib/space-page-title/space-page-title.component.js +27 -0
  24. package/esm2022/lib/space-page-title/space-page-title.component.js.map +1 -0
  25. package/esm2022/lib/spaces-card/index.js +2 -0
  26. package/esm2022/lib/spaces-card/index.js.map +1 -0
  27. package/esm2022/lib/spaces-card/spaces-card.component.js +208 -0
  28. package/esm2022/lib/spaces-card/spaces-card.component.js.map +1 -0
  29. package/esm2022/lib/spaces-list/index.js +2 -0
  30. package/esm2022/lib/spaces-list/index.js.map +1 -0
  31. package/esm2022/lib/spaces-list/spaces-list.component.js +111 -0
  32. package/esm2022/lib/spaces-list/spaces-list.component.js.map +1 -0
  33. package/esm2022/lib/spaces-menu/index.js +2 -0
  34. package/esm2022/lib/spaces-menu/index.js.map +1 -0
  35. package/esm2022/lib/spaces-menu/spaces-menu.component.js +105 -0
  36. package/esm2022/lib/spaces-menu/spaces-menu.component.js.map +1 -0
  37. package/esm2022/sneat-space-components.js +5 -0
  38. package/esm2022/sneat-space-components.js.map +1 -0
  39. package/index.d.ts +1 -0
  40. package/lib/avatar/avatar.component.d.ts +7 -0
  41. package/lib/index.d.ts +12 -0
  42. package/lib/space-base-component.directive.d.ts +68 -0
  43. package/lib/space-component-base-params.service.d.ts +15 -0
  44. package/lib/space-item-page-base.component.d.ts +22 -0
  45. package/lib/space-items-base.component.d.ts +4 -0
  46. package/lib/space-menu/index.d.ts +1 -0
  47. package/lib/space-menu/space-menu.component.d.ts +19 -0
  48. package/lib/space-module-base.component.d.ts +10 -0
  49. package/lib/space-page-base-component.service.d.ts +6 -0
  50. package/lib/space-page-title/space-page-title.component.d.ts +11 -0
  51. package/lib/spaces-card/index.d.ts +1 -0
  52. package/lib/spaces-card/spaces-card.component.d.ts +33 -0
  53. package/lib/spaces-list/index.d.ts +1 -0
  54. package/lib/spaces-list/spaces-list.component.d.ts +22 -0
  55. package/lib/spaces-menu/index.d.ts +1 -0
  56. package/lib/spaces-menu/spaces-menu.component.d.ts +22 -0
  57. package/package.json +27 -0
  58. package/sneat-space-components.d.ts +5 -0
  59. package/tsconfig.lib.prod.tsbuildinfo +1 -0
@@ -0,0 +1,8 @@
1
+ import { SpaceBaseComponent } from './space-base-component.directive';
2
+ export class SpaceItemsBaseComponent extends SpaceBaseComponent {
3
+ constructor(parentPagePath) {
4
+ super();
5
+ this.$defaultBackUrlSpacePath.set(parentPagePath);
6
+ }
7
+ }
8
+ //# sourceMappingURL=space-items-base.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"space-items-base.component.js","sourceRoot":"","sources":["../../../../../../libs/space/components/src/lib/space-items-base.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAEtE,MAAM,OAAgB,uBAAwB,SAAQ,kBAAkB;IACtE,YAAsB,cAAsB;QAC1C,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACpD,CAAC;CACF","sourcesContent":["import { SpaceBaseComponent } from './space-base-component.directive';\n\nexport abstract class SpaceItemsBaseComponent extends SpaceBaseComponent {\n protected constructor(parentPagePath: string) {\n super();\n this.$defaultBackUrlSpacePath.set(parentPagePath);\n }\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export * from './space-menu.component';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../libs/space/components/src/lib/space-menu/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC","sourcesContent":["export * from './space-menu.component';\n"]}
@@ -0,0 +1,119 @@
1
+ import { TitleCasePipe } from '@angular/common';
2
+ import { ChangeDetectionStrategy, Component, computed, inject, signal, } from '@angular/core';
3
+ import { ActivatedRoute, NavigationEnd, Router, RouterLink, } from '@angular/router';
4
+ import { IonButton, IonButtons, IonIcon, IonItem, IonLabel, IonList, IonSelect, IonSelectOption, MenuController, } from '@ionic/angular/standalone';
5
+ import { AuthMenuItemComponent } from '@sneat/auth-ui';
6
+ import { ContactusServicesModule } from '@sneat/contactus-services';
7
+ import { zipMapBriefsWithIDs } from '@sneat/space-models';
8
+ import { SpaceServiceModule } from '@sneat/space-services';
9
+ import { filter } from 'rxjs';
10
+ import { takeUntil } from 'rxjs/operators';
11
+ import { SpaceBaseComponent } from '../space-base-component.directive';
12
+ import { SpaceComponentBaseParams } from '../space-component-base-params.service';
13
+ import { ClassName } from '@sneat/ui';
14
+ import * as i0 from "@angular/core";
15
+ export class SpaceMenuComponent extends SpaceBaseComponent {
16
+ constructor() {
17
+ const router = inject(Router);
18
+ super();
19
+ this.$spaces = signal(undefined, ...(ngDevMode ? [{ debugName: "$spaces" }] : []));
20
+ this.$disabled = computed(() => !this.$spaceID(), ...(ngDevMode ? [{ debugName: "$disabled" }] : []));
21
+ this.$currentPage = signal('', ...(ngDevMode ? [{ debugName: "$currentPage" }] : []));
22
+ this.activatedRoute = inject(ActivatedRoute);
23
+ this.menuCtrl = inject(MenuController);
24
+ this.onUserStateChanged = (userState) => {
25
+ this.$spaces.set(userState?.record
26
+ ? zipMapBriefsWithIDs(userState.record.spaces) || []
27
+ : undefined);
28
+ };
29
+ this.spaceParams.userService.userState
30
+ .pipe(takeUntil(this.destroyed$))
31
+ .subscribe({
32
+ next: this.onUserStateChanged,
33
+ error: this.errorLogger.logErrorHandler('failed to get user stage'),
34
+ });
35
+ router.events
36
+ .pipe(this.takeUntilDestroyed(), filter((event) => event instanceof NavigationEnd))
37
+ .subscribe((event) => {
38
+ let route = this.activatedRoute.firstChild;
39
+ while (route?.firstChild) {
40
+ route = route.firstChild;
41
+ }
42
+ const url = event.urlAfterRedirects.split('/');
43
+ this.$currentPage.set(url.length > 4 ? url[4] : '');
44
+ });
45
+ }
46
+ // TODO: Should we use goSpacePage('') instead?
47
+ goOverview() {
48
+ const space = this.$space();
49
+ if (!space) {
50
+ this.errorLogger.logError('no space context');
51
+ return false;
52
+ }
53
+ this.spaceParams.spaceNavService.navigateToSpace(space).then((v) => {
54
+ if (v) {
55
+ this.closeMenu();
56
+ }
57
+ });
58
+ return false;
59
+ }
60
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
61
+ goSpacePage(event, _p) {
62
+ // At the moment we use routerLink for navigation
63
+ event.stopPropagation();
64
+ // event.preventDefault();
65
+ this.closeMenu();
66
+ return false;
67
+ }
68
+ closeMenu() {
69
+ this.menuCtrl.close().catch(this.errorLogger.logError);
70
+ }
71
+ onSpaceSelected(event) {
72
+ const spaceID = event.detail.value;
73
+ if (spaceID === this.space?.id) {
74
+ return;
75
+ }
76
+ const space = this.$spaces()?.find((t) => t.id === spaceID);
77
+ if (space) {
78
+ this.setSpaceRef(space);
79
+ this.spaceNav
80
+ .navigateToSpace(space)
81
+ .catch(this.errorLogger.logErrorHandler('Failed to navigate to teams page on current team changed from team menu dropdown'));
82
+ }
83
+ this.menuCtrl.close().catch(console.error);
84
+ return;
85
+ }
86
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: SpaceMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
87
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: SpaceMenuComponent, isStandalone: true, selector: "sneat-space-menu", providers: [
88
+ {
89
+ provide: ClassName,
90
+ useValue: 'SpaceMenuComponent',
91
+ },
92
+ SpaceComponentBaseParams,
93
+ ], usesInheritance: true, ngImport: i0, template: "<ion-list>\n <ion-item>\n <!--\t\t<ion-icon [name]=\"space.type === 'family' ? 'people-outline' : space.type === 'private' ? 'person-circle-outline' : 'people-outline' \" slot=\"end\" />-->\n <ion-select\n label=\"Space\"\n [value]=\"$space().id\"\n interface=\"popover\"\n (ionChange)=\"onSpaceSelected($event)\"\n style=\"font-weight: bold\"\n >\n @for (userSpace of $spaces(); track userSpace.id) {\n <ion-select-option [value]=\"userSpace.id\"\n >{{\n userSpace.brief.title ||\n (userSpace.brief.type | titlecase) ||\n space.id\n }}\n </ion-select-option>\n } @empty {\n @let space = $space();\n <ion-select-option [value]=\"space?.id\">\n @if (!space || (!space?.id && !space?.type)) {\n Loading...\n } @else {\n {{ space.brief?.title || (space.type | titlecase) || space.id }}\n }\n </ion-select-option>\n }\n </ion-select>\n <!--\t\t@if (!spaces) {-->\n <!--\t\t\t<ion-spinner name=\"lines\" slot=\"end\"></ion-spinner>-->\n <!--\t\t}-->\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('overview')\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === ''\"\n (click)=\"goOverview()\"\n >\n <ion-icon name=\"home-outline\" slot=\"start\" />\n <ion-label>Overview</ion-label>\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('assets')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'assets'\"\n (click)=\"goSpacePage($event, 'assets')\"\n >\n <ion-icon name=\"car-sport-outline\" slot=\"start\" />\n <ion-label>Assets</ion-label>\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('budget')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'budget'\"\n (click)=\"goSpacePage($event, 'budget')\"\n >\n <ion-icon name=\"cash-outline\" slot=\"start\" />\n <ion-label>Budget</ion-label>\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('calendar')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'calendar'\"\n (click)=\"closeMenu()\"\n >\n <ion-icon name=\"calendar-outline\" slot=\"start\" />\n <ion-label>Calendar</ion-label>\n <!--\t\t<ion-buttons slot=\"end\">-->\n <!--\t\t\t<ion-button color=\"primary\" style=\"text-transform: none; font-size: x-small\">Today</ion-button>-->\n <!--\t\t\t<ion-button color=\"primary\" style=\"text-transform: none; font-size: x-small\">Tomorrow</ion-button>-->\n <!--\t\t</ion-buttons>-->\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('contacts')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'contacts'\"\n (click)=\"goSpacePage($event, 'contacts')\"\n >\n <ion-icon name=\"people-outline\" slot=\"start\" />\n <ion-label>Contacts</ion-label>\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('debts')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'debts'\"\n (click)=\"goSpacePage($event, 'debts')\"\n >\n <ion-icon name=\"cash-outline\" slot=\"start\" />\n <ion-label>Debts</ion-label>\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('documents')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'documents'\"\n (click)=\"goSpacePage($event, 'documents')\"\n >\n <ion-icon name=\"documents-outline\" slot=\"start\" />\n <ion-label>Documents</ion-label>\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('lists')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'lists'\"\n (click)=\"goSpacePage($event, 'lists')\"\n >\n <ion-icon name=\"list-outline\" slot=\"start\" />\n <ion-label>Lists</ion-label>\n <ion-buttons slot=\"end\">\n <ion-button\n routerDirection=\"root\"\n [routerLink]=\"spacePageUrl('list/buy/groceries')\"\n (click)=\"goSpacePage($event, 'list/buy/groceries')\"\n >\n <ion-label>\uD83D\uDED2</ion-label>\n </ion-button>\n <!--\t\t\t<ion-button routerLink=\"./list/towatch\">\uD83C\uDF7F</ion-button>-->\n </ion-buttons>\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('members')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'members'\"\n (click)=\"closeMenu()\"\n >\n <ion-icon name=\"people-circle-outline\" slot=\"start\" />\n <ion-label>Members</ion-label>\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('trackers')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'trackers'\"\n (click)=\"closeMenu()\"\n >\n <ion-icon name=\"bar-chart-outline\" slot=\"start\" />\n <ion-label>Trackers</ion-label>\n </ion-item>\n <sneat-auth-menu-item />\n</ion-list>\n", styles: [".currentPage ion-label{font-weight:700}\n"], dependencies: [{ kind: "component", type: AuthMenuItemComponent, selector: "sneat-auth-menu-item" }, { kind: "ngmodule", type: ContactusServicesModule }, { kind: "ngmodule", type: SpaceServiceModule }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonSelect, selector: "ion-select", inputs: ["cancelText", "color", "compareWith", "disabled", "errorText", "expandedIcon", "fill", "helperText", "interface", "interfaceOptions", "justify", "label", "labelPlacement", "mode", "multiple", "name", "okText", "placeholder", "selectedText", "shape", "toggleIcon", "value"] }, { kind: "component", type: IonSelectOption, selector: "ion-select-option", inputs: ["disabled", "value"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
94
+ }
95
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: SpaceMenuComponent, decorators: [{
96
+ type: Component,
97
+ args: [{ selector: 'sneat-space-menu', imports: [
98
+ AuthMenuItemComponent,
99
+ ContactusServicesModule,
100
+ SpaceServiceModule,
101
+ TitleCasePipe,
102
+ RouterLink,
103
+ IonList,
104
+ IonItem,
105
+ IonSelect,
106
+ IonSelectOption,
107
+ IonIcon,
108
+ IonLabel,
109
+ IonButtons,
110
+ IonButton,
111
+ ], providers: [
112
+ {
113
+ provide: ClassName,
114
+ useValue: 'SpaceMenuComponent',
115
+ },
116
+ SpaceComponentBaseParams,
117
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ion-list>\n <ion-item>\n <!--\t\t<ion-icon [name]=\"space.type === 'family' ? 'people-outline' : space.type === 'private' ? 'person-circle-outline' : 'people-outline' \" slot=\"end\" />-->\n <ion-select\n label=\"Space\"\n [value]=\"$space().id\"\n interface=\"popover\"\n (ionChange)=\"onSpaceSelected($event)\"\n style=\"font-weight: bold\"\n >\n @for (userSpace of $spaces(); track userSpace.id) {\n <ion-select-option [value]=\"userSpace.id\"\n >{{\n userSpace.brief.title ||\n (userSpace.brief.type | titlecase) ||\n space.id\n }}\n </ion-select-option>\n } @empty {\n @let space = $space();\n <ion-select-option [value]=\"space?.id\">\n @if (!space || (!space?.id && !space?.type)) {\n Loading...\n } @else {\n {{ space.brief?.title || (space.type | titlecase) || space.id }}\n }\n </ion-select-option>\n }\n </ion-select>\n <!--\t\t@if (!spaces) {-->\n <!--\t\t\t<ion-spinner name=\"lines\" slot=\"end\"></ion-spinner>-->\n <!--\t\t}-->\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('overview')\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === ''\"\n (click)=\"goOverview()\"\n >\n <ion-icon name=\"home-outline\" slot=\"start\" />\n <ion-label>Overview</ion-label>\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('assets')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'assets'\"\n (click)=\"goSpacePage($event, 'assets')\"\n >\n <ion-icon name=\"car-sport-outline\" slot=\"start\" />\n <ion-label>Assets</ion-label>\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('budget')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'budget'\"\n (click)=\"goSpacePage($event, 'budget')\"\n >\n <ion-icon name=\"cash-outline\" slot=\"start\" />\n <ion-label>Budget</ion-label>\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('calendar')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'calendar'\"\n (click)=\"closeMenu()\"\n >\n <ion-icon name=\"calendar-outline\" slot=\"start\" />\n <ion-label>Calendar</ion-label>\n <!--\t\t<ion-buttons slot=\"end\">-->\n <!--\t\t\t<ion-button color=\"primary\" style=\"text-transform: none; font-size: x-small\">Today</ion-button>-->\n <!--\t\t\t<ion-button color=\"primary\" style=\"text-transform: none; font-size: x-small\">Tomorrow</ion-button>-->\n <!--\t\t</ion-buttons>-->\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('contacts')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'contacts'\"\n (click)=\"goSpacePage($event, 'contacts')\"\n >\n <ion-icon name=\"people-outline\" slot=\"start\" />\n <ion-label>Contacts</ion-label>\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('debts')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'debts'\"\n (click)=\"goSpacePage($event, 'debts')\"\n >\n <ion-icon name=\"cash-outline\" slot=\"start\" />\n <ion-label>Debts</ion-label>\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('documents')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'documents'\"\n (click)=\"goSpacePage($event, 'documents')\"\n >\n <ion-icon name=\"documents-outline\" slot=\"start\" />\n <ion-label>Documents</ion-label>\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('lists')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'lists'\"\n (click)=\"goSpacePage($event, 'lists')\"\n >\n <ion-icon name=\"list-outline\" slot=\"start\" />\n <ion-label>Lists</ion-label>\n <ion-buttons slot=\"end\">\n <ion-button\n routerDirection=\"root\"\n [routerLink]=\"spacePageUrl('list/buy/groceries')\"\n (click)=\"goSpacePage($event, 'list/buy/groceries')\"\n >\n <ion-label>\uD83D\uDED2</ion-label>\n </ion-button>\n <!--\t\t\t<ion-button routerLink=\"./list/towatch\">\uD83C\uDF7F</ion-button>-->\n </ion-buttons>\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('members')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'members'\"\n (click)=\"closeMenu()\"\n >\n <ion-icon name=\"people-circle-outline\" slot=\"start\" />\n <ion-label>Members</ion-label>\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('trackers')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'trackers'\"\n (click)=\"closeMenu()\"\n >\n <ion-icon name=\"bar-chart-outline\" slot=\"start\" />\n <ion-label>Trackers</ion-label>\n </ion-item>\n <sneat-auth-menu-item />\n</ion-list>\n", styles: [".currentPage ion-label{font-weight:700}\n"] }]
118
+ }], ctorParameters: () => [] });
119
+ //# sourceMappingURL=space-menu.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"space-menu.component.js","sourceRoot":"","sources":["../../../../../../../libs/space/components/src/lib/space-menu/space-menu.component.ts","../../../../../../../libs/space/components/src/lib/space-menu/space-menu.component.html"],"names":[],"mappings":"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","sourcesContent":["import { TitleCasePipe } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n computed,\n inject,\n signal,\n} from '@angular/core';\nimport {\n ActivatedRoute,\n NavigationEnd,\n Router,\n RouterLink,\n} from '@angular/router';\nimport {\n IonButton,\n IonButtons,\n IonIcon,\n IonItem,\n IonLabel,\n IonList,\n IonSelect,\n IonSelectOption,\n MenuController,\n} from '@ionic/angular/standalone';\nimport { ISneatUserState } from '@sneat/auth-core';\nimport { IUserSpaceBrief } from '@sneat/auth-models';\nimport { AuthMenuItemComponent } from '@sneat/auth-ui';\nimport { ContactusServicesModule } from '@sneat/contactus-services';\nimport { IIdAndBrief } from '@sneat/core';\nimport { zipMapBriefsWithIDs } from '@sneat/space-models';\nimport { SpaceServiceModule } from '@sneat/space-services';\nimport { filter } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { SpaceBaseComponent } from '../space-base-component.directive';\nimport { SpaceComponentBaseParams } from '../space-component-base-params.service';\nimport { ClassName } from '@sneat/ui';\n\n@Component({\n selector: 'sneat-space-menu',\n templateUrl: './space-menu.component.html',\n styles: '.currentPage ion-label {font-weight: bold}',\n imports: [\n AuthMenuItemComponent,\n ContactusServicesModule,\n SpaceServiceModule,\n TitleCasePipe,\n RouterLink,\n IonList,\n IonItem,\n IonSelect,\n IonSelectOption,\n IonIcon,\n IonLabel,\n IonButtons,\n IonButton,\n ],\n providers: [\n {\n provide: ClassName,\n useValue: 'SpaceMenuComponent',\n },\n SpaceComponentBaseParams,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SpaceMenuComponent extends SpaceBaseComponent {\n protected readonly $spaces = signal<\n readonly IIdAndBrief<IUserSpaceBrief>[] | undefined\n >(undefined);\n\n protected readonly $disabled = computed(() => !this.$spaceID());\n\n protected readonly $currentPage = signal<string>('');\n\n private readonly activatedRoute = inject(ActivatedRoute);\n private readonly menuCtrl = inject(MenuController);\n\n constructor() {\n const router = inject(Router);\n\n super();\n this.spaceParams.userService.userState\n .pipe(takeUntil(this.destroyed$))\n .subscribe({\n next: this.onUserStateChanged,\n error: this.errorLogger.logErrorHandler('failed to get user stage'),\n });\n router.events\n .pipe(\n this.takeUntilDestroyed(),\n filter((event) => event instanceof NavigationEnd),\n )\n .subscribe((event: NavigationEnd) => {\n let route = this.activatedRoute.firstChild;\n while (route?.firstChild) {\n route = route.firstChild;\n }\n const url = event.urlAfterRedirects.split('/');\n this.$currentPage.set(url.length > 4 ? url[4] : '');\n });\n }\n\n // TODO: Should we use goSpacePage('') instead?\n protected goOverview(): boolean {\n const space = this.$space();\n if (!space) {\n this.errorLogger.logError('no space context');\n return false;\n }\n this.spaceParams.spaceNavService.navigateToSpace(space).then((v) => {\n if (v) {\n this.closeMenu();\n }\n });\n return false;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n protected goSpacePage(event: Event, _p: string): boolean {\n // At the moment we use routerLink for navigation\n event.stopPropagation();\n // event.preventDefault();\n this.closeMenu();\n return false;\n }\n\n protected closeMenu(): void {\n this.menuCtrl.close().catch(this.errorLogger.logError);\n }\n\n protected onSpaceSelected(event: Event): void {\n const spaceID = (event as CustomEvent).detail.value as string;\n if (spaceID === this.space?.id) {\n return;\n }\n const space = this.$spaces()?.find((t) => t.id === spaceID);\n if (space) {\n this.setSpaceRef(space);\n this.spaceNav\n .navigateToSpace(space)\n .catch(\n this.errorLogger.logErrorHandler(\n 'Failed to navigate to teams page on current team changed from team menu dropdown',\n ),\n );\n }\n this.menuCtrl.close().catch(console.error);\n return;\n }\n\n private readonly onUserStateChanged = (userState: ISneatUserState): void => {\n this.$spaces.set(\n userState?.record\n ? zipMapBriefsWithIDs(userState.record.spaces) || []\n : undefined,\n );\n };\n}\n","<ion-list>\n <ion-item>\n <!--\t\t<ion-icon [name]=\"space.type === 'family' ? 'people-outline' : space.type === 'private' ? 'person-circle-outline' : 'people-outline' \" slot=\"end\" />-->\n <ion-select\n label=\"Space\"\n [value]=\"$space().id\"\n interface=\"popover\"\n (ionChange)=\"onSpaceSelected($event)\"\n style=\"font-weight: bold\"\n >\n @for (userSpace of $spaces(); track userSpace.id) {\n <ion-select-option [value]=\"userSpace.id\"\n >{{\n userSpace.brief.title ||\n (userSpace.brief.type | titlecase) ||\n space.id\n }}\n </ion-select-option>\n } @empty {\n @let space = $space();\n <ion-select-option [value]=\"space?.id\">\n @if (!space || (!space?.id && !space?.type)) {\n Loading...\n } @else {\n {{ space.brief?.title || (space.type | titlecase) || space.id }}\n }\n </ion-select-option>\n }\n </ion-select>\n <!--\t\t@if (!spaces) {-->\n <!--\t\t\t<ion-spinner name=\"lines\" slot=\"end\"></ion-spinner>-->\n <!--\t\t}-->\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('overview')\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === ''\"\n (click)=\"goOverview()\"\n >\n <ion-icon name=\"home-outline\" slot=\"start\" />\n <ion-label>Overview</ion-label>\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('assets')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'assets'\"\n (click)=\"goSpacePage($event, 'assets')\"\n >\n <ion-icon name=\"car-sport-outline\" slot=\"start\" />\n <ion-label>Assets</ion-label>\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('budget')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'budget'\"\n (click)=\"goSpacePage($event, 'budget')\"\n >\n <ion-icon name=\"cash-outline\" slot=\"start\" />\n <ion-label>Budget</ion-label>\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('calendar')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'calendar'\"\n (click)=\"closeMenu()\"\n >\n <ion-icon name=\"calendar-outline\" slot=\"start\" />\n <ion-label>Calendar</ion-label>\n <!--\t\t<ion-buttons slot=\"end\">-->\n <!--\t\t\t<ion-button color=\"primary\" style=\"text-transform: none; font-size: x-small\">Today</ion-button>-->\n <!--\t\t\t<ion-button color=\"primary\" style=\"text-transform: none; font-size: x-small\">Tomorrow</ion-button>-->\n <!--\t\t</ion-buttons>-->\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('contacts')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'contacts'\"\n (click)=\"goSpacePage($event, 'contacts')\"\n >\n <ion-icon name=\"people-outline\" slot=\"start\" />\n <ion-label>Contacts</ion-label>\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('debts')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'debts'\"\n (click)=\"goSpacePage($event, 'debts')\"\n >\n <ion-icon name=\"cash-outline\" slot=\"start\" />\n <ion-label>Debts</ion-label>\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('documents')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'documents'\"\n (click)=\"goSpacePage($event, 'documents')\"\n >\n <ion-icon name=\"documents-outline\" slot=\"start\" />\n <ion-label>Documents</ion-label>\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('lists')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'lists'\"\n (click)=\"goSpacePage($event, 'lists')\"\n >\n <ion-icon name=\"list-outline\" slot=\"start\" />\n <ion-label>Lists</ion-label>\n <ion-buttons slot=\"end\">\n <ion-button\n routerDirection=\"root\"\n [routerLink]=\"spacePageUrl('list/buy/groceries')\"\n (click)=\"goSpacePage($event, 'list/buy/groceries')\"\n >\n <ion-label>🛒</ion-label>\n </ion-button>\n <!--\t\t\t<ion-button routerLink=\"./list/towatch\">🍿</ion-button>-->\n </ion-buttons>\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('members')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'members'\"\n (click)=\"closeMenu()\"\n >\n <ion-icon name=\"people-circle-outline\" slot=\"start\" />\n <ion-label>Members</ion-label>\n </ion-item>\n <ion-item\n tappable\n [routerLink]=\"spacePageUrl('trackers')\"\n routerDirection=\"root\"\n [disabled]=\"$disabled()\"\n [class.currentPage]=\"$currentPage() === 'trackers'\"\n (click)=\"closeMenu()\"\n >\n <ion-icon name=\"bar-chart-outline\" slot=\"start\" />\n <ion-label>Trackers</ion-label>\n </ion-item>\n <sneat-auth-menu-item />\n</ion-list>\n"]}
@@ -0,0 +1,28 @@
1
+ import { BehaviorSubject } from 'rxjs';
2
+ import { takeUntil } from 'rxjs/operators';
3
+ import { SpaceBaseComponent } from './space-base-component.directive';
4
+ export class SpaceModuleBaseComponent extends SpaceBaseComponent {
5
+ constructor(spaceModuleService) {
6
+ super();
7
+ this.spaceModuleService = spaceModuleService;
8
+ this.spaceModuleDbo$ = new BehaviorSubject(undefined);
9
+ }
10
+ onSpaceIdChanged() {
11
+ super.onSpaceIdChanged();
12
+ this.spaceModuleService
13
+ .watchSpaceModuleRecord(this.space.id)
14
+ .pipe(takeUntil(this.spaceIDChanged$))
15
+ .subscribe({
16
+ next: (o) => {
17
+ this.spaceModuleDbo$.next(o.dbo);
18
+ this.onSpaceModuleDboChanged(o.dbo || null);
19
+ },
20
+ error: (err) => {
21
+ console.error('Failed to load team module record', err);
22
+ },
23
+ });
24
+ }
25
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
26
+ onSpaceModuleDboChanged(_dbo) { }
27
+ }
28
+ //# sourceMappingURL=space-module-base.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"space-module-base.component.js","sourceRoot":"","sources":["../../../../../../libs/space/components/src/lib/space-module-base.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,MAAM,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAGtE,MAAM,OAAgB,wBAGpB,SAAQ,kBAAkB;IAK1B,YAAsB,kBAA2C;QAC/D,KAAK,EAAE,CAAC;QADY,uBAAkB,GAAlB,kBAAkB,CAAyB;QAJ9C,oBAAe,GAAG,IAAI,eAAe,CAEtD,SAAS,CAAC,CAAC;IAIb,CAAC;IAEkB,gBAAgB;QACjC,KAAK,CAAC,gBAAgB,EAAE,CAAC;QACzB,IAAI,CAAC,kBAAkB;aACpB,sBAAsB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;aACrC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;aACrC,SAAS,CAAC;YACT,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE;gBACV,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;gBACjC,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC;YAC9C,CAAC;YACD,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE;gBACb,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,GAAG,CAAC,CAAC;YAC1D,CAAC;SACF,CAAC,CAAC;IACP,CAAC;IAED,mGAAmG;IACzF,uBAAuB,CAAC,IAAgB,IAAG,CAAC;CACvD","sourcesContent":["import { BehaviorSubject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { SpaceBaseComponent } from './space-base-component.directive';\nimport { SpaceModuleService } from '@sneat/space-services';\n\nexport abstract class SpaceModuleBaseComponent<\n Brief,\n Dbo extends Brief,\n> extends SpaceBaseComponent {\n protected readonly spaceModuleDbo$ = new BehaviorSubject<\n Dbo | null | undefined\n >(undefined);\n\n constructor(protected spaceModuleService: SpaceModuleService<Dbo>) {\n super();\n }\n\n protected override onSpaceIdChanged() {\n super.onSpaceIdChanged();\n this.spaceModuleService\n .watchSpaceModuleRecord(this.space.id)\n .pipe(takeUntil(this.spaceIDChanged$))\n .subscribe({\n next: (o) => {\n this.spaceModuleDbo$.next(o.dbo);\n this.onSpaceModuleDboChanged(o.dbo || null);\n },\n error: (err) => {\n console.error('Failed to load team module record', err);\n },\n });\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function\n protected onSpaceModuleDboChanged(_dbo: Dbo | null) {}\n}\n"]}
@@ -0,0 +1,11 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { SpaceBaseComponent } from './space-base-component.directive';
3
+ import * as i0 from "@angular/core";
4
+ export class SpacePageBaseComponent extends SpaceBaseComponent {
5
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: SpacePageBaseComponent, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
6
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: SpacePageBaseComponent }); }
7
+ }
8
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: SpacePageBaseComponent, decorators: [{
9
+ type: Injectable
10
+ }] });
11
+ //# sourceMappingURL=space-page-base-component.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"space-page-base-component.service.js","sourceRoot":"","sources":["../../../../../../libs/space/components/src/lib/space-page-base-component.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;;AAGtE,MAAM,OAAgB,sBAAuB,SAAQ,kBAAkB;8GAAjD,sBAAsB;kHAAtB,sBAAsB;;2FAAtB,sBAAsB;kBAD3C,UAAU","sourcesContent":["import { Injectable } from '@angular/core';\nimport { SpaceBaseComponent } from './space-base-component.directive';\n\n@Injectable() // we need this decorator so we can implement Angular interfaces\nexport abstract class SpacePageBaseComponent extends SpaceBaseComponent {}\n"]}
@@ -0,0 +1,27 @@
1
+ import { TitleCasePipe } from '@angular/common';
2
+ import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
3
+ import { IonTitle } from '@ionic/angular/standalone';
4
+ import * as i0 from "@angular/core";
5
+ export class SpacePageTitleComponent {
6
+ get typeTitle() {
7
+ return this.space?.type && this.titlesBySpaceType
8
+ ? this.titlesBySpaceType[this.space.type]
9
+ : '';
10
+ }
11
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: SpacePageTitleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
12
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: SpacePageTitleComponent, isStandalone: true, selector: "sneat-space-page-title", inputs: { icon: "icon", generalTitle: "generalTitle", space: "space", titlesBySpaceType: "titlesBySpaceType" }, ngImport: i0, template: "<ion-title>\n @if (space) {\n @if (!!typeTitle) {\n <span style=\"margin-right: 0.5em\">{{ icon }}</span>\n <span>{{ typeTitle }}</span>\n } @else {\n <span style=\"margin-right: 0.5em\">{{ icon }}</span>\n <span\n >{{ generalTitle }} &#64;\n {{ space.brief?.title || (space.type | titlecase) || space.id }}</span\n >\n }\n } @else {\n <span style=\"margin-right: 0.5em\">{{ icon }}</span>\n <span>{{ generalTitle }}</span>\n }\n</ion-title>\n", dependencies: [{ kind: "component", type: IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
13
+ }
14
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: SpacePageTitleComponent, decorators: [{
15
+ type: Component,
16
+ args: [{ imports: [TitleCasePipe, IonTitle], changeDetection: ChangeDetectionStrategy.OnPush, selector: 'sneat-space-page-title', template: "<ion-title>\n @if (space) {\n @if (!!typeTitle) {\n <span style=\"margin-right: 0.5em\">{{ icon }}</span>\n <span>{{ typeTitle }}</span>\n } @else {\n <span style=\"margin-right: 0.5em\">{{ icon }}</span>\n <span\n >{{ generalTitle }} &#64;\n {{ space.brief?.title || (space.type | titlecase) || space.id }}</span\n >\n }\n } @else {\n <span style=\"margin-right: 0.5em\">{{ icon }}</span>\n <span>{{ generalTitle }}</span>\n }\n</ion-title>\n" }]
17
+ }], propDecorators: { icon: [{
18
+ type: Input
19
+ }], generalTitle: [{
20
+ type: Input
21
+ }], space: [{
22
+ type: Input,
23
+ args: [{ required: true }]
24
+ }], titlesBySpaceType: [{
25
+ type: Input
26
+ }] } });
27
+ //# sourceMappingURL=space-page-title.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"space-page-title.component.js","sourceRoot":"","sources":["../../../../../../../libs/space/components/src/lib/space-page-title/space-page-title.component.ts","../../../../../../../libs/space/components/src/lib/space-page-title/space-page-title.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,uBAAuB,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;;AASrD,MAAM,OAAO,uBAAuB;IAMlC,IAAW,SAAS;QAClB,OAAO,IAAI,CAAC,KAAK,EAAE,IAAI,IAAI,IAAI,CAAC,iBAAiB;YAC/C,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;YACzC,CAAC,CAAC,EAAE,CAAC;IACT,CAAC;8GAVU,uBAAuB;kGAAvB,uBAAuB,kMCXpC,sfAiBA,4CDX2B,QAAQ,4EAAvB,aAAa;;2FAKZ,uBAAuB;kBANnC,SAAS;8BACC,CAAC,aAAa,EAAE,QAAQ,CAAC,mBACjB,uBAAuB,CAAC,MAAM,YACrC,wBAAwB;;sBAIjC,KAAK;;sBACL,KAAK;;sBACL,KAAK;uBAAC,EAAE,QAAQ,EAAE,IAAI,EAAE;;sBACxB,KAAK","sourcesContent":["import { TitleCasePipe } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, Input } from '@angular/core';\nimport { IonTitle } from '@ionic/angular/standalone';\nimport { ISpaceContext } from '@sneat/space-models';\n\n@Component({\n imports: [TitleCasePipe, IonTitle],\n changeDetection: ChangeDetectionStrategy.OnPush,\n selector: 'sneat-space-page-title',\n templateUrl: './space-page-title.component.html',\n})\nexport class SpacePageTitleComponent {\n @Input() icon?: string;\n @Input() generalTitle?: string;\n @Input({ required: true }) space?: ISpaceContext;\n @Input() titlesBySpaceType?: Record<string, string>;\n\n public get typeTitle(): string {\n return this.space?.type && this.titlesBySpaceType\n ? this.titlesBySpaceType[this.space.type]\n : '';\n }\n}\n","<ion-title>\n @if (space) {\n @if (!!typeTitle) {\n <span style=\"margin-right: 0.5em\">{{ icon }}</span>\n <span>{{ typeTitle }}</span>\n } @else {\n <span style=\"margin-right: 0.5em\">{{ icon }}</span>\n <span\n >{{ generalTitle }} &#64;\n {{ space.brief?.title || (space.type | titlecase) || space.id }}</span\n >\n }\n } @else {\n <span style=\"margin-right: 0.5em\">{{ icon }}</span>\n <span>{{ generalTitle }}</span>\n }\n</ion-title>\n"]}
@@ -0,0 +1,2 @@
1
+ export * from './spaces-card.component';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../libs/space/components/src/lib/spaces-card/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC","sourcesContent":["export * from './spaces-card.component';\n"]}
@@ -0,0 +1,208 @@
1
+ import { Component, ViewChild, inject } from '@angular/core';
2
+ import { FormsModule } from '@angular/forms';
3
+ import { IonButton, IonButtons, IonCard, IonCardContent, IonCardTitle, IonIcon, IonInput, IonItem, IonItemOption, IonItemOptions, IonItemSliding, IonLabel, IonList, IonSkeletonText, IonSpinner, ToastController, } from '@ionic/angular/standalone';
4
+ import { AnalyticsService } from '@sneat/core';
5
+ import { ErrorLogger } from '@sneat/core';
6
+ import { SpaceNavService, SpaceService } from '@sneat/space-services';
7
+ import { SneatUserService } from '@sneat/auth-core';
8
+ import { Subject } from 'rxjs';
9
+ import { takeUntil } from 'rxjs/operators';
10
+ import * as i0 from "@angular/core";
11
+ import * as i1 from "@angular/forms";
12
+ export class SpacesCardComponent {
13
+ constructor() {
14
+ this.errorLogger = inject(ErrorLogger);
15
+ this.navService = inject(SpaceNavService);
16
+ this.userService = inject(SneatUserService);
17
+ this.spaceService = inject(SpaceService);
18
+ this.analyticsService = inject(AnalyticsService);
19
+ this.toastController = inject(ToastController);
20
+ this.loadingState = 'Authenticating';
21
+ this.spaceName = '';
22
+ this.adding = false;
23
+ this.showAdd = false; //
24
+ this.destroyed = new Subject();
25
+ this.subscriptions = [];
26
+ this.setUser = (userState) => {
27
+ // console.log('SpacesCardComponent => user:', userState);
28
+ const user = userState.record;
29
+ if (user) {
30
+ this.spaces = Object.entries(user?.spaces ? user.spaces : {}).map(([id, team]) => ({ id, brief: team }));
31
+ this.spaces.sort((a, b) => (a.brief.title > b.brief.title ? 1 : -1));
32
+ this.showAdd = !this.spaces?.length;
33
+ if (this.showAdd) {
34
+ this.startAddingSpace();
35
+ }
36
+ }
37
+ else {
38
+ this.spaces = undefined;
39
+ }
40
+ };
41
+ }
42
+ ngOnDestroy() {
43
+ // console.log('SpacesCardComponent.ngOnDestroy()');
44
+ this.destroyed.next();
45
+ this.destroyed.complete();
46
+ this.unsubscribe('ngOnDestroy');
47
+ }
48
+ ngOnInit() {
49
+ this.watchUserRecord();
50
+ }
51
+ goSpace(space) {
52
+ this.navService
53
+ .navigateToSpace(space, 'forward')
54
+ .catch(this.errorLogger.logError);
55
+ }
56
+ addSpace() {
57
+ this.analyticsService.logEvent('addSpace');
58
+ const title = this.spaceName.trim();
59
+ if (!title) {
60
+ this.toastController
61
+ .create({
62
+ position: 'middle',
63
+ message: 'Space name is required',
64
+ color: 'tertiary',
65
+ duration: 5000,
66
+ keyboardClose: true,
67
+ buttons: [{ role: 'cancel', text: 'OK' }],
68
+ })
69
+ .then((toast) => toast
70
+ .present()
71
+ .catch((err) => this.errorLogger.logError(err, 'Failed to present toast')))
72
+ .catch((err) => this.errorLogger.logError(err, 'Faile to create toast'));
73
+ return;
74
+ }
75
+ if (this.spaces?.find((t) => t.brief.title === title)) {
76
+ this.toastController
77
+ .create({
78
+ message: 'You already have a team with the same name',
79
+ color: 'danger',
80
+ buttons: ['close'],
81
+ position: 'middle',
82
+ animated: true,
83
+ duration: 3000,
84
+ })
85
+ .then((toast) => {
86
+ toast
87
+ .present()
88
+ .catch((err) => this.errorLogger.logError(err, 'Failed to present toast'));
89
+ })
90
+ .catch((err) => this.errorLogger.logError(err, 'Failed to create toast'));
91
+ return;
92
+ }
93
+ const request = {
94
+ type: 'team',
95
+ // memberType: TeamMemberType.creator,
96
+ title,
97
+ };
98
+ this.adding = true;
99
+ this.spaceService.createSpace(request).subscribe({
100
+ next: (space) => {
101
+ this.analyticsService.logEvent('spaceCreated', { space: space.id });
102
+ const userTeamBrief2 = {
103
+ userContactID: 'TODO: populate userContactID',
104
+ title: space?.dbo?.title || space.id,
105
+ roles: ['creator'],
106
+ // memberType: request.memberType,
107
+ type: space?.dbo?.type || 'unknown',
108
+ };
109
+ if (userTeamBrief2 && !this.spaces?.find((t) => t.id === space.id)) {
110
+ this.spaces?.push({ id: space.id, brief: userTeamBrief2 });
111
+ }
112
+ this.adding = false;
113
+ this.spaceName = '';
114
+ this.goSpace(space);
115
+ },
116
+ error: (err) => {
117
+ this.errorLogger.logError(err, 'Failed to create new team record');
118
+ this.adding = false;
119
+ },
120
+ });
121
+ }
122
+ startAddingSpace() {
123
+ this.showAdd = true;
124
+ setTimeout(() => {
125
+ if (!this.addSpaceInput) {
126
+ this.errorLogger.logError('addTeamInput is not set');
127
+ return;
128
+ }
129
+ this.addSpaceInput
130
+ .setFocus()
131
+ .catch((err) => this.errorLogger.logError(err, 'Failed to set focus to "addTeamInput"'));
132
+ }, 200);
133
+ }
134
+ leaveSpace(space, event) {
135
+ if (event) {
136
+ event.stopPropagation();
137
+ event.preventDefault();
138
+ }
139
+ if (!confirm(`Are you sure you want to leave team ${space.brief.title}?`)) {
140
+ return;
141
+ }
142
+ const userID = this.userService.currentUserID;
143
+ if (!userID) {
144
+ this.errorLogger.logError('Failed to get current user ID');
145
+ return;
146
+ }
147
+ this.spaceService.leaveSpace({ spaceID: space.id }).subscribe({
148
+ next: () => console.log('left space'),
149
+ error: (err) => this.errorLogger.logError(err, `Failed to leave a space: ${space.brief.title}`),
150
+ });
151
+ }
152
+ watchUserRecord() {
153
+ this.userService.userState.pipe(takeUntil(this.destroyed)).subscribe({
154
+ next: (userState) => {
155
+ // console.log('SpacesCardComponent => user state changed:', userState);
156
+ if (userState.status === 'authenticating') {
157
+ if (this.loadingState === 'Authenticating') {
158
+ this.loadingState = 'Loading';
159
+ }
160
+ }
161
+ const uid = userState.user?.uid;
162
+ this.spaces = undefined;
163
+ if (!uid) {
164
+ this.unsubscribe('user signed out');
165
+ return;
166
+ }
167
+ this.subscriptions.push(this.userService.userState.subscribe({
168
+ next: this.setUser,
169
+ error: (err) => this.errorLogger.logError(err, 'Failed to get user record'),
170
+ }));
171
+ },
172
+ error: (err) => this.errorLogger.logError(err, 'Failed to get user ID'),
173
+ });
174
+ }
175
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
176
+ unsubscribe(_reason) {
177
+ // console.log(`SpacesCardComponent.unsubscribe(reason: ${reason})`);
178
+ this.subscriptions.forEach((s) => s.unsubscribe());
179
+ this.subscriptions = [];
180
+ }
181
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: SpacesCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
182
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: SpacesCardComponent, isStandalone: true, selector: "sneat-spaces-card", viewQueries: [{ propertyName: "addSpaceInput", first: true, predicate: IonInput, descendants: true }], ngImport: i0, template: "<ion-card>\n <ion-item>\n <ion-label>\n <ion-card-title color=\"medium\">Spaces</ion-card-title>\n </ion-label>\n <ion-buttons slot=\"end\" (click)=\"startAddingSpace()\">\n @if (!showAdd) {\n <ion-button color=\"primary\">\n <ion-icon name=\"add\" slot=\"start\" />\n <ion-label>Add</ion-label>\n </ion-button>\n }\n </ion-buttons>\n </ion-item>\n @if (spaces) {\n <ion-list>\n @for (space of spaces; track space.id) {\n <ion-item-sliding>\n <ion-item tappable detail (click)=\"goSpace(space)\">\n <ion-label>{{ space.brief.title }}</ion-label>\n <ion-buttons slot=\"end\">\n <ion-button color=\"medium\" (click)=\"leaveSpace(space, $event)\">\n <ion-icon name=\"close-outline\" />\n </ion-button>\n </ion-buttons>\n </ion-item>\n <ion-item-options side=\"start\">\n <ion-item-option color=\"danger\" (click)=\"leaveSpace(space)\"\n >Leave team\n </ion-item-option>\n </ion-item-options>\n <ion-item-options side=\"end\">\n <ion-item-option color=\"danger\" (click)=\"leaveSpace(space)\"\n >Leave team\n </ion-item-option>\n </ion-item-options>\n </ion-item-sliding>\n }\n </ion-list>\n } @else {\n <ion-list>\n <ion-item>\n <ion-spinner name=\"\" slot=\"start\" color=\"medium\" />\n <ion-buttons slot=\"start\">\n <ion-button disabled=\"disabled\" style=\"text-transform: none\"\n >{{ loadingState }}...\n </ion-button>\n </ion-buttons>\n <ion-skeleton-text animated />\n </ion-item>\n </ion-list>\n }\n\n @if (showAdd) {\n <ion-item [disabled]=\"adding\">\n <ion-input\n (keyup.enter)=\"addSpace()\"\n #addTeamInput\n [(ngModel)]=\"spaceName\"\n (keyup.escape)=\"showAdd = false\"\n placeholder=\"New team name\"\n />\n <ion-buttons slot=\"end\">\n <ion-button color=\"primary\" fill=\"solid\" (click)=\"addSpace()\">\n <ion-label>Create</ion-label>\n </ion-button>\n @if (!!spaces?.length) {\n <ion-button (click)=\"showAdd = false\" color=\"medium\" title=\"Cancel\">\n @if (adding) {\n <ion-spinner />\n } @else {\n <ion-icon name=\"close-outline\" />\n }\n </ion-button>\n }\n </ion-buttons>\n </ion-item>\n }\n @if (showAdd) {\n <ion-card-content>\n <p>Enter team name and click \"Create\" button to add a new team.</p>\n </ion-card-content>\n }\n</ion-card>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "size", "spellcheck", "step", "type", "value"] }, { kind: "component", type: IonCard, selector: "ion-card", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonCardTitle, selector: "ion-card-title", inputs: ["color", "mode"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonItemSliding, selector: "ion-item-sliding", inputs: ["disabled"] }, { kind: "component", type: IonItemOptions, selector: "ion-item-options", inputs: ["side"] }, { kind: "component", type: IonItemOption, selector: "ion-item-option", inputs: ["color", "disabled", "download", "expandable", "href", "mode", "rel", "target", "type"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: IonSkeletonText, selector: "ion-skeleton-text", inputs: ["animated"] }, { kind: "component", type: IonCardContent, selector: "ion-card-content", inputs: ["mode"] }] }); }
183
+ }
184
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: SpacesCardComponent, decorators: [{
185
+ type: Component,
186
+ args: [{ selector: 'sneat-spaces-card', imports: [
187
+ FormsModule,
188
+ IonInput,
189
+ IonCard,
190
+ IonItem,
191
+ IonLabel,
192
+ IonCardTitle,
193
+ IonButtons,
194
+ IonButton,
195
+ IonIcon,
196
+ IonList,
197
+ IonItemSliding,
198
+ IonItemOptions,
199
+ IonItemOption,
200
+ IonSpinner,
201
+ IonSkeletonText,
202
+ IonCardContent,
203
+ ], template: "<ion-card>\n <ion-item>\n <ion-label>\n <ion-card-title color=\"medium\">Spaces</ion-card-title>\n </ion-label>\n <ion-buttons slot=\"end\" (click)=\"startAddingSpace()\">\n @if (!showAdd) {\n <ion-button color=\"primary\">\n <ion-icon name=\"add\" slot=\"start\" />\n <ion-label>Add</ion-label>\n </ion-button>\n }\n </ion-buttons>\n </ion-item>\n @if (spaces) {\n <ion-list>\n @for (space of spaces; track space.id) {\n <ion-item-sliding>\n <ion-item tappable detail (click)=\"goSpace(space)\">\n <ion-label>{{ space.brief.title }}</ion-label>\n <ion-buttons slot=\"end\">\n <ion-button color=\"medium\" (click)=\"leaveSpace(space, $event)\">\n <ion-icon name=\"close-outline\" />\n </ion-button>\n </ion-buttons>\n </ion-item>\n <ion-item-options side=\"start\">\n <ion-item-option color=\"danger\" (click)=\"leaveSpace(space)\"\n >Leave team\n </ion-item-option>\n </ion-item-options>\n <ion-item-options side=\"end\">\n <ion-item-option color=\"danger\" (click)=\"leaveSpace(space)\"\n >Leave team\n </ion-item-option>\n </ion-item-options>\n </ion-item-sliding>\n }\n </ion-list>\n } @else {\n <ion-list>\n <ion-item>\n <ion-spinner name=\"\" slot=\"start\" color=\"medium\" />\n <ion-buttons slot=\"start\">\n <ion-button disabled=\"disabled\" style=\"text-transform: none\"\n >{{ loadingState }}...\n </ion-button>\n </ion-buttons>\n <ion-skeleton-text animated />\n </ion-item>\n </ion-list>\n }\n\n @if (showAdd) {\n <ion-item [disabled]=\"adding\">\n <ion-input\n (keyup.enter)=\"addSpace()\"\n #addTeamInput\n [(ngModel)]=\"spaceName\"\n (keyup.escape)=\"showAdd = false\"\n placeholder=\"New team name\"\n />\n <ion-buttons slot=\"end\">\n <ion-button color=\"primary\" fill=\"solid\" (click)=\"addSpace()\">\n <ion-label>Create</ion-label>\n </ion-button>\n @if (!!spaces?.length) {\n <ion-button (click)=\"showAdd = false\" color=\"medium\" title=\"Cancel\">\n @if (adding) {\n <ion-spinner />\n } @else {\n <ion-icon name=\"close-outline\" />\n }\n </ion-button>\n }\n </ion-buttons>\n </ion-item>\n }\n @if (showAdd) {\n <ion-card-content>\n <p>Enter team name and click \"Create\" button to add a new team.</p>\n </ion-card-content>\n }\n</ion-card>\n" }]
204
+ }], propDecorators: { addSpaceInput: [{
205
+ type: ViewChild,
206
+ args: [IonInput, { static: false }]
207
+ }] } });
208
+ //# sourceMappingURL=spaces-card.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spaces-card.component.js","sourceRoot":"","sources":["../../../../../../../libs/space/components/src/lib/spaces-card/spaces-card.component.ts","../../../../../../../libs/space/components/src/lib/spaces-card/spaces-card.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAqB,SAAS,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EACL,SAAS,EACT,UAAU,EACV,OAAO,EACP,cAAc,EACd,YAAY,EACZ,OAAO,EACP,QAAQ,EACR,OAAO,EACP,aAAa,EACb,cAAc,EACd,cAAc,EACd,QAAQ,EACR,OAAO,EACP,eAAe,EACf,UAAU,EACV,eAAe,GAChB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,gBAAgB,EAAqB,MAAM,aAAa,CAAC;AAGlE,OAAO,EAAE,WAAW,EAAgB,MAAM,aAAa,CAAC;AAExD,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAmB,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,OAAO,EAAgB,MAAM,MAAM,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;;;AAwB3C,MAAM,OAAO,mBAAmB;IAtBhC;QAuBmB,gBAAW,GAAG,MAAM,CAAe,WAAW,CAAC,CAAC;QAChD,eAAU,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;QACrC,gBAAW,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;QACvC,iBAAY,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;QACpC,qBAAgB,GAC/B,MAAM,CAAoB,gBAAgB,CAAC,CAAC;QAC7B,oBAAe,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;QAKpD,iBAAY,GAAiC,gBAAgB,CAAC;QAC9D,cAAS,GAAG,EAAE,CAAC;QACf,WAAM,GAAG,KAAK,CAAC;QACf,YAAO,GAAG,KAAK,CAAC,CAAC,EAAE;QACT,cAAS,GAAG,IAAI,OAAO,EAAQ,CAAC;QACzC,kBAAa,GAAmB,EAAE,CAAC;QA2KnC,YAAO,GAAG,CAAC,SAA0B,EAAQ,EAAE;YACrD,0DAA0D;YAC1D,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC;YAC9B,IAAI,IAAI,EAAE,CAAC;gBACT,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAC/D,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CACtC,CAAC;gBACF,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBACrE,IAAI,CAAC,OAAO,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC;gBACpC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;oBACjB,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBAC1B,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;YAC1B,CAAC;QACH,CAAC,CAAC;KACH;IAzLQ,WAAW;QAChB,oDAAoD;QACpD,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QACtB,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC;QAC1B,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;IAClC,CAAC;IAEM,QAAQ;QACb,IAAI,CAAC,eAAe,EAAE,CAAC;IACzB,CAAC;IAEM,OAAO,CAAC,KAAoB;QACjC,IAAI,CAAC,UAAU;aACZ,eAAe,CAAC,KAAK,EAAE,SAAS,CAAC;aACjC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IACtC,CAAC;IAEM,QAAQ;QACb,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QACpC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,IAAI,CAAC,eAAe;iBACjB,MAAM,CAAC;gBACN,QAAQ,EAAE,QAAQ;gBAClB,OAAO,EAAE,wBAAwB;gBACjC,KAAK,EAAE,UAAU;gBACjB,QAAQ,EAAE,IAAI;gBACd,aAAa,EAAE,IAAI;gBACnB,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;aAC1C,CAAC;iBACD,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CACd,KAAK;iBACF,OAAO,EAAE;iBACT,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CACb,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,EAAE,yBAAyB,CAAC,CAC1D,CACJ;iBACA,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CACb,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,EAAE,uBAAuB,CAAC,CACxD,CAAC;YACJ,OAAO;QACT,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,EAAE,CAAC;YACtD,IAAI,CAAC,eAAe;iBACjB,MAAM,CAAC;gBACN,OAAO,EAAE,4CAA4C;gBACrD,KAAK,EAAE,QAAQ;gBACf,OAAO,EAAE,CAAC,OAAO,CAAC;gBAClB,QAAQ,EAAE,QAAQ;gBAClB,QAAQ,EAAE,IAAI;gBACd,QAAQ,EAAE,IAAI;aACf,CAAC;iBACD,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;gBACd,KAAK;qBACF,OAAO,EAAE;qBACT,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CACb,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,EAAE,yBAAyB,CAAC,CAC1D,CAAC;YACN,CAAC,CAAC;iBACD,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CACb,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,EAAE,wBAAwB,CAAC,CACzD,CAAC;YACJ,OAAO;QACT,CAAC;QACD,MAAM,OAAO,GAAwB;YACnC,IAAI,EAAE,MAAM;YACZ,sCAAsC;YACtC,KAAK;SACN,CAAC;QACF,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC;YAC/C,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE;gBACd,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;gBACpE,MAAM,cAAc,GAAoB;oBACtC,aAAa,EAAE,8BAA8B;oBAC7C,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,IAAI,KAAK,CAAC,EAAE;oBACpC,KAAK,EAAE,CAAC,SAAS,CAAC;oBAClB,kCAAkC;oBAClC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,IAAI,SAAS;iBACpC,CAAC;gBACF,IAAI,cAAc,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;oBACnE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;gBAC7D,CAAC;gBACD,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;gBACpB,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC;gBACpB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YACtB,CAAC;YACD,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE;gBACb,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,EAAE,kCAAkC,CAAC,CAAC;gBACnE,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;YACtB,CAAC;SACF,CAAC,CAAC;IACL,CAAC;IAEM,gBAAgB;QACrB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,UAAU,CAAC,GAAG,EAAE;YACd,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;gBACxB,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,yBAAyB,CAAC,CAAC;gBACrD,OAAO;YACT,CAAC;YACD,IAAI,CAAC,aAAa;iBACf,QAAQ,EAAE;iBACV,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CACb,IAAI,CAAC,WAAW,CAAC,QAAQ,CACvB,GAAG,EACH,uCAAuC,CACxC,CACF,CAAC;QACN,CAAC,EAAE,GAAG,CAAC,CAAC;IACV,CAAC;IAEM,UAAU,CAAC,KAAmC,EAAE,KAAa;QAClE,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,CAAC,eAAe,EAAE,CAAC;YACxB,KAAK,CAAC,cAAc,EAAE,CAAC;QACzB,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,uCAAuC,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;YAC1E,OAAO;QACT,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC;QAC9C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,+BAA+B,CAAC,CAAC;YAC3D,OAAO;QACT,CAAC;QACD,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC;YAC5D,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;YACrC,KAAK,EAAE,CAAC,GAAY,EAAE,EAAE,CACtB,IAAI,CAAC,WAAW,CAAC,QAAQ,CACvB,GAAG,EACH,4BAA4B,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,CAChD;SACJ,CAAC,CAAC;IACL,CAAC;IAEO,eAAe;QACrB,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;YACnE,IAAI,EAAE,CAAC,SAAS,EAAE,EAAE;gBAClB,wEAAwE;gBACxE,IAAI,SAAS,CAAC,MAAM,KAAK,gBAAgB,EAAE,CAAC;oBAC1C,IAAI,IAAI,CAAC,YAAY,KAAK,gBAAgB,EAAE,CAAC;wBAC3C,IAAI,CAAC,YAAY,GAAG,SAAS,CAAC;oBAChC,CAAC;gBACH,CAAC;gBACD,MAAM,GAAG,GAAG,SAAS,CAAC,IAAI,EAAE,GAAG,CAAC;gBAChC,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;gBACxB,IAAI,CAAC,GAAG,EAAE,CAAC;oBACT,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC;oBACpC,OAAO;gBACT,CAAC;gBACD,IAAI,CAAC,aAAa,CAAC,IAAI,CACrB,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,SAAS,CAAC;oBACnC,IAAI,EAAE,IAAI,CAAC,OAAO;oBAClB,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CACb,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,EAAE,2BAA2B,CAAC;iBAC9D,CAAC,CACH,CAAC;YACJ,CAAC;YACD,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,EAAE,uBAAuB,CAAC;SACxE,CAAC,CAAC;IACL,CAAC;IAED,6DAA6D;IACrD,WAAW,CAAC,OAAgB;QAClC,qEAAqE;QACrE,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;QACnD,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC;IAC1B,CAAC;8GA1LU,mBAAmB;kGAAnB,mBAAmB,4HASnB,QAAQ,gDC7DrB,sqFAoFA,2CDlDI,WAAW,+VACX,QAAQ,8eACR,OAAO,yLACP,OAAO,0NACP,QAAQ,6FACR,YAAY,sFACZ,UAAU,8EACV,SAAS,oPACT,OAAO,2JACP,OAAO,yFACP,cAAc,mFACd,cAAc,+EACd,aAAa,8JACb,UAAU,yGACV,eAAe,oFACf,cAAc;;2FAGL,mBAAmB;kBAtB/B,SAAS;+BACE,mBAAmB,WAEpB;wBACP,WAAW;wBACX,QAAQ;wBACR,OAAO;wBACP,OAAO;wBACP,QAAQ;wBACR,YAAY;wBACZ,UAAU;wBACV,SAAS;wBACT,OAAO;wBACP,OAAO;wBACP,cAAc;wBACd,cAAc;wBACd,aAAa;wBACb,UAAU;wBACV,eAAe;wBACf,cAAc;qBACf;;sBAWA,SAAS;uBAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE","sourcesContent":["import { Component, OnDestroy, OnInit, ViewChild, inject } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport {\n IonButton,\n IonButtons,\n IonCard,\n IonCardContent,\n IonCardTitle,\n IonIcon,\n IonInput,\n IonItem,\n IonItemOption,\n IonItemOptions,\n IonItemSliding,\n IonLabel,\n IonList,\n IonSkeletonText,\n IonSpinner,\n ToastController,\n} from '@ionic/angular/standalone';\nimport { AnalyticsService, IAnalyticsService } from '@sneat/core';\nimport { IUserSpaceBrief } from '@sneat/auth-models';\nimport { IIdAndBrief } from '@sneat/core';\nimport { ErrorLogger, IErrorLogger } from '@sneat/core';\nimport { ICreateSpaceRequest, ISpaceContext } from '@sneat/space-models';\nimport { SpaceNavService, SpaceService } from '@sneat/space-services';\nimport { ISneatUserState, SneatUserService } from '@sneat/auth-core';\nimport { Subject, Subscription } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\n\n@Component({\n selector: 'sneat-spaces-card',\n templateUrl: './spaces-card.component.html',\n imports: [\n FormsModule,\n IonInput,\n IonCard,\n IonItem,\n IonLabel,\n IonCardTitle,\n IonButtons,\n IonButton,\n IonIcon,\n IonList,\n IonItemSliding,\n IonItemOptions,\n IonItemOption,\n IonSpinner,\n IonSkeletonText,\n IonCardContent,\n ],\n})\nexport class SpacesCardComponent implements OnInit, OnDestroy {\n private readonly errorLogger = inject<IErrorLogger>(ErrorLogger);\n private readonly navService = inject(SpaceNavService);\n private readonly userService = inject(SneatUserService);\n private readonly spaceService = inject(SpaceService);\n private readonly analyticsService =\n inject<IAnalyticsService>(AnalyticsService);\n private readonly toastController = inject(ToastController);\n\n @ViewChild(IonInput, { static: false }) addSpaceInput?: IonInput; // TODO: IonInput;\n\n public spaces?: IIdAndBrief<IUserSpaceBrief>[];\n public loadingState: 'Authenticating' | 'Loading' = 'Authenticating';\n public spaceName = '';\n public adding = false;\n public showAdd = false; //\n private readonly destroyed = new Subject<void>();\n private subscriptions: Subscription[] = [];\n\n public ngOnDestroy(): void {\n // console.log('SpacesCardComponent.ngOnDestroy()');\n this.destroyed.next();\n this.destroyed.complete();\n this.unsubscribe('ngOnDestroy');\n }\n\n public ngOnInit(): void {\n this.watchUserRecord();\n }\n\n public goSpace(space: ISpaceContext) {\n this.navService\n .navigateToSpace(space, 'forward')\n .catch(this.errorLogger.logError);\n }\n\n public addSpace() {\n this.analyticsService.logEvent('addSpace');\n const title = this.spaceName.trim();\n if (!title) {\n this.toastController\n .create({\n position: 'middle',\n message: 'Space name is required',\n color: 'tertiary',\n duration: 5000,\n keyboardClose: true,\n buttons: [{ role: 'cancel', text: 'OK' }],\n })\n .then((toast) =>\n toast\n .present()\n .catch((err) =>\n this.errorLogger.logError(err, 'Failed to present toast'),\n ),\n )\n .catch((err) =>\n this.errorLogger.logError(err, 'Faile to create toast'),\n );\n return;\n }\n if (this.spaces?.find((t) => t.brief.title === title)) {\n this.toastController\n .create({\n message: 'You already have a team with the same name',\n color: 'danger',\n buttons: ['close'],\n position: 'middle',\n animated: true,\n duration: 3000,\n })\n .then((toast) => {\n toast\n .present()\n .catch((err) =>\n this.errorLogger.logError(err, 'Failed to present toast'),\n );\n })\n .catch((err) =>\n this.errorLogger.logError(err, 'Failed to create toast'),\n );\n return;\n }\n const request: ICreateSpaceRequest = {\n type: 'team',\n // memberType: TeamMemberType.creator,\n title,\n };\n this.adding = true;\n this.spaceService.createSpace(request).subscribe({\n next: (space) => {\n this.analyticsService.logEvent('spaceCreated', { space: space.id });\n const userTeamBrief2: IUserSpaceBrief = {\n userContactID: 'TODO: populate userContactID',\n title: space?.dbo?.title || space.id,\n roles: ['creator'],\n // memberType: request.memberType,\n type: space?.dbo?.type || 'unknown',\n };\n if (userTeamBrief2 && !this.spaces?.find((t) => t.id === space.id)) {\n this.spaces?.push({ id: space.id, brief: userTeamBrief2 });\n }\n this.adding = false;\n this.spaceName = '';\n this.goSpace(space);\n },\n error: (err) => {\n this.errorLogger.logError(err, 'Failed to create new team record');\n this.adding = false;\n },\n });\n }\n\n public startAddingSpace(): void {\n this.showAdd = true;\n setTimeout(() => {\n if (!this.addSpaceInput) {\n this.errorLogger.logError('addTeamInput is not set');\n return;\n }\n this.addSpaceInput\n .setFocus()\n .catch((err) =>\n this.errorLogger.logError(\n err,\n 'Failed to set focus to \"addTeamInput\"',\n ),\n );\n }, 200);\n }\n\n public leaveSpace(space: IIdAndBrief<IUserSpaceBrief>, event?: Event): void {\n if (event) {\n event.stopPropagation();\n event.preventDefault();\n }\n if (!confirm(`Are you sure you want to leave team ${space.brief.title}?`)) {\n return;\n }\n const userID = this.userService.currentUserID;\n if (!userID) {\n this.errorLogger.logError('Failed to get current user ID');\n return;\n }\n this.spaceService.leaveSpace({ spaceID: space.id }).subscribe({\n next: () => console.log('left space'),\n error: (err: unknown) =>\n this.errorLogger.logError(\n err,\n `Failed to leave a space: ${space.brief.title}`,\n ),\n });\n }\n\n private watchUserRecord(): void {\n this.userService.userState.pipe(takeUntil(this.destroyed)).subscribe({\n next: (userState) => {\n // console.log('SpacesCardComponent => user state changed:', userState);\n if (userState.status === 'authenticating') {\n if (this.loadingState === 'Authenticating') {\n this.loadingState = 'Loading';\n }\n }\n const uid = userState.user?.uid;\n this.spaces = undefined;\n if (!uid) {\n this.unsubscribe('user signed out');\n return;\n }\n this.subscriptions.push(\n this.userService.userState.subscribe({\n next: this.setUser,\n error: (err) =>\n this.errorLogger.logError(err, 'Failed to get user record'),\n }),\n );\n },\n error: (err) => this.errorLogger.logError(err, 'Failed to get user ID'),\n });\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n private unsubscribe(_reason?: string): void {\n // console.log(`SpacesCardComponent.unsubscribe(reason: ${reason})`);\n this.subscriptions.forEach((s) => s.unsubscribe());\n this.subscriptions = [];\n }\n\n private setUser = (userState: ISneatUserState): void => {\n // console.log('SpacesCardComponent => user:', userState);\n const user = userState.record;\n if (user) {\n this.spaces = Object.entries(user?.spaces ? user.spaces : {}).map(\n ([id, team]) => ({ id, brief: team }),\n );\n this.spaces.sort((a, b) => (a.brief.title > b.brief.title ? 1 : -1));\n this.showAdd = !this.spaces?.length;\n if (this.showAdd) {\n this.startAddingSpace();\n }\n } else {\n this.spaces = undefined;\n }\n };\n}\n","<ion-card>\n <ion-item>\n <ion-label>\n <ion-card-title color=\"medium\">Spaces</ion-card-title>\n </ion-label>\n <ion-buttons slot=\"end\" (click)=\"startAddingSpace()\">\n @if (!showAdd) {\n <ion-button color=\"primary\">\n <ion-icon name=\"add\" slot=\"start\" />\n <ion-label>Add</ion-label>\n </ion-button>\n }\n </ion-buttons>\n </ion-item>\n @if (spaces) {\n <ion-list>\n @for (space of spaces; track space.id) {\n <ion-item-sliding>\n <ion-item tappable detail (click)=\"goSpace(space)\">\n <ion-label>{{ space.brief.title }}</ion-label>\n <ion-buttons slot=\"end\">\n <ion-button color=\"medium\" (click)=\"leaveSpace(space, $event)\">\n <ion-icon name=\"close-outline\" />\n </ion-button>\n </ion-buttons>\n </ion-item>\n <ion-item-options side=\"start\">\n <ion-item-option color=\"danger\" (click)=\"leaveSpace(space)\"\n >Leave team\n </ion-item-option>\n </ion-item-options>\n <ion-item-options side=\"end\">\n <ion-item-option color=\"danger\" (click)=\"leaveSpace(space)\"\n >Leave team\n </ion-item-option>\n </ion-item-options>\n </ion-item-sliding>\n }\n </ion-list>\n } @else {\n <ion-list>\n <ion-item>\n <ion-spinner name=\"\" slot=\"start\" color=\"medium\" />\n <ion-buttons slot=\"start\">\n <ion-button disabled=\"disabled\" style=\"text-transform: none\"\n >{{ loadingState }}...\n </ion-button>\n </ion-buttons>\n <ion-skeleton-text animated />\n </ion-item>\n </ion-list>\n }\n\n @if (showAdd) {\n <ion-item [disabled]=\"adding\">\n <ion-input\n (keyup.enter)=\"addSpace()\"\n #addTeamInput\n [(ngModel)]=\"spaceName\"\n (keyup.escape)=\"showAdd = false\"\n placeholder=\"New team name\"\n />\n <ion-buttons slot=\"end\">\n <ion-button color=\"primary\" fill=\"solid\" (click)=\"addSpace()\">\n <ion-label>Create</ion-label>\n </ion-button>\n @if (!!spaces?.length) {\n <ion-button (click)=\"showAdd = false\" color=\"medium\" title=\"Cancel\">\n @if (adding) {\n <ion-spinner />\n } @else {\n <ion-icon name=\"close-outline\" />\n }\n </ion-button>\n }\n </ion-buttons>\n </ion-item>\n }\n @if (showAdd) {\n <ion-card-content>\n <p>Enter team name and click \"Create\" button to add a new team.</p>\n </ion-card-content>\n }\n</ion-card>\n"]}
@@ -0,0 +1,2 @@
1
+ export * from './spaces-list.component';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../libs/space/components/src/lib/spaces-list/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC","sourcesContent":["export * from './spaces-list.component';\n"]}