@ieeesa-npm/groups 0.15.0 → 0.15.2

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.
@@ -0,0 +1,37 @@
1
+ import { MatDialogRef } from '@angular/material/dialog';
2
+ import { AvailableForeignGroup } from '../../models/reciprocal-credit.model';
3
+ import * as i0 from "@angular/core";
4
+ /** Data passed into the Add Working Groups modal. */
5
+ export interface AddWorkingGroupsDialogData {
6
+ availableGroups: AvailableForeignGroup[];
7
+ selectedGroupIds: string[];
8
+ }
9
+ /** Row model with a local selection flag. */
10
+ interface WorkingGroupRow extends AvailableForeignGroup {
11
+ selected: boolean;
12
+ }
13
+ /**
14
+ * Modal to select one or more foreign working groups (under the same committee)
15
+ * for reciprocal credit. Provides search and a checkbox table. Returns the
16
+ * selected AvailableForeignGroup[] on Add.
17
+ * @export
18
+ * @class AddWorkingGroupsComponent
19
+ */
20
+ export declare class AddWorkingGroupsComponent {
21
+ private dialogRef;
22
+ private data;
23
+ rows: WorkingGroupRow[];
24
+ searchTerm: string;
25
+ constructor(dialogRef: MatDialogRef<AddWorkingGroupsComponent>, data: AddWorkingGroupsDialogData);
26
+ /** Rows filtered by the search term (group name). */
27
+ get filteredRows(): WorkingGroupRow[];
28
+ /** Count of currently selected rows (for the title). */
29
+ get selectedCount(): number;
30
+ /** Toggle a row's selection. */
31
+ toggleRow(row: WorkingGroupRow): void;
32
+ onCancel(): void;
33
+ onAdd(): void;
34
+ static ɵfac: i0.ɵɵFactoryDeclaration<AddWorkingGroupsComponent, never>;
35
+ static ɵcmp: i0.ɵɵComponentDeclaration<AddWorkingGroupsComponent, "ieeesa-add-working-groups", never, {}, {}, never, never, true, never>;
36
+ }
37
+ export {};
@@ -9,6 +9,7 @@ import { GroupInfo } from '../../models/group-info.model';
9
9
  import { AlertType } from '@ieeesa-npm/models';
10
10
  import { GroupFunctionType } from '../../models/group-function-type.model';
11
11
  import { ParentGroupsInfo } from '../../models/parent-groups-info.model';
12
+ import { SelectedForeignGroup } from '../reciprocal-credit-section/reciprocal-credit-section.component';
12
13
  import * as i0 from "@angular/core";
13
14
  /**
14
15
  * CreateGroupComponent uses DynamicFormComponent to build create new group form or edit group and implement the functionalities of submission of form and handling success and error scenarios.
@@ -33,6 +34,9 @@ export declare class CreateGroupComponent implements OnInit, OnDestroy {
33
34
  formCancel: EventEmitter<any>;
34
35
  createGroupText: {
35
36
  heading: string;
37
+ reciprocalCredit: {
38
+ selectAtLeastOneGroup: string;
39
+ };
36
40
  label: {
37
41
  parentGroup: string;
38
42
  changeParentGroup: string;
@@ -56,7 +60,7 @@ export declare class CreateGroupComponent implements OnInit, OnDestroy {
56
60
  parentGroup: string;
57
61
  changeParentGroup: string;
58
62
  newParentGroup: string;
59
- groupType: string;
63
+ groupType: string; /** Config ids of previously-saved reciprocal rows removed locally — for soft-delete on Save. */
60
64
  groupName: string;
61
65
  shortName: string;
62
66
  groupScope: string;
