@sneat/contactus-internal 0.3.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 (71) hide show
  1. package/esm2022/index.js +2 -0
  2. package/esm2022/index.js.map +1 -0
  3. package/esm2022/lib/contactus-routing.module.js +48 -0
  4. package/esm2022/lib/contactus-routing.module.js.map +1 -0
  5. package/esm2022/lib/index.js +3 -0
  6. package/esm2022/lib/index.js.map +1 -0
  7. package/esm2022/lib/members/index.js +4 -0
  8. package/esm2022/lib/members/index.js.map +1 -0
  9. package/esm2022/lib/members/members-base-page.js +30 -0
  10. package/esm2022/lib/members/members-base-page.js.map +1 -0
  11. package/esm2022/lib/members/members-routing.js +32 -0
  12. package/esm2022/lib/members/members-routing.js.map +1 -0
  13. package/esm2022/lib/members/pages/member/space-member-page.component.js +95 -0
  14. package/esm2022/lib/members/pages/member/space-member-page.component.js.map +1 -0
  15. package/esm2022/lib/members/pages/member-base-page.js +23 -0
  16. package/esm2022/lib/members/pages/member-base-page.js.map +1 -0
  17. package/esm2022/lib/members/pages/members/members-page.component.js +155 -0
  18. package/esm2022/lib/members/pages/members/members-page.component.js.map +1 -0
  19. package/esm2022/lib/members/pages/new-member/index.js +2 -0
  20. package/esm2022/lib/members/pages/new-member/index.js.map +1 -0
  21. package/esm2022/lib/members/pages/new-member/new-member-form.component.js +223 -0
  22. package/esm2022/lib/members/pages/new-member/new-member-form.component.js.map +1 -0
  23. package/esm2022/lib/members/pages/new-member/new-member-page.component.js +132 -0
  24. package/esm2022/lib/members/pages/new-member/new-member-page.component.js.map +1 -0
  25. package/esm2022/lib/pages/contact/contact-page.component.js +96 -0
  26. package/esm2022/lib/pages/contact/contact-page.component.js.map +1 -0
  27. package/esm2022/lib/pages/contact/index.js +2 -0
  28. package/esm2022/lib/pages/contact/index.js.map +1 -0
  29. package/esm2022/lib/pages/contact-base-page.js +59 -0
  30. package/esm2022/lib/pages/contact-base-page.js.map +1 -0
  31. package/esm2022/lib/pages/contacts/contacts-page.component.js +113 -0
  32. package/esm2022/lib/pages/contacts/contacts-page.component.js.map +1 -0
  33. package/esm2022/lib/pages/contacts/index.js +2 -0
  34. package/esm2022/lib/pages/contacts/index.js.map +1 -0
  35. package/esm2022/lib/pages/index.js +5 -0
  36. package/esm2022/lib/pages/index.js.map +1 -0
  37. package/esm2022/lib/pages/new-contact/index.js +2 -0
  38. package/esm2022/lib/pages/new-contact/index.js.map +1 -0
  39. package/esm2022/lib/pages/new-contact/new-contact-page.component.js +104 -0
  40. package/esm2022/lib/pages/new-contact/new-contact-page.component.js.map +1 -0
  41. package/esm2022/lib/pages/new-location/index.js +2 -0
  42. package/esm2022/lib/pages/new-location/index.js.map +1 -0
  43. package/esm2022/lib/pages/new-location/new-location-page.component.js +55 -0
  44. package/esm2022/lib/pages/new-location/new-location-page.component.js.map +1 -0
  45. package/esm2022/sneat-contactus-internal.js +5 -0
  46. package/esm2022/sneat-contactus-internal.js.map +1 -0
  47. package/index.d.ts +1 -0
  48. package/lib/contactus-routing.module.d.ts +2 -0
  49. package/lib/index.d.ts +2 -0
  50. package/lib/members/index.d.ts +2 -0
  51. package/lib/members/members-base-page.d.ts +12 -0
  52. package/lib/members/members-routing.d.ts +2 -0
  53. package/lib/members/pages/member/space-member-page.component.d.ts +11 -0
  54. package/lib/members/pages/member-base-page.d.ts +10 -0
  55. package/lib/members/pages/members/members-page.component.d.ts +18 -0
  56. package/lib/members/pages/new-member/index.d.ts +1 -0
  57. package/lib/members/pages/new-member/new-member-form.component.d.ts +26 -0
  58. package/lib/members/pages/new-member/new-member-page.component.d.ts +17 -0
  59. package/lib/pages/contact/contact-page.component.d.ts +15 -0
  60. package/lib/pages/contact/index.d.ts +1 -0
  61. package/lib/pages/contact-base-page.d.ts +16 -0
  62. package/lib/pages/contacts/contacts-page.component.d.ts +22 -0
  63. package/lib/pages/contacts/index.d.ts +1 -0
  64. package/lib/pages/index.d.ts +4 -0
  65. package/lib/pages/new-contact/index.d.ts +1 -0
  66. package/lib/pages/new-contact/new-contact-page.component.d.ts +24 -0
  67. package/lib/pages/new-location/index.d.ts +1 -0
  68. package/lib/pages/new-location/new-location-page.component.d.ts +12 -0
  69. package/package.json +26 -0
  70. package/sneat-contactus-internal.d.ts +5 -0
  71. package/tsconfig.lib.prod.tsbuildinfo +1 -0