@@ -111,6 +115,13 @@ export declare class CreateGroupComponent implements OnInit, OnDestroy {
111
115
  allowedParentGroupsOptions: SelectOption[];
112
116
  isParentGroupChanged: boolean;
113
117
  slideToggleOption: SlideToggleOption;
118
+ /** Reciprocal credit state (Working Group only) — captured for Save. */
119
+ reciprocalEnabled: boolean;
120
+ reciprocalSelectedGroups: SelectedForeignGroup[];
121
+ /** Config ids of previously-saved reciprocal rows removed locally — for soft-delete on Save. */
122
+ reciprocalRemovedConfigIds: string[];
123
+ /** Group type currently selected in the create form (for gating the section). */
124
+ selectedCreateGroupTypeId?: string;
114
125
  dynamicFormComponent: DynamicFormComponent;
115
126
  constructor(groupsService: GroupsService, globalErrorHandlerService: GlobalErrorHandlerService, alertService: AlertsService);
116
127
  /**
@@ -166,6 +177,15 @@ export declare class CreateGroupComponent implements OnInit, OnDestroy {
166
177
  * @memberof CreateGroupComponent
167
178
  */
168
179
  editGroup(formData: any): void;
180
+ /**
181
+ * Persists reciprocal-credit changes captured from the section after a
182
+ * successful group edit: POSTs newly-added foreign groups (those without a
183
+ * configId) and soft-deletes each removed config id. Emits the group-edit
184
+ * response once persistence completes (or immediately if there's nothing to do).
185
+ * @param {*} editResponse the successful edit-group response
186
+ * @memberof CreateGroupComponent
187
+ */
188
+ private persistReciprocalCredit;
169
189
  /**
170
190
  * Captures the server side errors and handles the errors based on the custom or Http errors.
171
191
  * @param {HttpErrorResponse} error
@@ -193,6 +213,39 @@ export declare class CreateGroupComponent implements OnInit, OnDestroy {
193
213
  * @memberof CreateGroupComponent
194
214
  */
195
215
  createGroupCancelled(): void;
216
+ /**
217
+ * True when the group being created/edited is a Working Group — gates the
218
+ * Reciprocal Credit section.
219
+ * @return {boolean}
220
+ * @memberof CreateGroupComponent
221
+ */
222
+ get isWorkingGroup(): boolean;
223
+ /**
224
+ * True when the Reciprocal Credit section should be shown: only for a Working
225
+ * Group in EDIT mode. Hidden during create because the home group has no id
226
+ * yet and the create flow is still being finalized with the client team.
227
+ * @return {boolean}
228
+ * @memberof CreateGroupComponent
229
+ */
230
+ get isReciprocalSectionVisible(): boolean;
231
+ /**
232
+ * True when the reciprocal section is shown, the toggle is ON, but no foreign
233
+ * group has been added — an invalid state (BE rejects an empty foreign-group
234
+ * list). Used to block the edit Save.
235
+ * @return {boolean}
236
+ * @memberof CreateGroupComponent
237
+ */
238
+ get isReciprocalInvalid(): boolean;
239
+ /** Home group id for the reciprocal section (present in edit). */
240
+ get reciprocalHomeGroupId(): string | undefined;
241
+ /** Parent committee name shown in the reciprocal helper text. */
242
+ get reciprocalParentCommitteeName(): string | undefined;
243
+ /** Capture reciprocal toggle state from the section. */
244
+ onReciprocalEnabledChange(enabled: boolean): void;
245
+ /** Capture reciprocal foreign-group selection from the section. */
246
+ onReciprocalSelectionChange(groups: SelectedForeignGroup[]): void;
247
+ /** Capture the config ids to soft-delete on Save from the section. */
248
+ onReciprocalRemovedConfigIdsChange(configIds: string[]): void;
196
249
  /**
197
250
  * Gets allowed parent groups for reassigning the parent.
198
251
  * @param {string} groupId
@@ -0,0 +1,102 @@
1
+ import { EventEmitter, OnDestroy, OnInit } from '@angular/core';
2
+ import { MatDialog } from '@angular/material/dialog';
3
+ import { SlideToggleOption } from '@ieeesa-npm/presentation';
4
+ import { Subject } from 'rxjs';
5
+ import { GroupsService } from '../../services/groups.service';
6
+ import { AvailableForeignGroup } from '../../models/reciprocal-credit.model';
7
+ import * as i0 from "@angular/core";
8
+ /**
9
+ * A selected foreign group shown as a chip. `configId` is present only for groups
10
+ * that were loaded from an existing (saved) config — it is needed to remove that
11
+ * specific row on the BE when the group is de-selected or the toggle is turned off.
12
+ */
13
+ export interface SelectedForeignGroup {
14
+ groupId: string;
15
+ groupName: string;
16
+ configId?: string;
17
+ }
18
+ /**
19
+ * Reciprocal Credit configuration section shown inside the group create/edit
20
+ * form — ONLY when the group is a Working Group. Provides the enable toggle,
21
+ * selected foreign-group chips, and the "+ Add Working Groups" launcher.
22
+ *
23
+ * The toggle has no backend flag: it is derived from whether any config rows
24
+ * exist for the home group. Enabling persists nothing until at least one foreign
25
+ * group is added (POST); disabling soft-deletes every existing config row
26
+ * (one POST /{configId}/remove per row).
27
+ *
28
+ * The parent form reads `enabled` and `selectedForeignGroups` to build the save
29
+ * request, and `removedConfigIds` to know which existing rows to remove.
30
+ * @export
31
+ * @class ReciprocalCreditSectionComponent
32
+ */
33
+ export declare class ReciprocalCreditSectionComponent implements OnInit, OnDestroy {
34
+ private groupsService;
35
+ private dialog;
36
+ destroy$: Subject<boolean>;
37
+ /** Home group id (present in edit; absent in create until the group is saved). */
38
+ homeGroupId?: string;
39
+ /** Optional event id for event-scoped configs (omit for global/Groups screen). */
40
+ eventId?: string;
41
+ /** Parent committee name for the helper text ("Only groups under ..."). */
42
+ parentCommitteeName?: string;
43
+ /** Emits the current enabled state whenever it changes. */
44
+ enabledChange: EventEmitter<boolean>;
45
+ /** Emits the current selected foreign groups whenever they change. */
46
+ selectionChange: EventEmitter<SelectedForeignGroup[]>;
47
+ /**
48
+ * Emits the config ids of previously-saved rows that have been removed locally
49
+ * (chip de-selected or toggle turned off), so the parent can soft-delete each
50
+ * on save.
51
+ */
52
+ removedConfigIdsChange: EventEmitter<string[]>;
53
+ /** Toggle state. */
54
+ enabled: boolean;
55
+ /** Option config for the shared ieeesa-slide-toggle. */
56
+ toggleOption: SlideToggleOption;
57
+ /** Selected foreign working groups (chips). */
58
+ selectedForeignGroups: SelectedForeignGroup[];
59
+ /**
60
+ * Persistent map of foreignGroupId → configId for the rows that existed on the
61
+ * initial load. Kept for the whole edit session so a saved group re-selected
62
+ * after being de-selected recovers its configId (and its queued removal is undone).
63
+ */
64
+ private savedConfigIdByGroupId;
65
+ /**
66
+ * Config ids that existed on load but have since been removed locally (either by
67
+ * de-selecting a chip or turning the toggle off). The parent removes each on save.
68
+ */
69
+ removedConfigIds: string[];
70
+ /** All foreign working groups available under the same committee. */
71
+ availableGroups: AvailableForeignGroup[];
72
+ isLoading: boolean;
73
+ constructor(groupsService: GroupsService, dialog: MatDialog);
74
+ ngOnInit(): void;
75
+ /** Fetch the foreign working groups available for selection. */
76
+ private loadAvailableGroups;
77
+ /**
78
+ * Load existing reciprocal config rows for the edit-prefill path. The toggle is
79
+ * ON when one or more rows exist; each chip keeps its own configId for removal.
80
+ */
81
+ private loadExistingConfig;
82
+ /** Handle the enable/disable toggle (shared ieeesa-slide-toggle emits SlideToggleOption). */
83
+ onToggleChange(option: SlideToggleOption): void;
84
+ /** Open the Add Working Groups modal. */
85
+ onAddWorkingGroups(): void;
86
+ /**
87
+ * Merge the modal's returned selection into the current chips. Groups that are
88
+ * no longer selected but were saved get queued for removal; already-selected
89
+ * groups keep their existing configId.
90
+ */
91
+ private mergeSelection;
92
+ /** Remove a selected foreign group chip. */
93
+ removeGroup(groupId: string): void;
94
+ /** Track saved rows (those with a configId) that must be removed on the BE. */
95
+ private queueRemovalOf;
96
+ /** True when the section is valid (toggle off, OR toggle on with ≥1 group). */
97
+ get isValid(): boolean;
98
+ private emitState;
99
+ ngOnDestroy(): void;
100
+ static ɵfac: i0.ɵɵFactoryDeclaration<ReciprocalCreditSectionComponent, never>;
101
+ static ɵcmp: i0.ɵɵComponentDeclaration<ReciprocalCreditSectionComponent, "ieeesa-reciprocal-credit-section", never, { "homeGroupId": { "alias": "homeGroupId"; "required": false; }; "eventId": { "alias": "eventId"; "required": false; }; "parentCommitteeName": { "alias": "parentCommitteeName"; "required": false; }; }, { "enabledChange": "enabledChange"; "selectionChange": "selectionChange"; "removedConfigIdsChange": "removedConfigIdsChange"; }, never, never, true, never>;
102
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * A foreign group returned by the `available-groups` endpoint. It is a candidate
3
+ * that can be selected as a reciprocal-credit source for a home group.
4
+ *
5
+ * Real API: GET /v1/meetings/admin/reciprocal-credit/{homeGroupId}/available-groups
6
+ * Body item shape: { groupId, groupName }
7
+ * @export
8
+ * @interface AvailableForeignGroup
9
+ */
10
+ export interface AvailableForeignGroup {
11
+ groupId: string;
12
+ groupName: string;
13
+ }
14
+ /** Scope of a reciprocal-credit config row. */
15
+ export type ReciprocalCreditScope = 'EVENT' | 'GLOBAL';
16
+ /**
17
+ * A single reciprocal-credit config row. The BE returns one row per foreign
18
+ * group, each with its own `configId` (needed to remove/soft-delete that row).
19
+ *
20
+ * Real API: GET/POST /v1/meetings/admin/reciprocal-credit... → body: ReciprocalCreditConfigRow[]
21
+ * @export
22
+ * @interface ReciprocalCreditConfigRow
23
+ */
24
+ export interface ReciprocalCreditConfigRow {
25
+ configId: string;
26
+ homeGroupId: string;
27
+ foreignGroupId: string;
28
+ foreignGroupName: string;
29
+ /** Present only for event-scoped configs. */
30
+ eventId?: string;
31
+ scope: ReciprocalCreditScope;
32
+ }
33
+ /**
34
+ * Payload for saving a reciprocal-credit configuration.
35
+ * `eventId` is included only for event-scoped configs; omit it for global configs.
36
+ *
37
+ * Real API: POST /v1/meetings/admin/reciprocal-credit
38
+ * @export
39
+ * @interface SaveReciprocalCreditPayload
40
+ */
41
+ export interface SaveReciprocalCreditPayload {
42
+ homeGroupId: string;
43
+ foreignGroupIds: string[];
44
+ eventId?: string;
45
+ }
46
+ /** Standard API response wrapper for reciprocal endpoints. */
47
+ export interface ReciprocalCreditResponse<T> {
48
+ status: boolean;
49
+ message: string;
50
+ body: T;
51
+ }
@@ -8,6 +8,7 @@ import { GroupInfo } from '../models/group-info.model';
8
8
  import { SearchUsersPayload, FilterUsersPayload, GetGroupUsersResponse, User, LoggedInUserInfo } from '../models/user.model';
9
9
  import { Role } from '../models/role.model';
10
10
  import { EditGroupPayload } from '../models/edit-group.model';
11
+ import { AvailableForeignGroup, ReciprocalCreditConfigRow, ReciprocalCreditResponse, SaveReciprocalCreditPayload } from '../models/reciprocal-credit.model';
11
12
  import { GroupFunctionType } from '../models/group-function-type.model';
12
13
  import { RosterFunctionType } from '../models/roster-function-type.model';
13
14
  import { GroupUserInfo } from '../models/group-user-info.model';
@@ -45,6 +46,14 @@ export declare class GroupsService {
45
46
  "1006": string;
46
47
  "1007": string;
47
48
  "1008": string;
49
+ /**
50
+ * Handles custom API errors: maps BE error codes to messages and shows an
51
+ * alert. Mirrors the events-and-meetings error handling so reciprocal-credit
52
+ * failures (e.g. MTG-011 duplicate, MTG-012 permission) surface consistently.
53
+ * @param {*} error the HttpErrorResponse from a failed call
54
+ * @param {boolean} [showAlert=true] whether to display the alert
55
+ * @memberof GroupsService
56
+ */
48
57
  "1009": string;
49
58
  "1010": string;
50
59
  "1011": string;
@@ -67,12 +76,6 @@ export declare class GroupsService {
67
76
  "1028": string;
68
77
  "1029": string;
69
78
  "1030": string;
70
- /**
71
- * Gets the group users for the given group id.
72
- * @param {string} groupId
73
- * @return {Observable<GetGroupUsersResponse>}
74
- * @memberof GroupsService
75
- */
76
79
  "1031": string;
77
80
  "1032": string;
78
81
  "1033": string;
@@ -83,7 +86,11 @@ export declare class GroupsService {
83
86
  "1038": string;
84
87
  "1039": string;
85
88
  "2001": string;
86
- "2002": string;
89
+ "2002": string; /**
90
+ * Sets group function type.
91
+ * @param {GroupFunctionType} groupFunctionType -group function type.
92
+ * @memberof GroupsService
93
+ */
87
94
  "2010": string;
88
95
  "2011": string;
89
96
  "20l2": string;
@@ -95,16 +102,15 @@ export declare class GroupsService {
95
102
  "2018": string;
96
103
  "2019": string;
97
104
  "2020": string;
98
- "2021": string; /**
99
- * Gets the group users based on searched name or email
100
- * @param {SearchUsersPayload} payload
101
- * @return {Observable<GetGroupUsersResponse>}
102
- * @memberof GroupsService
103
- */
105
+ "2021": string;
104
106
  "2022": string;
105
107
  "2023": string;
106
108
  "2024": string;
107
109
  "3004": string;
110
+ "MTG-010": string;
111
+ "MTG-011": string;
112
+ "MTG-012": string;
113
+ default: string;
108
114
  };
109
115
  apiBaseUrl: string;
110
116
  userPermission: any;
@@ -180,6 +186,15 @@ export declare class GroupsService {
180
186
  * @memberof GroupsService
181
187
  */
182
188
  parseErrorMessage(errorCodes: string[]): string[];
189
+ /**
190
+ * Handles custom API errors: maps BE error codes to messages and shows an
191
+ * alert. Mirrors the events-and-meetings error handling so reciprocal-credit
192
+ * failures (e.g. MTG-011 duplicate, MTG-012 permission) surface consistently.
193
+ * @param {*} error the HttpErrorResponse from a failed call
194
+ * @param {boolean} [showAlert=true] whether to display the alert
195
+ * @memberof GroupsService
196
+ */
197
+ handleErrors(error: any, showAlert?: boolean): void;
183
198
  /**
184
199
  * Sets selected group info.
185
200
  * @param {(GroupInfo | undefined)} selectedGroupInfo -selected group info.
@@ -429,6 +444,49 @@ export declare class GroupsService {
429
444
  * @memberof GroupsService
430
445
  */
431
446
  getMemberTypes(): Role[];
447
+ /** Path prefix (relative to apiBaseUrl) for the reciprocal-credit endpoints. */
448
+ private readonly RECIPROCAL_BASE_PATH;
449
+ /**
450
+ * Build a reciprocal-credit endpoint URL from apiBaseUrl + the base path,
451
+ * guarding against accidental double slashes if apiBaseUrl has a trailing slash.
452
+ * @param {string} [suffix] extra path/query appended after the base path.
453
+ * @return {string}
454
+ */
455
+ private buildReciprocalUrl;
456
+ /**
457
+ * Fetch the foreign groups available for reciprocal credit for a home group.
458
+ * GET {apiBaseUrl}/meetings/admin/reciprocal-credit/{homeGroupId}/available-groups
459
+ * @param {string} homeGroupId
460
+ * @return {Observable<ReciprocalCreditResponse<AvailableForeignGroup[]>>}
461
+ * @memberof GroupsService
462
+ */
463
+ getAvailableReciprocalGroups(homeGroupId: string): Observable<ReciprocalCreditResponse<AvailableForeignGroup[]>>;
464
+ /**
465
+ * Load existing reciprocal-credit config rows for a home group (edit prefill).
466
+ * GET {apiBaseUrl}/meetings/admin/reciprocal-credit/{homeGroupId}[?eventId=...]
467
+ * Returns one row per foreign group; an empty array means reciprocal credit is off.
468
+ * @param {string} homeGroupId
469
+ * @param {string} [eventId] optional — filters to an event-scoped config.
470
+ * @return {Observable<ReciprocalCreditResponse<ReciprocalCreditConfigRow[]>>}
471
+ * @memberof GroupsService
472
+ */
473
+ getReciprocalConfig(homeGroupId: string, eventId?: string): Observable<ReciprocalCreditResponse<ReciprocalCreditConfigRow[]>>;
474
+ /**
475
+ * Save a reciprocal-credit config (creates/reactivates one row per foreign group).
476
+ * POST {apiBaseUrl}/meetings/admin/reciprocal-credit
477
+ * @param {SaveReciprocalCreditPayload} payload
478
+ * @return {Observable<ReciprocalCreditResponse<ReciprocalCreditConfigRow[]>>}
479
+ * @memberof GroupsService
480
+ */
481
+ saveReciprocalCredit(payload: SaveReciprocalCreditPayload): Observable<ReciprocalCreditResponse<ReciprocalCreditConfigRow[]>>;
482
+ /**
483
+ * Remove (soft delete) a single reciprocal-credit config row by its configId.
484
+ * POST {apiBaseUrl}/meetings/admin/reciprocal-credit/{configId}/remove
485
+ * @param {string} configId
486
+ * @return {Observable<ReciprocalCreditResponse<null>>}
487
+ * @memberof GroupsService
488
+ */
489
+ removeReciprocalConfig(configId: string): Observable<ReciprocalCreditResponse<null>>;
432
490
  static ɵfac: i0.ɵɵFactoryDeclaration<GroupsService, never>;
433
491
  static ɵprov: i0.ɵɵInjectableDeclaration<GroupsService>;
434
492
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ieeesa-npm/groups",
3
- "version": "0.15.0",
3
+ "version": "0.15.2",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^16.1.0",
6
6
  "@angular/core": "^16.1.0"
package/public-api.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  export * from './lib/components/create-group/create-group.component';
2
2
  export * from './lib/components/tree-view/tree-view.component';
3
3
  export * from './lib/components/edit-user-roles/edit-user-roles.component';
4
+ export * from './lib/components/reciprocal-credit-section/reciprocal-credit-section.component';
5
+ export * from './lib/components/add-working-groups/add-working-groups.component';
4
6
  export * from './lib/groups.component';
5
7
  export * from './lib/models/create-group.model';
6
8
  export * from './lib/models/group-action.model';
@@ -20,6 +22,7 @@ export * from './lib/models/role-type.model';
20
22
  export * from './lib/models/roster-type.model';
21
23
  export * from './lib/models/table-column-schema-user-group.model';
22
24
  export * from './lib/models/parent-groups-info.model';
25
+ export * from './lib/models/reciprocal-credit.model';
23
26
  export * from './lib/services/groups.service';
24
27
  export * from './lib/assets/form-validations';
25
28
  export * from './lib/groups.module';