@@ -0,0 +1,223 @@
1
+ import { ChangeDetectionStrategy, Component, computed, inject, signal, ViewChild, } from '@angular/core';
2
+ import { FormsModule, ReactiveFormsModule, UntypedFormGroup, } from '@angular/forms';
3
+ import { IonButton, IonCard, IonCardContent, IonCardHeader, IonCardSubtitle, IonCardTitle, IonCol, IonGrid, IonLabel, IonRow, IonSpinner, NavController, } from '@ionic/angular/standalone';
4
+ import { namesToUrlParams } from '@sneat/auth-models';
5
+ import { MemberService } from '@sneat/contactus-services';
6
+ import { PersonWizardComponent } from '@sneat/contactus-shared';
7
+ import { formNexInAnimation } from '@sneat/core';
8
+ import { personNames } from '@sneat/auth-ui';
9
+ import { RoutingState } from '@sneat/core';
10
+ import { isRelatedPersonReady, } from '@sneat/contactus-core';
11
+ import { zipMapBriefsWithIDs } from '@sneat/space-models';
12
+ import { QRCodeComponent } from 'angularx-qrcode';
13
+ import { WithNewContactInput } from '@sneat/contactus-shared';
14
+ import { ClassName } from '@sneat/ui';
15
+ import * as i0 from "@angular/core";
16
+ import * as i1 from "@angular/forms";
17
+ export class NewMemberFormComponent extends WithNewContactInput {
18
+ constructor() {
19
+ super();
20
+ this.personRequirements = {
21
+ ageGroup: { required: true },
22
+ gender: { required: true },
23
+ };
24
+ this.navController = inject(NavController);
25
+ this.$isSubmitting = signal(false, ...(ngDevMode ? [{ debugName: "$isSubmitting" }] : []));
26
+ this.$canSubmit = computed(() => this.$spaceRef().id &&
27
+ !this.$isSubmitting() &&
28
+ this.$isContactReady() &&
29
+ !this.addMemberForm.disabled && //TODO(check) Could be a problem with Push detection strategy?
30
+ this.addMemberForm.valid, ...(ngDevMode ? [{ debugName: "$canSubmit" }] : []));
31
+ this.$qrData = computed(() => {
32
+ const contact = this.$contact();
33
+ let url = `https://sneat.app/pwa/join?family=${contact.space.id}`;
34
+ const { gender, ageGroup } = contact.dbo;
35
+ if (gender &&
36
+ gender !== 'unknown' &&
37
+ gender !== 'undisclosed' &&
38
+ gender !== 'other') {
39
+ url += '&gender=' + gender;
40
+ }
41
+ if (ageGroup) {
42
+ url += '&ageGroup=' + ageGroup;
43
+ }
44
+ url += namesToUrlParams(contact.dbo.names);
45
+ url += '&utm_source=sneat.app&utm_medium=qr_code&utm_campaign=new_member';
46
+ return url;
47
+ }, ...(ngDevMode ? [{ debugName: "$qrData" }] : []));
48
+ this.$isContactReady = computed(() => {
49
+ const contact = this.$contact();
50
+ return (contact && isRelatedPersonReady(contact.dbo, this.personRequirements));
51
+ }, ...(ngDevMode ? [{ debugName: "$isContactReady" }] : []));
52
+ // @ViewChild('emailInput', { static: false }) emailInput?: IonInput;
53
+ // @ViewChild('genderFirstInput', { static: false }) genderFirstInput?: IonRadio;
54
+ // public get isPersonFormReady(): boolean {
55
+ // return isRelatedPersonNotReady(this.member, this.personRequirements);
56
+ // }
57
+ //
58
+ // public readonly setFocusToInput = createSetFocusToInput(
59
+ // this.params.errorLogger,
60
+ // );
61
+ // public readonly memberType = new FormControl<TeamMemberType>('member', [
62
+ // Validators.required,
63
+ // ]);
64
+ this.addMemberForm = new UntypedFormGroup({
65
+ // email: this.email,
66
+ // phone: this.phone,
67
+ // ageGroup: this.ageGroup,
68
+ // relationship: this.relationship,
69
+ });
70
+ this.memberService = inject(MemberService);
71
+ const routingState = inject(RoutingState);
72
+ this.hasNavHistory = routingState.hasHistory();
73
+ }
74
+ ngOnChanges(changes) {
75
+ if (changes['$space']) {
76
+ this.setPersonRequirements(this.$contact());
77
+ }
78
+ }
79
+ setPersonRequirements(contact) {
80
+ const spaceRef = this.$spaceRef();
81
+ this.personRequirements = {
82
+ // TODO: Should we move it inside person form wizard?
83
+ ...this.personRequirements,
84
+ ageGroup: spaceRef.type === 'family' && contact.dbo.type !== 'animal'
85
+ ? { required: true }
86
+ : { hide: true },
87
+ roles: spaceRef.type === 'family' && contact.dbo.type !== 'animal'
88
+ ? { hide: true }
89
+ : { required: true },
90
+ relatedAs: spaceRef.type === 'family' && contact.dbo.type !== 'animal'
91
+ ? { required: true }
92
+ : { hide: true },
93
+ };
94
+ }
95
+ submit() {
96
+ // if (!this.hasNames) {
97
+ // alert('Please enter first or last or full name of the new member');
98
+ // if (!this.firstName.value && !this.lastName.value) {
99
+ // this.setFocusToInput(this.firstNameInput);
100
+ // } else {
101
+ // this.setFocusToInput(this.fullNameInput);
102
+ // }
103
+ // return;
104
+ // }
105
+ if (!this.personFormComponent) {
106
+ throw '!this.personFormComponent';
107
+ }
108
+ const spaceRef = this.$spaceRef();
109
+ const contact = this.$contact();
110
+ if (!spaceRef?.id) {
111
+ this.errorLogger.logError('not able to add new member without space context');
112
+ return;
113
+ }
114
+ if (!contact) {
115
+ this.errorLogger.logError('member field is undefined');
116
+ return;
117
+ }
118
+ if (this.personRequirements.ageGroup?.required && !contact.dbo.ageGroup) {
119
+ throw new Error('Age group is a required field');
120
+ }
121
+ if (this.personRequirements.gender?.required && !contact.dbo.gender) {
122
+ throw new Error('Gender is a required field');
123
+ }
124
+ const displayName = personNames(contact.dbo.names);
125
+ const duplicateMember = zipMapBriefsWithIDs(this.contactusSpace?.dbo?.contacts)?.find((m) => personNames(m.brief.names) === displayName);
126
+ if (duplicateMember) {
127
+ alert('There is already a member with same name: ' + displayName);
128
+ return;
129
+ }
130
+ const request = {
131
+ ...contact.dbo,
132
+ type: contact.dbo.type,
133
+ status: 'active',
134
+ countryID: '--',
135
+ roles: ['contributor'],
136
+ spaceID: spaceRef.id,
137
+ };
138
+ this.$isSubmitting.set(true);
139
+ this.addMemberForm.disable();
140
+ this.memberService.createMember(request).subscribe({
141
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
142
+ next: (_member) => {
143
+ // console.log('member created:', member);
144
+ if (this.hasNavHistory) {
145
+ this.navController
146
+ .pop()
147
+ .catch(this.errorLogger.logErrorHandler('failed to navigate to prev page'));
148
+ }
149
+ else {
150
+ this.spaceNavService
151
+ .navigateBackToSpacePage(spaceRef, 'members')
152
+ .catch(this.errorLogger.logErrorHandler('failed to navigate back to members page'));
153
+ }
154
+ },
155
+ error: (err) => {
156
+ this.errorLogger.logError(err, 'Failed to create a new member');
157
+ this.addMemberForm.enable();
158
+ setTimeout(() => {
159
+ this.$isSubmitting.set(false);
160
+ }, 1000);
161
+ },
162
+ });
163
+ // this.startCommuneReadwriteTx([MemberKind], (tx, communeDto, userDto) =>
164
+ // this.membersService.addCommuneItem(
165
+ // {
166
+ // ...memberDto,
167
+ // communeId: communeDto.id,
168
+ // },
169
+ // tx,
170
+ // ))
171
+ // .subscribe({
172
+ // next: member => {
173
+ // console.log('New member ID:', member.id);
174
+ // setTimeout(
175
+ // () => {
176
+ // this.navigateRoot(
177
+ // 'member',
178
+ // { id: member.id },
179
+ // { memberDto: member },
180
+ // );
181
+ // },
182
+ // // tslint:disable-next-line:no-magic-numbers
183
+ // 100,
184
+ // );
185
+ // },
186
+ // error: err => {
187
+ // this.errorLogger.logError(err, 'Failed to create new member');
188
+ // },
189
+ // },
190
+ // );
191
+ }
192
+ onContactChanged(contact) {
193
+ // console.log('NewMemberFormComponent.onContactChanged()', contact);
194
+ this.setPersonRequirements(contact);
195
+ this.contactChange.emit(contact);
196
+ }
197
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NewMemberFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
198
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: NewMemberFormComponent, isStandalone: true, selector: "sneat-new-member-form", providers: [{ provide: ClassName, useValue: 'NewMemberFormComponent' }], viewQueries: [{ propertyName: "personFormComponent", first: true, predicate: PersonWizardComponent, descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<form [formGroup]=\"addMemberForm\" (ngSubmit)=\"submit()\">\n <sneat-person-wizard\n [$space]=\"$spaceRef()\"\n [$contact]=\"$contact()\"\n (contactChange)=\"onContactChanged($event)\"\n [displayAgeGroupValue]=\"true\"\n [disabled]=\"$isSubmitting()\"\n [requires]=\"personRequirements\"\n [$fields]=\"{ contactType: { hide: true } }\"\n />\n\n @if (addMemberForm.errors) {\n <ion-card>\n <ion-card-header color=\"danger\">\n <ion-card-title>Errors</ion-card-title>\n </ion-card-header>\n <ion-card-content> Errors: {{ addMemberForm.errors }}</ion-card-content>\n </ion-card>\n }\n\n <ion-card>\n <ion-grid>\n <ion-row>\n <ion-col size=\"5\">\n <!--\t\t\t\t\tpersonRequirements: {{personRequirements|json}}-->\n <!--\t\t\t\t\t$isContactReady: {{$isContactReady()}}-->\n <ion-button\n expand=\"full\"\n size=\"large\"\n (click)=\"submit()\"\n [disabled]=\"!$canSubmit()\"\n >\n @if ($isSubmitting()) {\n <ion-spinner\n name=\"lines-small\"\n slot=\"start\"\n class=\"ion-margin-end\"\n />\n }\n <ion-label>Add member</ion-label>\n </ion-button>\n </ion-col>\n <ion-col size=\"1\" style=\"text-align: center\">\n <p>or</p>\n </ion-col>\n @if (!$isSubmitting()) {\n <ion-col size=\"6\">\n <qrcode\n style=\"float: left\"\n [qrdata]=\"$qrData()\"\n [width]=\"140\"\n errorCorrectionLevel=\"M\"\n />\n <ion-card-header>\n <ion-card-title>Self-add</ion-card-title>\n <ion-card-subtitle>\n Ask the new member to scan this QR code and fill the form to\n join this space. Or send them this\n <a target=\"_blank\" [href]=\"$qrData()\">link</a>.\n </ion-card-subtitle>\n </ion-card-header>\n </ion-col>\n }\n </ion-row>\n </ion-grid>\n </ion-card>\n</form>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: PersonWizardComponent, selector: "sneat-person-wizard", inputs: ["requires", "disabled", "hideRelationship", "hidePetOption", "displayAgeGroupValue", "nameFields", "$fields"], outputs: ["isReadyToSubmitChange"] }, { kind: "component", type: IonCard, selector: "ion-card", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonCardContent, selector: "ion-card-content", inputs: ["mode"] }, { kind: "component", type: IonCardHeader, selector: "ion-card-header", inputs: ["color", "mode", "translucent"] }, { kind: "component", type: IonCardTitle, selector: "ion-card-title", inputs: ["color", "mode"] }, { kind: "component", type: IonCardSubtitle, selector: "ion-card-subtitle", inputs: ["color", "mode"] }, { kind: "component", type: QRCodeComponent, selector: "qrcode", inputs: ["allowEmptyString", "colorDark", "colorLight", "cssClass", "elementType", "errorCorrectionLevel", "imageSrc", "imageHeight", "imageWidth", "margin", "qrdata", "scale", "version", "width", "alt", "ariaLabel", "title"], outputs: ["qrCodeURL"] }, { 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: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonRow, selector: "ion-row" }, { kind: "component", type: IonGrid, selector: "ion-grid", inputs: ["fixed"] }, { kind: "component", type: IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }], animations: [formNexInAnimation], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
199
+ }
200
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NewMemberFormComponent, decorators: [{
201
+ type: Component,
202
+ args: [{ animations: [formNexInAnimation], imports: [
203
+ FormsModule,
204
+ ReactiveFormsModule,
205
+ PersonWizardComponent,
206
+ IonCard,
207
+ IonCardContent,
208
+ IonCardHeader,
209
+ IonCardTitle,
210
+ IonCardSubtitle,
211
+ QRCodeComponent,
212
+ IonButton,
213
+ IonSpinner,
214
+ IonLabel,
215
+ IonRow,
216
+ IonGrid,
217
+ IonCol,
218
+ ], providers: [{ provide: ClassName, useValue: 'NewMemberFormComponent' }], changeDetection: ChangeDetectionStrategy.OnPush, selector: 'sneat-new-member-form', template: "<form [formGroup]=\"addMemberForm\" (ngSubmit)=\"submit()\">\n <sneat-person-wizard\n [$space]=\"$spaceRef()\"\n [$contact]=\"$contact()\"\n (contactChange)=\"onContactChanged($event)\"\n [displayAgeGroupValue]=\"true\"\n [disabled]=\"$isSubmitting()\"\n [requires]=\"personRequirements\"\n [$fields]=\"{ contactType: { hide: true } }\"\n />\n\n @if (addMemberForm.errors) {\n <ion-card>\n <ion-card-header color=\"danger\">\n <ion-card-title>Errors</ion-card-title>\n </ion-card-header>\n <ion-card-content> Errors: {{ addMemberForm.errors }}</ion-card-content>\n </ion-card>\n }\n\n <ion-card>\n <ion-grid>\n <ion-row>\n <ion-col size=\"5\">\n <!--\t\t\t\t\tpersonRequirements: {{personRequirements|json}}-->\n <!--\t\t\t\t\t$isContactReady: {{$isContactReady()}}-->\n <ion-button\n expand=\"full\"\n size=\"large\"\n (click)=\"submit()\"\n [disabled]=\"!$canSubmit()\"\n >\n @if ($isSubmitting()) {\n <ion-spinner\n name=\"lines-small\"\n slot=\"start\"\n class=\"ion-margin-end\"\n />\n }\n <ion-label>Add member</ion-label>\n </ion-button>\n </ion-col>\n <ion-col size=\"1\" style=\"text-align: center\">\n <p>or</p>\n </ion-col>\n @if (!$isSubmitting()) {\n <ion-col size=\"6\">\n <qrcode\n style=\"float: left\"\n [qrdata]=\"$qrData()\"\n [width]=\"140\"\n errorCorrectionLevel=\"M\"\n />\n <ion-card-header>\n <ion-card-title>Self-add</ion-card-title>\n <ion-card-subtitle>\n Ask the new member to scan this QR code and fill the form to\n join this space. Or send them this\n <a target=\"_blank\" [href]=\"$qrData()\">link</a>.\n </ion-card-subtitle>\n </ion-card-header>\n </ion-col>\n }\n </ion-row>\n </ion-grid>\n </ion-card>\n</form>\n" }]
219
+ }], ctorParameters: () => [], propDecorators: { personFormComponent: [{
220
+ type: ViewChild,
221
+ args: [PersonWizardComponent, { static: false }]
222
+ }] } });
223
+ //# sourceMappingURL=new-member-form.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"new-member-form.component.js","sourceRoot":"","sources":["../../../../../../../../../libs/contactus/internal/src/lib/members/pages/new-member/new-member-form.component.ts","../../../../../../../../../libs/contactus/internal/src/lib/members/pages/new-member/new-member-form.component.html"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,SAAS,EACT,QAAQ,EACR,MAAM,EAEN,MAAM,EAEN,SAAS,GACV,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,SAAS,EACT,OAAO,EACP,cAAc,EACd,aAAa,EACb,eAAe,EACf,YAAY,EACZ,MAAM,EACN,OAAO,EACP,QAAQ,EACR,MAAM,EACN,UAAU,EACV,aAAa,GACd,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAIL,oBAAoB,GAGrB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;;;AA0BtC,MAAM,OAAO,sBACX,SAAQ,mBAAmB;IA6E3B;QACE,KAAK,EAAE,CAAC;QA3EH,uBAAkB,GAAwB;YAC/C,QAAQ,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;YAC5B,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;SAC3B,CAAC;QAEe,kBAAa,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC;QAGpC,kBAAa,GAAG,MAAM,CAAC,KAAK,yDAAC,CAAC;QAE9B,eAAU,GAAG,QAAQ,CACtC,GAAG,EAAE,CACH,IAAI,CAAC,SAAS,EAAE,CAAC,EAAE;YACnB,CAAC,IAAI,CAAC,aAAa,EAAE;YACrB,IAAI,CAAC,eAAe,EAAE;YACtB,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,IAAI,8DAA8D;YAC9F,IAAI,CAAC,aAAa,CAAC,KAAK,sDAC3B,CAAC;QAEiB,YAAO,GAAG,QAAQ,CAAC,GAAG,EAAE;YACzC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YAChC,IAAI,GAAG,GAAG,qCAAqC,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;YAClE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC;YACzC,IACE,MAAM;gBACN,MAAM,KAAK,SAAS;gBACpB,MAAM,KAAK,aAAa;gBACxB,MAAM,KAAK,OAAO,EAClB,CAAC;gBACD,GAAG,IAAI,UAAU,GAAG,MAAM,CAAC;YAC7B,CAAC;YACD,IAAI,QAAQ,EAAE,CAAC;gBACb,GAAG,IAAI,YAAY,GAAG,QAAQ,CAAC;YACjC,CAAC;YACD,GAAG,IAAI,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAC3C,GAAG,IAAI,kEAAkE,CAAC;YAC1E,OAAO,GAAG,CAAC;QACb,CAAC,mDAAC,CAAC;QAIgB,oBAAe,GAAG,QAAQ,CAAC,GAAG,EAAE;YACjD,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YAChC,OAAO,CACL,OAAO,IAAI,oBAAoB,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,kBAAkB,CAAC,CACtE,CAAC;QACJ,CAAC,2DAAC,CAAC;QAIH,qEAAqE;QACrE,iFAAiF;QAEjF,4CAA4C;QAC5C,yEAAyE;QACzE,IAAI;QACJ,EAAE;QACF,2DAA2D;QAC3D,4BAA4B;QAC5B,KAAK;QAEL,2EAA2E;QAC3E,wBAAwB;QACxB,MAAM;QAEC,kBAAa,GAAG,IAAI,gBAAgB,CAAC;QAC1C,qBAAqB;QACrB,qBAAqB;QACrB,2BAA2B;QAC3B,mCAAmC;SACpC,CAAC,CAAC;QAEc,kBAAa,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC;QAIrD,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;QAC1C,IAAI,CAAC,aAAa,GAAG,YAAY,CAAC,UAAU,EAAE,CAAC;IACjD,CAAC;IAED,WAAW,CAAC,OAAsB;QAChC,IAAI,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YACtB,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IAEO,qBAAqB,CAAC,OAAqC;QACjE,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAClC,IAAI,CAAC,kBAAkB,GAAG;YACxB,qDAAqD;YACrD,GAAG,IAAI,CAAC,kBAAkB;YAC1B,QAAQ,EACN,QAAQ,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,KAAK,QAAQ;gBACzD,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE;gBACpB,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE;YACpB,KAAK,EACH,QAAQ,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,KAAK,QAAQ;gBACzD,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE;gBAChB,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE;YACxB,SAAS,EACP,QAAQ,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,KAAK,QAAQ;gBACzD,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE;gBACpB,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE;SACrB,CAAC;IACJ,CAAC;IAED,MAAM;QACJ,wBAAwB;QACxB,uEAAuE;QACvE,wDAAwD;QACxD,+CAA+C;QAC/C,YAAY;QACZ,8CAA8C;QAC9C,KAAK;QACL,WAAW;QACX,IAAI;QACJ,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC9B,MAAM,2BAA2B,CAAC;QACpC,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAClC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChC,IAAI,CAAC,QAAQ,EAAE,EAAE,EAAE,CAAC;YAClB,IAAI,CAAC,WAAW,CAAC,QAAQ,CACvB,kDAAkD,CACnD,CAAC;YACF,OAAO;QACT,CAAC;QACD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,2BAA2B,CAAC,CAAC;YACvD,OAAO;QACT,CAAC;QACD,IAAI,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;YACxE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;QACnD,CAAC;QACD,IAAI,IAAI,CAAC,kBAAkB,CAAC,MAAM,EAAE,QAAQ,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;YACpE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChD,CAAC;QACD,MAAM,WAAW,GAAG,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACnD,MAAM,eAAe,GAAG,mBAAmB,CACzC,IAAI,CAAC,cAAc,EAAE,GAAG,EAAE,QAAQ,CACnC,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,WAAW,CAAC,CAAC;QAC3D,IAAI,eAAe,EAAE,CAAC;YACpB,KAAK,CAAC,4CAA4C,GAAG,WAAW,CAAC,CAAC;YAClE,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAA8B;YACzC,GAAG,OAAO,CAAC,GAAG;YACd,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,IAAyB;YAC3C,MAAM,EAAE,QAAQ;YAChB,SAAS,EAAE,IAAI;YACf,KAAK,EAAE,CAAC,aAAa,CAAC;YACtB,OAAO,EAAE,QAAQ,CAAC,EAAE;SACrB,CAAC;QAEF,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC7B,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC;YACjD,6DAA6D;YAC7D,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE;gBAChB,0CAA0C;gBAC1C,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;oBACvB,IAAI,CAAC,aAAa;yBACf,GAAG,EAAE;yBACL,KAAK,CACJ,IAAI,CAAC,WAAW,CAAC,eAAe,CAC9B,iCAAiC,CAClC,CACF,CAAC;gBACN,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,eAAe;yBACjB,uBAAuB,CAAC,QAAQ,EAAE,SAAS,CAAC;yBAC5C,KAAK,CACJ,IAAI,CAAC,WAAW,CAAC,eAAe,CAC9B,yCAAyC,CAC1C,CACF,CAAC;gBACN,CAAC;YACH,CAAC;YACD,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE;gBACb,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,EAAE,+BAA+B,CAAC,CAAC;gBAChE,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC;gBAC5B,UAAU,CAAC,GAAG,EAAE;oBACd,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBAChC,CAAC,EAAE,IAAI,CAAC,CAAC;YACX,CAAC;SACF,CAAC,CAAC;QAEH,0EAA0E;QAC1E,uCAAuC;QACvC,MAAM;QACN,mBAAmB;QACnB,+BAA+B;QAC/B,OAAO;QACP,QAAQ;QACR,MAAM;QACN,gBAAgB;QAChB,uBAAuB;QACvB,gDAAgD;QAChD,kBAAkB;QAClB,eAAe;QACf,2BAA2B;QAC3B,mBAAmB;QACnB,4BAA4B;QAC5B,gCAAgC;QAChC,WAAW;QACX,UAAU;QACV,oDAAoD;QACpD,YAAY;QACZ,SAAS;QACT,QAAQ;QACR,qBAAqB;QACrB,qEAAqE;QACrE,QAAQ;QACR,OAAO;QACP,MAAM;IACR,CAAC;IAED,gBAAgB,CAAC,OAAqC;QACpD,qEAAqE;QACrE,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC;QACpC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;8GAlOU,sBAAsB;kGAAtB,sBAAsB,oEALtB,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,wBAAwB,EAAE,CAAC,+EAyD5D,qBAAqB,4FC5HlC,mnEAmEA,2CDhBI,WAAW,+SACX,mBAAmB,gLACnB,qBAAqB,4NACrB,OAAO,yLACP,cAAc,+EACd,aAAa,sGACb,YAAY,sFACZ,eAAe,yFACf,eAAe,8SACf,SAAS,oPACT,UAAU,yGACV,QAAQ,6FACR,MAAM,oDACN,OAAO,wEACP,MAAM,oSAhBI,CAAC,kBAAkB,CAAC;;2FAuBrB,sBAAsB;kBAxBlC,SAAS;iCACI,CAAC,kBAAkB,CAAC,WACvB;wBACP,WAAW;wBACX,mBAAmB;wBACnB,qBAAqB;wBACrB,OAAO;wBACP,cAAc;wBACd,aAAa;wBACb,YAAY;wBACZ,eAAe;wBACf,eAAe;wBACf,SAAS;wBACT,UAAU;wBACV,QAAQ;wBACR,MAAM;wBACN,OAAO;wBACP,MAAM;qBACP,aACU,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,wBAAwB,EAAE,CAAC,mBACtD,uBAAuB,CAAC,MAAM,YACrC,uBAAuB;;sBAuDhC,SAAS;uBAAC,qBAAqB,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE","sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n inject,\n OnChanges,\n signal,\n SimpleChanges,\n ViewChild,\n} from '@angular/core';\nimport {\n FormsModule,\n ReactiveFormsModule,\n UntypedFormGroup,\n} from '@angular/forms';\nimport {\n IonButton,\n IonCard,\n IonCardContent,\n IonCardHeader,\n IonCardSubtitle,\n IonCardTitle,\n IonCol,\n IonGrid,\n IonLabel,\n IonRow,\n IonSpinner,\n NavController,\n} from '@ionic/angular/standalone';\nimport { namesToUrlParams } from '@sneat/auth-models';\nimport { MemberService } from '@sneat/contactus-services';\nimport { PersonWizardComponent } from '@sneat/contactus-shared';\nimport { formNexInAnimation } from '@sneat/core';\nimport { personNames } from '@sneat/auth-ui';\nimport { RoutingState } from '@sneat/core';\nimport {\n IContactusSpaceDboAndID,\n ICreateSpaceMemberRequest,\n IPersonRequirements,\n isRelatedPersonReady,\n MemberContactType,\n NewContactBaseDboAndSpaceRef,\n} from '@sneat/contactus-core';\nimport { zipMapBriefsWithIDs } from '@sneat/space-models';\nimport { QRCodeComponent } from 'angularx-qrcode';\nimport { WithNewContactInput } from '@sneat/contactus-shared';\nimport { ClassName } from '@sneat/ui';\n\n@Component({\n animations: [formNexInAnimation],\n imports: [\n FormsModule,\n ReactiveFormsModule,\n PersonWizardComponent,\n IonCard,\n IonCardContent,\n IonCardHeader,\n IonCardTitle,\n IonCardSubtitle,\n QRCodeComponent,\n IonButton,\n IonSpinner,\n IonLabel,\n IonRow,\n IonGrid,\n IonCol,\n ],\n providers: [{ provide: ClassName, useValue: 'NewMemberFormComponent' }],\n changeDetection: ChangeDetectionStrategy.OnPush,\n selector: 'sneat-new-member-form',\n templateUrl: 'new-member-form.component.html',\n})\nexport class NewMemberFormComponent\n extends WithNewContactInput\n implements OnChanges\n{\n public personRequirements: IPersonRequirements = {\n ageGroup: { required: true },\n gender: { required: true },\n };\n\n private readonly navController = inject(NavController);\n\n private readonly hasNavHistory: boolean;\n protected readonly $isSubmitting = signal(false);\n\n protected readonly $canSubmit = computed(\n () =>\n this.$spaceRef().id &&\n !this.$isSubmitting() &&\n this.$isContactReady() &&\n !this.addMemberForm.disabled && //TODO(check) Could be a problem with Push detection strategy?\n this.addMemberForm.valid,\n );\n\n protected readonly $qrData = computed(() => {\n const contact = this.$contact();\n let url = `https://sneat.app/pwa/join?family=${contact.space.id}`;\n const { gender, ageGroup } = contact.dbo;\n if (\n gender &&\n gender !== 'unknown' &&\n gender !== 'undisclosed' &&\n gender !== 'other'\n ) {\n url += '&gender=' + gender;\n }\n if (ageGroup) {\n url += '&ageGroup=' + ageGroup;\n }\n url += namesToUrlParams(contact.dbo.names);\n url += '&utm_source=sneat.app&utm_medium=qr_code&utm_campaign=new_member';\n return url;\n });\n\n protected contactusSpace?: IContactusSpaceDboAndID;\n\n protected readonly $isContactReady = computed(() => {\n const contact = this.$contact();\n return (\n contact && isRelatedPersonReady(contact.dbo, this.personRequirements)\n );\n });\n\n @ViewChild(PersonWizardComponent, { static: false })\n personFormComponent?: PersonWizardComponent;\n // @ViewChild('emailInput', { static: false }) emailInput?: IonInput;\n // @ViewChild('genderFirstInput', { static: false }) genderFirstInput?: IonRadio;\n\n // public get isPersonFormReady(): boolean {\n // \treturn isRelatedPersonNotReady(this.member, this.personRequirements);\n // }\n //\n // public readonly setFocusToInput = createSetFocusToInput(\n // \tthis.params.errorLogger,\n // );\n\n // public readonly memberType = new FormControl<TeamMemberType>('member', [\n // \tValidators.required,\n // ]);\n\n public addMemberForm = new UntypedFormGroup({\n // email: this.email,\n // phone: this.phone,\n // ageGroup: this.ageGroup,\n // relationship: this.relationship,\n });\n\n private readonly memberService = inject(MemberService);\n\n public constructor() {\n super();\n const routingState = inject(RoutingState);\n this.hasNavHistory = routingState.hasHistory();\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['$space']) {\n this.setPersonRequirements(this.$contact());\n }\n }\n\n private setPersonRequirements(contact: NewContactBaseDboAndSpaceRef): void {\n const spaceRef = this.$spaceRef();\n this.personRequirements = {\n // TODO: Should we move it inside person form wizard?\n ...this.personRequirements,\n ageGroup:\n spaceRef.type === 'family' && contact.dbo.type !== 'animal'\n ? { required: true }\n : { hide: true },\n roles:\n spaceRef.type === 'family' && contact.dbo.type !== 'animal'\n ? { hide: true }\n : { required: true },\n relatedAs:\n spaceRef.type === 'family' && contact.dbo.type !== 'animal'\n ? { required: true }\n : { hide: true },\n };\n }\n\n submit(): void {\n // if (!this.hasNames) {\n // \talert('Please enter first or last or full name of the new member');\n // \tif (!this.firstName.value && !this.lastName.value) {\n // \t\tthis.setFocusToInput(this.firstNameInput);\n // \t} else {\n // \t\tthis.setFocusToInput(this.fullNameInput);\n // \t}\n // \treturn;\n // }\n if (!this.personFormComponent) {\n throw '!this.personFormComponent';\n }\n const spaceRef = this.$spaceRef();\n const contact = this.$contact();\n if (!spaceRef?.id) {\n this.errorLogger.logError(\n 'not able to add new member without space context',\n );\n return;\n }\n if (!contact) {\n this.errorLogger.logError('member field is undefined');\n return;\n }\n if (this.personRequirements.ageGroup?.required && !contact.dbo.ageGroup) {\n throw new Error('Age group is a required field');\n }\n if (this.personRequirements.gender?.required && !contact.dbo.gender) {\n throw new Error('Gender is a required field');\n }\n const displayName = personNames(contact.dbo.names);\n const duplicateMember = zipMapBriefsWithIDs(\n this.contactusSpace?.dbo?.contacts,\n )?.find((m) => personNames(m.brief.names) === displayName);\n if (duplicateMember) {\n alert('There is already a member with same name: ' + displayName);\n return;\n }\n\n const request: ICreateSpaceMemberRequest = {\n ...contact.dbo,\n type: contact.dbo.type as MemberContactType,\n status: 'active',\n countryID: '--',\n roles: ['contributor'],\n spaceID: spaceRef.id,\n };\n\n this.$isSubmitting.set(true);\n this.addMemberForm.disable();\n this.memberService.createMember(request).subscribe({\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n next: (_member) => {\n // console.log('member created:', member);\n if (this.hasNavHistory) {\n this.navController\n .pop()\n .catch(\n this.errorLogger.logErrorHandler(\n 'failed to navigate to prev page',\n ),\n );\n } else {\n this.spaceNavService\n .navigateBackToSpacePage(spaceRef, 'members')\n .catch(\n this.errorLogger.logErrorHandler(\n 'failed to navigate back to members page',\n ),\n );\n }\n },\n error: (err) => {\n this.errorLogger.logError(err, 'Failed to create a new member');\n this.addMemberForm.enable();\n setTimeout(() => {\n this.$isSubmitting.set(false);\n }, 1000);\n },\n });\n\n // this.startCommuneReadwriteTx([MemberKind], (tx, communeDto, userDto) =>\n // \tthis.membersService.addCommuneItem(\n // \t\t{\n // \t\t\t...memberDto,\n // \t\t\tcommuneId: communeDto.id,\n // \t\t},\n // \t\ttx,\n // \t))\n // \t.subscribe({\n // \t\t\tnext: member => {\n // \t\t\t\tconsole.log('New member ID:', member.id);\n // \t\t\t\tsetTimeout(\n // \t\t\t\t\t() => {\n // \t\t\t\t\t\tthis.navigateRoot(\n // \t\t\t\t\t\t\t'member',\n // \t\t\t\t\t\t\t{ id: member.id },\n // \t\t\t\t\t\t\t{ memberDto: member },\n // \t\t\t\t\t\t);\n // \t\t\t\t\t},\n // \t\t\t\t\t// tslint:disable-next-line:no-magic-numbers\n // \t\t\t\t\t100,\n // \t\t\t\t);\n // \t\t\t},\n // \t\t\terror: err => {\n // \t\t\t\tthis.errorLogger.logError(err, 'Failed to create new member');\n // \t\t\t},\n // \t\t},\n // \t);\n }\n\n onContactChanged(contact: NewContactBaseDboAndSpaceRef): void {\n // console.log('NewMemberFormComponent.onContactChanged()', contact);\n this.setPersonRequirements(contact);\n this.contactChange.emit(contact);\n }\n}\n","<form [formGroup]=\"addMemberForm\" (ngSubmit)=\"submit()\">\n <sneat-person-wizard\n [$space]=\"$spaceRef()\"\n [$contact]=\"$contact()\"\n (contactChange)=\"onContactChanged($event)\"\n [displayAgeGroupValue]=\"true\"\n [disabled]=\"$isSubmitting()\"\n [requires]=\"personRequirements\"\n [$fields]=\"{ contactType: { hide: true } }\"\n />\n\n @if (addMemberForm.errors) {\n <ion-card>\n <ion-card-header color=\"danger\">\n <ion-card-title>Errors</ion-card-title>\n </ion-card-header>\n <ion-card-content> Errors: {{ addMemberForm.errors }}</ion-card-content>\n </ion-card>\n }\n\n <ion-card>\n <ion-grid>\n <ion-row>\n <ion-col size=\"5\">\n <!--\t\t\t\t\tpersonRequirements: {{personRequirements|json}}-->\n <!--\t\t\t\t\t$isContactReady: {{$isContactReady()}}-->\n <ion-button\n expand=\"full\"\n size=\"large\"\n (click)=\"submit()\"\n [disabled]=\"!$canSubmit()\"\n >\n @if ($isSubmitting()) {\n <ion-spinner\n name=\"lines-small\"\n slot=\"start\"\n class=\"ion-margin-end\"\n />\n }\n <ion-label>Add member</ion-label>\n </ion-button>\n </ion-col>\n <ion-col size=\"1\" style=\"text-align: center\">\n <p>or</p>\n </ion-col>\n @if (!$isSubmitting()) {\n <ion-col size=\"6\">\n <qrcode\n style=\"float: left\"\n [qrdata]=\"$qrData()\"\n [width]=\"140\"\n errorCorrectionLevel=\"M\"\n />\n <ion-card-header>\n <ion-card-title>Self-add</ion-card-title>\n <ion-card-subtitle>\n Ask the new member to scan this QR code and fill the form to\n join this space. Or send them this\n <a target=\"_blank\" [href]=\"$qrData()\">link</a>.\n </ion-card-subtitle>\n </ion-card-header>\n </ion-col>\n }\n </ion-row>\n </ion-grid>\n </ion-card>\n</form>\n"]}
@@ -0,0 +1,132 @@
1
+ import { Component, computed, effect, signal } from '@angular/core';
2
+ import { IonBackButton, IonButtons, IonCard, IonCardContent, IonContent, IonHeader, IonSegment, IonSegmentButton, IonTitle, IonToolbar, } from '@ionic/angular/standalone';
3
+ import { ContactusServicesModule, ContactusSpaceContextService, } from '@sneat/contactus-services';
4
+ import { InviteLinksComponent, NewPetFormComponent, } from '@sneat/contactus-shared';
5
+ import { RoleSpaceMember, } from '@sneat/contactus-core';
6
+ import { SpacePageBaseComponent } from '@sneat/space-components';
7
+ import { SpaceServiceModule } from '@sneat/space-services';
8
+ import { filter, first, takeUntil } from 'rxjs';
9
+ import { NewMemberFormComponent } from './new-member-form.component';
10
+ import { ClassName } from '@sneat/ui';
11
+ import * as i0 from "@angular/core";
12
+ export class NewMemberPageComponent extends SpacePageBaseComponent {
13
+ // @ViewChild('nameInput', { static: false }) nameInput?: IonInput;
14
+ onContactTypeChanged(event) {
15
+ this.$contact.update((contact) => ({
16
+ ...contact,
17
+ dbo: {
18
+ ...contact.dbo,
19
+ type: event.detail.value,
20
+ },
21
+ }));
22
+ }
23
+ constructor() {
24
+ super();
25
+ this.$inviteType = signal('mass', ...(ngDevMode ? [{ debugName: "$inviteType" }] : []));
26
+ this.$contact = signal({
27
+ space: { id: '' },
28
+ dbo: {
29
+ type: 'person',
30
+ gender: 'unknown', // Undefined would indicate "loading" and gender form would be disabled.
31
+ roles: [RoleSpaceMember],
32
+ },
33
+ }, ...(ngDevMode ? [{ debugName: "$contact" }] : []));
34
+ this.$contactType = computed(() => this.$contact().dbo?.type, ...(ngDevMode ? [{ debugName: "$contactType" }] : []));
35
+ this.trackFirstSpaceTypeChanged = () => {
36
+ try {
37
+ this.spaceTypeChanged$
38
+ .pipe(takeUntil(this.destroyed$), filter((v) => !!v), first())
39
+ .subscribe({
40
+ next: (spaceType) => {
41
+ console.log('NewMemberPageComponent: spaceTypeChanged$ =>', spaceType);
42
+ if (spaceType === 'family' && this.$inviteType() === 'mass') {
43
+ this.$inviteType.set('personal');
44
+ }
45
+ },
46
+ error: this.logErrorHandler('failed to process space type changes'),
47
+ });
48
+ }
49
+ catch (e) {
50
+ this.logError(e, 'failed to subscribe for first space type change');
51
+ }
52
+ };
53
+ this.$defaultBackUrlSpacePath.set('members');
54
+ const contactusSpaceContextService = new ContactusSpaceContextService(this.destroyed$, this.spaceIDChanged$);
55
+ effect(() => {
56
+ const space = this.$spaceRef();
57
+ this.$contact.update((contact) => ({
58
+ ...contact,
59
+ space: space || { id: '' },
60
+ }));
61
+ });
62
+ this.trackFirstSpaceTypeChanged();
63
+ this.route.queryParams.subscribe((params) => {
64
+ const group = params['group'];
65
+ const setContactTypeAndAgeGroup = (contact, contactType, ageGroup) => ({
66
+ ...contact,
67
+ dbo: {
68
+ ...contact.dbo,
69
+ type: contactType,
70
+ ageGroup,
71
+ },
72
+ });
73
+ switch (group) {
74
+ case 'adults':
75
+ this.$contact.update((contact) => setContactTypeAndAgeGroup(contact, 'person', 'adult'));
76
+ break;
77
+ case 'kids':
78
+ this.$contact.update((contact) => setContactTypeAndAgeGroup(contact, 'person', 'child'));
79
+ break;
80
+ case 'pets':
81
+ this.$contact.update((contact) => setContactTypeAndAgeGroup(contact, 'animal'));
82
+ break;
83
+ default:
84
+ this.$contact.update((contact) => setContactTypeAndAgeGroup(contact, 'person'));
85
+ break;
86
+ }
87
+ const roles = params['roles'] || '';
88
+ if (roles) {
89
+ this.$contact.update((contact) => ({
90
+ ...contact,
91
+ dbo: {
92
+ ...contact.dbo,
93
+ roles: roles.split(',').map((s) => s.trim()),
94
+ },
95
+ }));
96
+ }
97
+ });
98
+ contactusSpaceContextService.contactusSpaceContext$
99
+ .pipe(this.takeUntilDestroyed())
100
+ .subscribe({
101
+ next: (contactusTeam) => {
102
+ this.contactusSpace = contactusTeam;
103
+ },
104
+ });
105
+ }
106
+ onTabChanged(event) {
107
+ this.$inviteType.set(event.detail.value);
108
+ }
109
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NewMemberPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
110
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: NewMemberPageComponent, isStandalone: true, selector: "sneat-new-member-page", providers: [{ provide: ClassName, useValue: 'NewMemberPageComponent' }], usesInheritance: true, ngImport: i0, template: "<ion-header>\n <ion-toolbar color=\"light\" class=\"with-back-button\">\n <ion-buttons slot=\"start\">\n <ion-back-button [defaultHref]=\"$defaultBackUrl()\" />\n </ion-buttons>\n <ion-title>\n @if (space.brief || space.type) {\n @if ($contact().dbo.type === \"animal\") {\n New pet\n } @else {\n @switch ($contact().dbo.ageGroup) {\n @case (\"child\") {\n New child\n }\n @case (\"adult\") {\n New adult\n }\n @default {\n New member\n }\n }\n }\n &#64; {{ $space().brief?.title || space.type }}\n } @else {\n New member\n }\n </ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-segment\n [value]=\"$contactType()\"\n (ionChange)=\"onContactTypeChanged($event)\"\n>\n <ion-segment-button value=\"person\">Person</ion-segment-button>\n <ion-segment-button value=\"animal\">Pet</ion-segment-button>\n</ion-segment>\n\n<ion-content class=\"cardy\">\n @switch ($contactType()) {\n @case (\"person\") {\n @if (space.id && space.type !== \"family\") {\n <ion-segment [value]=\"$inviteType()\" (ionChange)=\"onTabChanged($event)\">\n <ion-segment-button value=\"mass\">\n Mass invite [{{ space.id }} - {{ space.type }}]\n </ion-segment-button>\n <ion-segment-button value=\"personal\"\n >Personal invite</ion-segment-button\n >\n </ion-segment>\n }\n\n @switch ($inviteType()) {\n @case (\"personal\") {\n <sneat-new-member-form\n [$space]=\"$space()\"\n [$contact]=\"$contact()\"\n (contactChange)=\"$contact.set($event)\"\n />\n }\n @case (\"mass\") {\n <ion-card>\n <ion-card-content>\n <sneat-invite-links [contactusSpace]=\"contactusSpace\" />\n\n <p>\n <b>Or</b> you can send\n <a\n href=\"\"\n (click)=\"$inviteType.set('personal'); $event.preventDefault()\"\n >personal invite</a\n >\n by email.\n </p>\n </ion-card-content>\n </ion-card>\n }\n }\n }\n @case (\"animal\") {\n <sneat-new-pet-form\n [$space]=\"$space()\"\n [$contact]=\"$contact()\"\n (contactChange)=\"$contact.set($event)\"\n />\n }\n }\n</ion-content>\n", dependencies: [{ kind: "ngmodule", type: ContactusServicesModule }, { kind: "component", type: NewMemberFormComponent, selector: "sneat-new-member-form" }, { kind: "component", type: InviteLinksComponent, selector: "sneat-invite-links", inputs: ["contactusSpace"] }, { kind: "ngmodule", type: SpaceServiceModule }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonSegment, selector: "ion-segment", inputs: ["color", "disabled", "mode", "scrollable", "selectOnFocus", "swipeGesture", "value"] }, { kind: "component", type: IonSegmentButton, selector: "ion-segment-button", inputs: ["contentId", "disabled", "layout", "mode", "type", "value"] }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonBackButton, selector: "ion-back-button" }, { kind: "component", type: IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: IonCard, selector: "ion-card", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonCardContent, selector: "ion-card-content", inputs: ["mode"] }, { kind: "component", type: NewPetFormComponent, selector: "sneat-new-pet-form" }] }); }
111
+ }
112
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NewMemberPageComponent, decorators: [{
113
+ type: Component,
114
+ args: [{ imports: [
115
+ ContactusServicesModule,
116
+ NewMemberFormComponent,
117
+ InviteLinksComponent,
118
+ SpaceServiceModule,
119
+ IonContent,
120
+ IonSegment,
121
+ IonSegmentButton,
122
+ IonHeader,
123
+ IonToolbar,
124
+ IonButtons,
125
+ IonBackButton,
126
+ IonTitle,
127
+ IonCard,
128
+ IonCardContent,
129
+ NewPetFormComponent,
130
+ ], providers: [{ provide: ClassName, useValue: 'NewMemberPageComponent' }], selector: 'sneat-new-member-page', template: "<ion-header>\n <ion-toolbar color=\"light\" class=\"with-back-button\">\n <ion-buttons slot=\"start\">\n <ion-back-button [defaultHref]=\"$defaultBackUrl()\" />\n </ion-buttons>\n <ion-title>\n @if (space.brief || space.type) {\n @if ($contact().dbo.type === \"animal\") {\n New pet\n } @else {\n @switch ($contact().dbo.ageGroup) {\n @case (\"child\") {\n New child\n }\n @case (\"adult\") {\n New adult\n }\n @default {\n New member\n }\n }\n }\n &#64; {{ $space().brief?.title || space.type }}\n } @else {\n New member\n }\n </ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-segment\n [value]=\"$contactType()\"\n (ionChange)=\"onContactTypeChanged($event)\"\n>\n <ion-segment-button value=\"person\">Person</ion-segment-button>\n <ion-segment-button value=\"animal\">Pet</ion-segment-button>\n</ion-segment>\n\n<ion-content class=\"cardy\">\n @switch ($contactType()) {\n @case (\"person\") {\n @if (space.id && space.type !== \"family\") {\n <ion-segment [value]=\"$inviteType()\" (ionChange)=\"onTabChanged($event)\">\n <ion-segment-button value=\"mass\">\n Mass invite [{{ space.id }} - {{ space.type }}]\n </ion-segment-button>\n <ion-segment-button value=\"personal\"\n >Personal invite</ion-segment-button\n >\n </ion-segment>\n }\n\n @switch ($inviteType()) {\n @case (\"personal\") {\n <sneat-new-member-form\n [$space]=\"$space()\"\n [$contact]=\"$contact()\"\n (contactChange)=\"$contact.set($event)\"\n />\n }\n @case (\"mass\") {\n <ion-card>\n <ion-card-content>\n <sneat-invite-links [contactusSpace]=\"contactusSpace\" />\n\n <p>\n <b>Or</b> you can send\n <a\n href=\"\"\n (click)=\"$inviteType.set('personal'); $event.preventDefault()\"\n >personal invite</a\n >\n by email.\n </p>\n </ion-card-content>\n </ion-card>\n }\n }\n }\n @case (\"animal\") {\n <sneat-new-pet-form\n [$space]=\"$space()\"\n [$contact]=\"$contact()\"\n (contactChange)=\"$contact.set($event)\"\n />\n }\n }\n</ion-content>\n" }]
131
+ }], ctorParameters: () => [] });
132
+ //# sourceMappingURL=new-member-page.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"new-member-page.component.js","sourceRoot":"","sources":["../../../../../../../../../libs/contactus/internal/src/lib/members/pages/new-member/new-member-page.component.ts","../../../../../../../../../libs/contactus/internal/src/lib/members/pages/new-member/new-member-page.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, computed, effect, signal } from '@angular/core';\nimport {\n IonBackButton,\n IonButtons,\n IonCard,\n IonCardContent,\n IonContent,\n IonHeader,\n IonSegment,\n IonSegmentButton,\n IonTitle,\n IonToolbar,\n} from '@ionic/angular/standalone';\nimport {\n ContactusServicesModule,\n ContactusSpaceContextService,\n} from '@sneat/contactus-services';\nimport {\n InviteLinksComponent,\n NewPetFormComponent,\n} from '@sneat/contactus-shared';\nimport {\n ContactType,\n IContactusSpaceDboAndID,\n NewContactBaseDboAndSpaceRef,\n RoleSpaceMember,\n} from '@sneat/contactus-core';\nimport { AgeGroupID } from '@sneat/core';\nimport { SpacePageBaseComponent } from '@sneat/space-components';\nimport { SpaceServiceModule } from '@sneat/space-services';\nimport { filter, first, takeUntil } from 'rxjs';\nimport { NewMemberFormComponent } from './new-member-form.component';\nimport { ClassName } from '@sneat/ui';\n\ntype InviteType = 'personal' | 'mass';\n\n@Component({\n imports: [\n ContactusServicesModule,\n NewMemberFormComponent,\n InviteLinksComponent,\n SpaceServiceModule,\n IonContent,\n IonSegment,\n IonSegmentButton,\n IonHeader,\n IonToolbar,\n IonButtons,\n IonBackButton,\n IonTitle,\n IonCard,\n IonCardContent,\n NewPetFormComponent,\n ],\n providers: [{ provide: ClassName, useValue: 'NewMemberPageComponent' }],\n selector: 'sneat-new-member-page',\n templateUrl: './new-member-page.component.html',\n})\nexport class NewMemberPageComponent extends SpacePageBaseComponent {\n // @ViewChild('nameInput', { static: false }) nameInput?: IonInput;\n\n protected onContactTypeChanged(event: CustomEvent): void {\n this.$contact.update((contact) => ({\n ...contact,\n dbo: {\n ...contact.dbo,\n type: event.detail.value as ContactType,\n },\n }));\n }\n\n protected readonly $inviteType = signal<InviteType>('mass');\n\n protected readonly $contact = signal<NewContactBaseDboAndSpaceRef>({\n space: { id: '' },\n dbo: {\n type: 'person',\n gender: 'unknown', // Undefined would indicate \"loading\" and gender form would be disabled.\n roles: [RoleSpaceMember],\n },\n });\n\n protected readonly $contactType = computed(() => this.$contact().dbo?.type);\n\n public constructor() {\n super();\n this.$defaultBackUrlSpacePath.set('members');\n const contactusSpaceContextService = new ContactusSpaceContextService(\n this.destroyed$,\n this.spaceIDChanged$,\n );\n effect(() => {\n const space = this.$spaceRef();\n this.$contact.update((contact) => ({\n ...contact,\n space: space || { id: '' },\n }));\n });\n this.trackFirstSpaceTypeChanged();\n this.route.queryParams.subscribe((params) => {\n const group = params['group'];\n const setContactTypeAndAgeGroup = (\n contact: NewContactBaseDboAndSpaceRef,\n contactType: ContactType,\n ageGroup?: AgeGroupID,\n ) => ({\n ...contact,\n dbo: {\n ...contact.dbo,\n type: contactType,\n ageGroup,\n },\n });\n switch (group) {\n case 'adults':\n this.$contact.update((contact) =>\n setContactTypeAndAgeGroup(contact, 'person', 'adult'),\n );\n break;\n case 'kids':\n this.$contact.update((contact) =>\n setContactTypeAndAgeGroup(contact, 'person', 'child'),\n );\n break;\n case 'pets':\n this.$contact.update((contact) =>\n setContactTypeAndAgeGroup(contact, 'animal'),\n );\n break;\n default:\n this.$contact.update((contact) =>\n setContactTypeAndAgeGroup(contact, 'person'),\n );\n break;\n }\n const roles = params['roles'] || '';\n if (roles) {\n this.$contact.update((contact) => ({\n ...contact,\n dbo: {\n ...contact.dbo,\n roles: roles.split(',').map((s: string) => s.trim()),\n },\n }));\n }\n });\n\n contactusSpaceContextService.contactusSpaceContext$\n .pipe(this.takeUntilDestroyed())\n .subscribe({\n next: (contactusTeam) => {\n this.contactusSpace = contactusTeam;\n },\n });\n }\n\n protected contactusSpace?: IContactusSpaceDboAndID;\n\n private readonly trackFirstSpaceTypeChanged = (): void => {\n try {\n this.spaceTypeChanged$\n .pipe(\n takeUntil(this.destroyed$),\n filter((v) => !!v),\n first(),\n )\n .subscribe({\n next: (spaceType) => {\n console.log(\n 'NewMemberPageComponent: spaceTypeChanged$ =>',\n spaceType,\n );\n if (spaceType === 'family' && this.$inviteType() === 'mass') {\n this.$inviteType.set('personal');\n }\n },\n error: this.logErrorHandler('failed to process space type changes'),\n });\n } catch (e) {\n this.logError(e, 'failed to subscribe for first space type change');\n }\n };\n\n protected onTabChanged(event: CustomEvent): void {\n this.$inviteType.set(event.detail.value as InviteType);\n }\n}\n","<ion-header>\n <ion-toolbar color=\"light\" class=\"with-back-button\">\n <ion-buttons slot=\"start\">\n <ion-back-button [defaultHref]=\"$defaultBackUrl()\" />\n </ion-buttons>\n <ion-title>\n @if (space.brief || space.type) {\n @if ($contact().dbo.type === \"animal\") {\n New pet\n } @else {\n @switch ($contact().dbo.ageGroup) {\n @case (\"child\") {\n New child\n }\n @case (\"adult\") {\n New adult\n }\n @default {\n New member\n }\n }\n }\n &#64; {{ $space().brief?.title || space.type }}\n } @else {\n New member\n }\n </ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-segment\n [value]=\"$contactType()\"\n (ionChange)=\"onContactTypeChanged($event)\"\n>\n <ion-segment-button value=\"person\">Person</ion-segment-button>\n <ion-segment-button value=\"animal\">Pet</ion-segment-button>\n</ion-segment>\n\n<ion-content class=\"cardy\">\n @switch ($contactType()) {\n @case (\"person\") {\n @if (space.id && space.type !== \"family\") {\n <ion-segment [value]=\"$inviteType()\" (ionChange)=\"onTabChanged($event)\">\n <ion-segment-button value=\"mass\">\n Mass invite [{{ space.id }} - {{ space.type }}]\n </ion-segment-button>\n <ion-segment-button value=\"personal\"\n >Personal invite</ion-segment-button\n >\n </ion-segment>\n }\n\n @switch ($inviteType()) {\n @case (\"personal\") {\n <sneat-new-member-form\n [$space]=\"$space()\"\n [$contact]=\"$contact()\"\n (contactChange)=\"$contact.set($event)\"\n />\n }\n @case (\"mass\") {\n <ion-card>\n <ion-card-content>\n <sneat-invite-links [contactusSpace]=\"contactusSpace\" />\n\n <p>\n <b>Or</b> you can send\n <a\n href=\"\"\n (click)=\"$inviteType.set('personal'); $event.preventDefault()\"\n >personal invite</a\n >\n by email.\n </p>\n </ion-card-content>\n </ion-card>\n }\n }\n }\n @case (\"animal\") {\n <sneat-new-pet-form\n [$space]=\"$space()\"\n [$contact]=\"$contact()\"\n (contactChange)=\"$contact.set($event)\"\n />\n }\n }\n</ion-content>\n"]}
@@ -0,0 +1,96 @@
1
+ import { Component, inject } from '@angular/core';
2
+ import { IonBackButton, IonButton, IonButtons, IonContent, IonHeader, IonIcon, IonMenuButton, IonTitle, IonToolbar, } from '@ionic/angular/standalone';
3
+ import { ContactDetailsComponent, PersonTitle } from '@sneat/contactus-shared';
4
+ import { SneatNavService } from '@sneat/core';
5
+ import { ContactService, ContactusServicesModule, } from '@sneat/contactus-services';
6
+ import { SpaceServiceModule } from '@sneat/space-services';
7
+ import { ClassName } from '@sneat/ui';
8
+ import { ContactBasePage } from '../contact-base-page';
9
+ import * as i0 from "@angular/core";
10
+ export class ContactPageComponent extends ContactBasePage {
11
+ constructor() {
12
+ super(inject(ContactService));
13
+ this.contactsService = inject(ContactService);
14
+ this.sneatNavService = inject(SneatNavService);
15
+ this.segment = 'contact';
16
+ this.defaultBackPage = 'contacts';
17
+ }
18
+ // TODO: use or remove
19
+ watchChildContacts() {
20
+ const contactID = this.$contactID();
21
+ if (!contactID) {
22
+ return;
23
+ }
24
+ const space = this.space;
25
+ if (!space) {
26
+ return;
27
+ }
28
+ this.contactsService
29
+ .watchChildContacts(space, contactID)
30
+ .pipe(this.takeUntilDestroyed())
31
+ .subscribe({
32
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
33
+ next: (_children) => {
34
+ // Handle children if needed
35
+ },
36
+ error: this.errorLogger.logErrorHandler('failed to get child contacts'),
37
+ });
38
+ }
39
+ // TODO: use or remove
40
+ saveAddress(save) {
41
+ const spaceID = this.space?.id, contactID = this.$contactID(), address = save.object;
42
+ if (!spaceID || !contactID || !address) {
43
+ save.error('Can not save address without team and contact context');
44
+ return;
45
+ }
46
+ const request = {
47
+ spaceID,
48
+ contactID,
49
+ address,
50
+ };
51
+ this.contactService.updateContact(request).subscribe({
52
+ next: () => save.success(),
53
+ error: save.error,
54
+ });
55
+ }
56
+ deleteContact() {
57
+ const contact = this.$contact();
58
+ if (!contact) {
59
+ return;
60
+ }
61
+ if (!confirm(`Are you sure you want to delete contact "${contact.brief?.title}"?`)) {
62
+ return;
63
+ }
64
+ const request = {
65
+ spaceID: this.space.id,
66
+ contactID: contact.id,
67
+ };
68
+ this.contactsService.deleteContact(request).subscribe({
69
+ next: () => {
70
+ this.sneatNavService.goBack(`/space/${this.space?.id}/contacts`);
71
+ },
72
+ error: this.errorLogger.logErrorHandler('failed to delete contact'),
73
+ });
74
+ }
75
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ContactPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
76
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: ContactPageComponent, isStandalone: true, selector: "sneat-contact-page", providers: [{ provide: ClassName, useValue: 'ContactPageComponent' }], usesInheritance: true, ngImport: i0, template: "<ion-header>\n <ion-toolbar color=\"light\">\n <ion-buttons slot=\"start\">\n <ion-back-button [defaultHref]=\"$defaultBackUrl()\" />\n </ion-buttons>\n <ion-title>\n @if ($contact(); as contact) {\n {{ contact | personTitle }}\n } @else {\n Contact\n }\n </ion-title>\n <ion-buttons slot=\"end\">\n <ion-button\n title=\"Delete contact\"\n color=\"medium\"\n (click)=\"deleteContact()\"\n >\n <ion-icon name=\"trash\" slot=\"start\" />\n </ion-button>\n <ion-menu-button />\n </ion-buttons>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n <sneat-contact-details [$contact]=\"$contact()\" [$space]=\"$space()\" />\n</ion-content>\n", dependencies: [{ kind: "component", type: ContactDetailsComponent, selector: "sneat-contact-details", inputs: ["$contact"], outputs: ["contactChange"] }, { kind: "ngmodule", type: ContactusServicesModule }, { kind: "ngmodule", type: SpaceServiceModule }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonBackButton, selector: "ion-back-button" }, { kind: "component", type: IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { 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: IonMenuButton, selector: "ion-menu-button", inputs: ["autoHide", "color", "disabled", "menu", "mode", "type"] }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "pipe", type: PersonTitle, name: "personTitle" }] }); }
77
+ }
78
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ContactPageComponent, decorators: [{
79
+ type: Component,
80
+ args: [{ selector: 'sneat-contact-page', imports: [
81
+ ContactDetailsComponent,
82
+ ContactusServicesModule,
83
+ SpaceServiceModule,
84
+ PersonTitle,
85
+ IonHeader,
86
+ IonToolbar,
87
+ IonButtons,
88
+ IonBackButton,
89
+ IonTitle,
90
+ IonButton,
91
+ IonIcon,
92
+ IonMenuButton,
93
+ IonContent,
94
+ ], providers: [{ provide: ClassName, useValue: 'ContactPageComponent' }], template: "<ion-header>\n <ion-toolbar color=\"light\">\n <ion-buttons slot=\"start\">\n <ion-back-button [defaultHref]=\"$defaultBackUrl()\" />\n </ion-buttons>\n <ion-title>\n @if ($contact(); as contact) {\n {{ contact | personTitle }}\n } @else {\n Contact\n }\n </ion-title>\n <ion-buttons slot=\"end\">\n <ion-button\n title=\"Delete contact\"\n color=\"medium\"\n (click)=\"deleteContact()\"\n >\n <ion-icon name=\"trash\" slot=\"start\" />\n </ion-button>\n <ion-menu-button />\n </ion-buttons>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n <sneat-contact-details [$contact]=\"$contact()\" [$space]=\"$space()\" />\n</ion-content>\n" }]
95
+ }], ctorParameters: () => [] });
96
+ //# sourceMappingURL=contact-page.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contact-page.component.js","sourceRoot":"","sources":["../../../../../../../../libs/contactus/internal/src/lib/pages/contact/contact-page.component.ts","../../../../../../../../libs/contactus/internal/src/lib/pages/contact/contact-page.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, inject } from '@angular/core';\nimport {\n IonBackButton,\n IonButton,\n IonButtons,\n IonContent,\n IonHeader,\n IonIcon,\n IonMenuButton,\n IonTitle,\n IonToolbar,\n} from '@ionic/angular/standalone';\nimport { ISaveEvent } from '@sneat/components';\nimport { ContactDetailsComponent, PersonTitle } from '@sneat/contactus-shared';\nimport { SneatNavService } from '@sneat/core';\nimport { IAddress } from '@sneat/contactus-core';\nimport {\n ContactService,\n ContactusServicesModule,\n IContactRequest,\n IUpdateContactRequest,\n} from '@sneat/contactus-services';\nimport { SpaceServiceModule } from '@sneat/space-services';\nimport { ClassName } from '@sneat/ui';\nimport { ContactBasePage } from '../contact-base-page';\n\n@Component({\n selector: 'sneat-contact-page',\n templateUrl: './contact-page.component.html',\n imports: [\n ContactDetailsComponent,\n ContactusServicesModule,\n SpaceServiceModule,\n PersonTitle,\n IonHeader,\n IonToolbar,\n IonButtons,\n IonBackButton,\n IonTitle,\n IonButton,\n IonIcon,\n IonMenuButton,\n IonContent,\n ],\n providers: [{ provide: ClassName, useValue: 'ContactPageComponent' }],\n})\nexport class ContactPageComponent extends ContactBasePage {\n private readonly contactsService = inject(ContactService);\n private readonly sneatNavService = inject(SneatNavService);\n\n protected segment: 'contact' | 'members' | 'assets' = 'contact';\n\n constructor() {\n super(inject(ContactService));\n this.defaultBackPage = 'contacts';\n }\n\n // TODO: use or remove\n private watchChildContacts(): void {\n const contactID = this.$contactID();\n if (!contactID) {\n return;\n }\n const space = this.space;\n if (!space) {\n return;\n }\n this.contactsService\n .watchChildContacts(space, contactID)\n .pipe(this.takeUntilDestroyed())\n .subscribe({\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n next: (_children) => {\n // Handle children if needed\n },\n error: this.errorLogger.logErrorHandler('failed to get child contacts'),\n });\n }\n\n // TODO: use or remove\n protected saveAddress(save: ISaveEvent<IAddress>): void {\n const spaceID = this.space?.id,\n contactID = this.$contactID(),\n address = save.object;\n\n if (!spaceID || !contactID || !address) {\n save.error('Can not save address without team and contact context');\n return;\n }\n\n const request: IUpdateContactRequest = {\n spaceID,\n contactID,\n address,\n };\n\n this.contactService.updateContact(request).subscribe({\n next: () => save.success(),\n error: save.error,\n });\n }\n\n protected deleteContact(): void {\n const contact = this.$contact();\n if (!contact) {\n return;\n }\n if (\n !confirm(\n `Are you sure you want to delete contact \"${contact.brief?.title}\"?`,\n )\n ) {\n return;\n }\n const request: IContactRequest = {\n spaceID: this.space.id,\n contactID: contact.id,\n };\n\n this.contactsService.deleteContact(request).subscribe({\n next: () => {\n this.sneatNavService.goBack(`/space/${this.space?.id}/contacts`);\n },\n error: this.errorLogger.logErrorHandler('failed to delete contact'),\n });\n }\n}\n","<ion-header>\n <ion-toolbar color=\"light\">\n <ion-buttons slot=\"start\">\n <ion-back-button [defaultHref]=\"$defaultBackUrl()\" />\n </ion-buttons>\n <ion-title>\n @if ($contact(); as contact) {\n {{ contact | personTitle }}\n } @else {\n Contact\n }\n </ion-title>\n <ion-buttons slot=\"end\">\n <ion-button\n title=\"Delete contact\"\n color=\"medium\"\n (click)=\"deleteContact()\"\n >\n <ion-icon name=\"trash\" slot=\"start\" />\n </ion-button>\n <ion-menu-button />\n </ion-buttons>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n <sneat-contact-details [$contact]=\"$contact()\" [$space]=\"$space()\" />\n</ion-content>\n"]}
@@ -0,0 +1,2 @@
1
+ export * from './contact-page.component';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../../libs/contactus/internal/src/lib/pages/contact/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC","sourcesContent":["export * from './contact-page.component';\n"]}