@ieeesa-npm/dashboard 0.0.1 → 0.0.3
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.
- package/esm2022/lib/assets/constants.json +23 -6
- package/esm2022/lib/assets/dashboard-mock.mjs +5 -1
- package/esm2022/lib/assets/dashboard-route-paths.mock.mjs +7 -5
- package/esm2022/lib/components/event-group-card/event-group-card.component.mjs +168 -31
- package/esm2022/lib/components/meeting-attendance-row/meeting-attendance-row.component.mjs +25 -24
- package/esm2022/lib/components/upcoming-meetings-events/upcoming-meetings-events.component.mjs +103 -5
- package/esm2022/lib/components/welcome-header/dashboard-welcome-header.component.mjs +3 -3
- package/esm2022/lib/components/your-groups/your-groups.component.mjs +264 -118
- package/esm2022/lib/dashboard.component.mjs +54 -14
- package/esm2022/lib/models/event-meeting-list-item.model.mjs +2 -0
- package/esm2022/lib/models/event-meeting-list-payload.model.mjs +8 -0
- package/esm2022/lib/models/group-row.model.mjs +1 -1
- package/esm2022/lib/models/meeting-row.model.mjs +1 -1
- package/esm2022/lib/models/my-groups-view.model.mjs +2 -0
- package/esm2022/lib/models/upcoming-event.model.mjs +13 -2
- package/esm2022/lib/services/dashboard.service.mjs +229 -35
- package/esm2022/lib/utils/date-format.util.mjs +110 -0
- package/esm2022/lib/utils/event-meeting-mapper.util.mjs +96 -0
- package/esm2022/public-api.mjs +3 -1
- package/fesm2022/ieeesa-npm-dashboard.mjs +1300 -444
- package/fesm2022/ieeesa-npm-dashboard.mjs.map +1 -1
- package/lib/components/event-group-card/event-group-card.component.d.ts +100 -132
- package/lib/components/meeting-attendance-row/meeting-attendance-row.component.d.ts +8 -132
- package/lib/components/member-level-badge/member-level-badge.component.d.ts +19 -3
- package/lib/components/upcoming-meetings-events/upcoming-meetings-events.component.d.ts +63 -126
- package/lib/components/your-groups/your-groups.component.d.ts +158 -51
- package/lib/dashboard.component.d.ts +48 -10
- package/lib/models/event-meeting-list-item.model.d.ts +107 -0
- package/lib/models/event-meeting-list-payload.model.d.ts +40 -0
- package/lib/models/group-row.model.d.ts +25 -0
- package/lib/models/meeting-row.model.d.ts +18 -2
- package/lib/models/my-groups-view.model.d.ts +56 -0
- package/lib/models/upcoming-event.model.d.ts +40 -2
- package/lib/services/dashboard.service.d.ts +97 -14
- package/lib/utils/date-format.util.d.ts +60 -0
- package/lib/utils/event-meeting-mapper.util.d.ts +50 -0
- package/package.json +1 -1
- package/public-api.d.ts +2 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Raw list item returned by the real "events & meetings" backend
|
|
3
|
+
* (`POST {apiBaseUrl}/meetings/eventsAndMeetings`). A single list may contain
|
|
4
|
+
* both EVENT rows (`isMeetingEvent === true` / `hasChildren === true`, which own
|
|
5
|
+
* child meetings) and STANDALONE MEETING rows (`isMeetingEvent === false`).
|
|
6
|
+
*
|
|
7
|
+
* Dates are epoch milliseconds (not ISO strings) and must be formatted with
|
|
8
|
+
* luxon `DateTime.fromMillis`. This shape mirrors the `events-and-meetings`
|
|
9
|
+
* library's `EventsAndMeetings` list model so the dashboard reuses the exact
|
|
10
|
+
* backend contract referenced by the existing
|
|
11
|
+
* `view-events-meetings-list` screen.
|
|
12
|
+
*/
|
|
13
|
+
export interface EventMeetingListItem {
|
|
14
|
+
/** Stable identifier of the event or standalone meeting. */
|
|
15
|
+
id: string;
|
|
16
|
+
/** Event / meeting display name. */
|
|
17
|
+
name: string;
|
|
18
|
+
/** Start date-time as an ISO-8601 string (or epoch ms for legacy fixtures). */
|
|
19
|
+
startDateTime: string | number;
|
|
20
|
+
/** End date-time as an ISO-8601 string (or epoch ms for legacy fixtures). */
|
|
21
|
+
endDateTime: string | number;
|
|
22
|
+
/** IANA / offset-prefixed timezone string, e.g. "(UTC+05:30) Asia/Kolkata". */
|
|
23
|
+
timeZone: string;
|
|
24
|
+
/** Owning group id. */
|
|
25
|
+
groupId?: string;
|
|
26
|
+
/** Owning group display name. */
|
|
27
|
+
groupName?: string;
|
|
28
|
+
/** Owning group acronym, when provided. */
|
|
29
|
+
groupAcronym?: string;
|
|
30
|
+
/** Room / location text, when provided. */
|
|
31
|
+
meetingLocation?: string | null;
|
|
32
|
+
/** True when this row is an EVENT that owns child meetings. */
|
|
33
|
+
hasChildren?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* True when the row represents an EVENT (vs. a standalone meeting). Combined
|
|
36
|
+
* with {@link hasChildren} this is the EVENT-vs-STANDALONE discriminator.
|
|
37
|
+
*/
|
|
38
|
+
isMeetingEvent?: boolean;
|
|
39
|
+
/** Lifecycle status, e.g. "In Progress", "Upcoming", "Starts Soon". */
|
|
40
|
+
status?: string;
|
|
41
|
+
/** True when the signed-in user is a member of the owning group. */
|
|
42
|
+
isMemberOfGroup?: boolean;
|
|
43
|
+
/** True when the current user is currently attending (drives the pill). */
|
|
44
|
+
isCurrentlyAttending?: boolean;
|
|
45
|
+
/** True when the row is open for attendance logging. */
|
|
46
|
+
isOpenForAttendance?: boolean;
|
|
47
|
+
/** Event id a standalone/child meeting belongs to, when applicable. */
|
|
48
|
+
eventId?: string;
|
|
49
|
+
/** Meeting id, when the row is a meeting. */
|
|
50
|
+
meetingId?: string;
|
|
51
|
+
/** Alternate name key some payloads use for meetings. */
|
|
52
|
+
meetingTitle?: string;
|
|
53
|
+
/** Alternate status key (the list screen copies status here). */
|
|
54
|
+
contentUnderLink?: string;
|
|
55
|
+
/** Alternate location key used by some meeting payloads. */
|
|
56
|
+
room?: string | null;
|
|
57
|
+
/** Count of child meetings for an event, when the backend provides it. */
|
|
58
|
+
meetingCount?: number;
|
|
59
|
+
/** Count of child meetings open for attendance, when provided. */
|
|
60
|
+
openForAttendanceCount?: number;
|
|
61
|
+
/** "Day X of Y" indicator string, when the backend provides it. */
|
|
62
|
+
dayIndicator?: string;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Response envelope for the dashboard events-&-meetings list endpoint, matching
|
|
66
|
+
* the `events-and-meetings` library's `GetEventsAndMeetingsResponse` body shape.
|
|
67
|
+
*/
|
|
68
|
+
export interface EventMeetingListResponse {
|
|
69
|
+
status: boolean;
|
|
70
|
+
message?: string;
|
|
71
|
+
body: {
|
|
72
|
+
totalRecords: number;
|
|
73
|
+
eventMeetingList: EventMeetingListItem[];
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Child-meeting list item returned by the per-event expand endpoint
|
|
78
|
+
* (`POST {apiBaseUrl}/meetings/meetingsDetails`). Dates are epoch milliseconds.
|
|
79
|
+
* Mirrors the `events-and-meetings` library's `Meeting` model.
|
|
80
|
+
*/
|
|
81
|
+
export interface EventMeetingDetailItem {
|
|
82
|
+
meetingId: string;
|
|
83
|
+
meetingTitle: string;
|
|
84
|
+
meetingStDate: string | number;
|
|
85
|
+
meetingEdDate: string | number;
|
|
86
|
+
meetingLocation?: string;
|
|
87
|
+
groupId?: string;
|
|
88
|
+
groupName?: string;
|
|
89
|
+
groupAcronym?: string;
|
|
90
|
+
timeZone?: string;
|
|
91
|
+
status?: string;
|
|
92
|
+
isMemberOfGroup?: boolean;
|
|
93
|
+
isCurrentlyAttending?: boolean;
|
|
94
|
+
isOpenForAttendance?: boolean;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Response envelope for the per-event child-meetings expand endpoint, matching
|
|
98
|
+
* the `events-and-meetings` library's `GetMeetingsByEventIdResponse` body shape.
|
|
99
|
+
*/
|
|
100
|
+
export interface EventMeetingDetailResponse {
|
|
101
|
+
status: boolean;
|
|
102
|
+
message?: string;
|
|
103
|
+
body: {
|
|
104
|
+
totalRecords: number;
|
|
105
|
+
meetings: EventMeetingDetailItem[];
|
|
106
|
+
};
|
|
107
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request payloads for the dashboard "events & meetings" backend calls. These
|
|
3
|
+
* mirror the `events-and-meetings` library's `GetEventsAndMeetingsPayload` /
|
|
4
|
+
* `GetMeetingsByEventIdPayload` so the dashboard reuses the exact contract the
|
|
5
|
+
* existing `view-events-meetings-list` screen posts.
|
|
6
|
+
*/
|
|
7
|
+
/** Filter block shared by the list and expand payloads. */
|
|
8
|
+
export interface EventMeetingFilter {
|
|
9
|
+
/** Lifecycle statuses to include, e.g. ["In Progress", "Upcoming"]. */
|
|
10
|
+
status: string[];
|
|
11
|
+
/** Whether every meeting (regardless of membership) should be returned. */
|
|
12
|
+
isAllMeetingSelected: boolean;
|
|
13
|
+
/** Optional group-id scope. */
|
|
14
|
+
groupIds?: string[];
|
|
15
|
+
}
|
|
16
|
+
/** Payload for `POST {apiBaseUrl}/meetings/eventsAndMeetings` (the section list). */
|
|
17
|
+
export interface EventMeetingListPayload {
|
|
18
|
+
payload: {
|
|
19
|
+
/** Null for the top-level list; an event id when scoping to one event. */
|
|
20
|
+
eventId: string | null;
|
|
21
|
+
sortColumn: string;
|
|
22
|
+
ascendingOrder: boolean;
|
|
23
|
+
page: number;
|
|
24
|
+
size: number;
|
|
25
|
+
searchTerm?: string | null;
|
|
26
|
+
filter: EventMeetingFilter;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/** Payload for `POST {apiBaseUrl}/meetings/meetingsDetails` (per-event expand). */
|
|
30
|
+
export interface EventMeetingDetailPayload {
|
|
31
|
+
payload: {
|
|
32
|
+
eventId: string;
|
|
33
|
+
sortColumn: string;
|
|
34
|
+
ascendingOrder: boolean;
|
|
35
|
+
page: number;
|
|
36
|
+
size: number;
|
|
37
|
+
searchTerm?: string | null;
|
|
38
|
+
filter: EventMeetingFilter;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A single node in a group's ancestor hierarchy (root→leaf), as returned by
|
|
3
|
+
* GET /v1/groups/my-groups. Used to render the expandable hierarchy rows in the
|
|
4
|
+
* Your Groups table.
|
|
5
|
+
*/
|
|
6
|
+
export interface GroupHierarchyNode {
|
|
7
|
+
groupId: string;
|
|
8
|
+
groupName: string;
|
|
9
|
+
groupShortName?: string;
|
|
10
|
+
groupAcronym?: string;
|
|
11
|
+
groupLevel?: number;
|
|
12
|
+
groupParentId?: string | null;
|
|
13
|
+
groupType?: string;
|
|
14
|
+
groupTypeName?: string | null;
|
|
15
|
+
groupDesc?: string | null;
|
|
16
|
+
hasChildren?: boolean | null;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Table-facing view of a group in the Your Groups section. The display fields
|
|
20
|
+
* are mapped from the backend; `hierarchy` carries the group's ancestor path so
|
|
21
|
+
* the row can expand to show the hierarchy (matching the My Profile Find Groups
|
|
22
|
+
* tree).
|
|
23
|
+
*/
|
|
1
24
|
export interface GroupRow {
|
|
2
25
|
groupId: string;
|
|
3
26
|
group: string;
|
|
@@ -5,4 +28,6 @@ export interface GroupRow {
|
|
|
5
28
|
officerRole?: string;
|
|
6
29
|
affiliation?: string;
|
|
7
30
|
memberLevel: string;
|
|
31
|
+
/** Ancestor hierarchy (root→leaf) for the expandable hierarchy rows. */
|
|
32
|
+
hierarchy?: GroupHierarchyNode[];
|
|
8
33
|
}
|
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
import { AttendanceState } from './attendance-state.model';
|
|
2
|
+
/**
|
|
3
|
+
* View model for a single meeting row, used both for an event's expanded child
|
|
4
|
+
* meetings and (via {@link UpcomingEvent}) for standalone meeting cards.
|
|
5
|
+
*
|
|
6
|
+
* `startEpochMs` / `endEpochMs` carry the raw epoch-milliseconds values from the
|
|
7
|
+
* backend and are formatted with luxon `DateTime.fromMillis`. The legacy ISO
|
|
8
|
+
* `meetingDate` / `meetingTime` fields are retained for existing fixtures/tests.
|
|
9
|
+
*/
|
|
2
10
|
export interface MeetingRow {
|
|
3
11
|
meetingId: string;
|
|
4
12
|
meetingName: string;
|
|
5
13
|
groupOrCommittee?: string;
|
|
6
14
|
roomOrLocation?: string;
|
|
7
|
-
|
|
8
|
-
|
|
15
|
+
/** Start date-time as an ISO-8601 string (or epoch ms for fixtures). */
|
|
16
|
+
startDateTime?: string | number;
|
|
17
|
+
/** End date-time as an ISO-8601 string (or epoch ms for fixtures). */
|
|
18
|
+
endDateTime?: string | number;
|
|
19
|
+
/** Legacy ISO meeting date, retained for fixtures/tests. */
|
|
20
|
+
meetingDate?: string;
|
|
21
|
+
/** Legacy ISO meeting time, retained for fixtures/tests. */
|
|
22
|
+
meetingTime?: string;
|
|
9
23
|
timezone: string;
|
|
24
|
+
status?: string;
|
|
25
|
+
isMemberOfGroup?: boolean;
|
|
10
26
|
isOpenForAttendance?: boolean;
|
|
11
27
|
attendanceState?: AttendanceState;
|
|
12
28
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read-only aggregate view returned by GET /v1/groups/my-groups, mirroring the
|
|
3
|
+
* groups-api `MyGroupsView` DTO. The dashboard "Your Groups" section consumes
|
|
4
|
+
* the `groups` collection; `interests` is not shown on the dashboard.
|
|
5
|
+
*/
|
|
6
|
+
export interface MyGroupsView {
|
|
7
|
+
groups: MyGroupView[];
|
|
8
|
+
interests?: MyInterestView[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A single officer role the user holds in a group, as returned in the
|
|
12
|
+
* `officer` array of GET /v1/groups/my-groups.
|
|
13
|
+
*/
|
|
14
|
+
export interface GroupOfficer {
|
|
15
|
+
officerId: string;
|
|
16
|
+
officerName: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A single group the user is a roster member of. Carries the group's name,
|
|
20
|
+
* type, affiliations, the user's member level, and the user's officer role(s)
|
|
21
|
+
* for the group (the `officer` array — empty when the user holds no officer
|
|
22
|
+
* role).
|
|
23
|
+
*/
|
|
24
|
+
export interface MyGroupView {
|
|
25
|
+
groupId: string;
|
|
26
|
+
groupName: string;
|
|
27
|
+
groupType?: string;
|
|
28
|
+
groupTypeName?: string | null;
|
|
29
|
+
/** Ancestor hierarchy (root→leaf) of the group, for the expandable rows. */
|
|
30
|
+
hierarchy?: MyGroupHierarchyItem[];
|
|
31
|
+
affiliations?: string[];
|
|
32
|
+
memberLevelId?: string | null;
|
|
33
|
+
memberLevel?: string | null;
|
|
34
|
+
/** Officer roles the user holds in this group (e.g. "Chair"); empty if none. */
|
|
35
|
+
officer?: GroupOfficer[];
|
|
36
|
+
}
|
|
37
|
+
/** A single node in a group's ancestor hierarchy (root→leaf). */
|
|
38
|
+
export interface MyGroupHierarchyItem {
|
|
39
|
+
groupId: string;
|
|
40
|
+
groupName: string;
|
|
41
|
+
groupShortName?: string;
|
|
42
|
+
groupAcronym?: string;
|
|
43
|
+
groupLevel?: number;
|
|
44
|
+
groupParentId?: string | null;
|
|
45
|
+
groupType?: string;
|
|
46
|
+
groupTypeName?: string | null;
|
|
47
|
+
groupDesc?: string | null;
|
|
48
|
+
hasChildren?: boolean | null;
|
|
49
|
+
}
|
|
50
|
+
/** A single interest the user has expressed (not shown on the dashboard). */
|
|
51
|
+
export interface MyInterestView {
|
|
52
|
+
interestId: string;
|
|
53
|
+
groupId: string;
|
|
54
|
+
groupName: string;
|
|
55
|
+
status: string;
|
|
56
|
+
}
|
|
@@ -1,13 +1,51 @@
|
|
|
1
1
|
import { MeetingRow } from './meeting-row.model';
|
|
2
|
+
/**
|
|
3
|
+
* Discriminates how a row in the "Upcoming Meetings & Events" list is rendered.
|
|
4
|
+
* EVENT rows render as an expandable event block that owns child meetings;
|
|
5
|
+
* STANDALONE_MEETING rows render as a single meeting card and always sort LAST
|
|
6
|
+
* within the list.
|
|
7
|
+
*/
|
|
8
|
+
export declare enum UpcomingItemKind {
|
|
9
|
+
EVENT = "EVENT",
|
|
10
|
+
STANDALONE_MEETING = "STANDALONE_MEETING"
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* View model for a single entry in the "Upcoming Meetings & Events" section.
|
|
14
|
+
*
|
|
15
|
+
* When {@link kind} is `EVENT` the entry renders as the expandable event block
|
|
16
|
+
* (header badge, title, "Day X of Y", meeting-count sub-line, dates/timezone,
|
|
17
|
+
* View button, and the show/hide child-meeting list). When `kind` is
|
|
18
|
+
* `STANDALONE_MEETING` the entry renders as a single standalone meeting card
|
|
19
|
+
* (rendered after all events).
|
|
20
|
+
*
|
|
21
|
+
* `startEpochMs` / `endEpochMs` carry the raw epoch-milliseconds values from the
|
|
22
|
+
* backend and are formatted with luxon `DateTime.fromMillis`. The legacy ISO
|
|
23
|
+
* `startDate` / `endDate` fields are retained for existing fixtures/tests.
|
|
24
|
+
*/
|
|
2
25
|
export interface UpcomingEvent {
|
|
3
26
|
eventId: string;
|
|
27
|
+
/** EVENT vs. STANDALONE_MEETING render discriminator. */
|
|
28
|
+
kind: UpcomingItemKind;
|
|
4
29
|
title: string;
|
|
5
30
|
status: string;
|
|
6
31
|
dayIndicator?: string;
|
|
7
32
|
meetingCount: number;
|
|
8
33
|
openForAttendanceCount: number;
|
|
9
|
-
|
|
10
|
-
|
|
34
|
+
/** Start date-time as an ISO-8601 string (or epoch ms for fixtures). */
|
|
35
|
+
startDateTime?: string | number;
|
|
36
|
+
/** End date-time as an ISO-8601 string (or epoch ms for fixtures). */
|
|
37
|
+
endDateTime?: string | number;
|
|
38
|
+
/** Legacy ISO start date, retained for fixtures/tests. */
|
|
39
|
+
startDate?: string;
|
|
40
|
+
/** Legacy ISO end date, retained for fixtures/tests. */
|
|
41
|
+
endDate?: string;
|
|
11
42
|
timezone: string;
|
|
43
|
+
/** Owning group label, shown on standalone-meeting cards. */
|
|
44
|
+
groupOrCommittee?: string;
|
|
45
|
+
/** Room / location, shown on standalone-meeting cards. */
|
|
46
|
+
roomOrLocation?: string;
|
|
47
|
+
/** True when the user is a member of the owning group. */
|
|
48
|
+
isMemberOfGroup?: boolean;
|
|
49
|
+
/** The event's child meetings (empty / lazily loaded for EVENT rows). */
|
|
12
50
|
meetings: MeetingRow[];
|
|
13
51
|
}
|
|
@@ -5,7 +5,9 @@ import { AttendanceState } from '../models/attendance-state.model';
|
|
|
5
5
|
import { DashboardListResponse } from '../models/dashboard-list-response.model';
|
|
6
6
|
import { DashboardSectionState } from '../models/dashboard-section-state.model';
|
|
7
7
|
import { GroupRow } from '../models/group-row.model';
|
|
8
|
+
import { MyGroupsView } from '../models/my-groups-view.model';
|
|
8
9
|
import { UpcomingEvent } from '../models/upcoming-event.model';
|
|
10
|
+
import { EventMeetingDetailResponse, EventMeetingListResponse } from '../models/event-meeting-list-item.model';
|
|
9
11
|
import * as i0 from "@angular/core";
|
|
10
12
|
/**
|
|
11
13
|
* DashboardService is the single source of truth for the dashboard landing
|
|
@@ -16,11 +18,12 @@ import * as i0 from "@angular/core";
|
|
|
16
18
|
* through the shared `HttpService` from `@ieeesa-npm/utility` (never
|
|
17
19
|
* `HttpClient` directly).
|
|
18
20
|
*
|
|
19
|
-
* The upcoming-events
|
|
20
|
-
*
|
|
21
|
-
* the
|
|
22
|
-
*
|
|
23
|
-
*
|
|
21
|
+
* The upcoming-events load calls the real `POST /meetings/eventsAndMeetings`
|
|
22
|
+
* endpoint (child meetings are lazily loaded per-event via
|
|
23
|
+
* `POST /meetings/meetingsDetails`); the groups load calls `GET
|
|
24
|
+
* /groups/my-groups`. The attendance actions compose the pure reducers from
|
|
25
|
+
* `attendance-reducers.ts` so the displayed `AttendanceState` only advances on a
|
|
26
|
+
* successful resolution and the prior state is retained on failure.
|
|
24
27
|
* @export
|
|
25
28
|
* @class DashboardService
|
|
26
29
|
*/
|
|
@@ -58,16 +61,75 @@ export declare class DashboardService {
|
|
|
58
61
|
*/
|
|
59
62
|
setAppConfig(apiBaseURL: string, userPermissions: UserPermission[]): void;
|
|
60
63
|
/**
|
|
61
|
-
* Loads the user's upcoming events
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
64
|
+
* Loads the user's upcoming events & meetings from the real backend via
|
|
65
|
+
* `POST {apiBaseUrl}/meetings/eventsAndMeetings`, the same endpoint the
|
|
66
|
+
* `view-events-meetings-list` screen uses. The response is mapped into the
|
|
67
|
+
* dashboard view models (with STANDALONE_MEETING rows ordered last), the
|
|
68
|
+
* per-meeting attendance-state map is seeded, and the section advances through
|
|
69
|
+
* LOADING → LOADED/EMPTY on success, leaving the caller to set ERROR on
|
|
70
|
+
* failure. Follows the shared `pipe(map, catchError(throw))` pattern.
|
|
71
|
+
* @return {Observable<EventMeetingListResponse>} The upcoming events & meetings response envelope.
|
|
72
|
+
* @memberof DashboardService
|
|
73
|
+
*/
|
|
74
|
+
loadUpcomingEvents(): Observable<EventMeetingListResponse>;
|
|
75
|
+
/**
|
|
76
|
+
* Lazily loads (and paginates) the child meetings of an EVENT row via
|
|
77
|
+
* `POST {apiBaseUrl}/meetings/meetingsDetails` — the per-event expand endpoint
|
|
78
|
+
* used by the reference screen. On success the loaded meetings are mapped and
|
|
79
|
+
* merged onto the matching event in the `upcomingEvents` list (with its
|
|
80
|
+
* `meetingCount` / `openForAttendanceCount` refreshed), and the per-meeting
|
|
81
|
+
* attendance-state map is extended. Each event paginates independently.
|
|
82
|
+
* @param {string} eventId - The event whose meetings to load.
|
|
83
|
+
* @param {number} [page=1] - The one-based page to request.
|
|
84
|
+
* @param {number} [size=EVENT_MEETINGS_PAGE_SIZE] - The page size.
|
|
85
|
+
* @return {Observable<EventMeetingDetailResponse>} The child-meetings response envelope.
|
|
86
|
+
* @memberof DashboardService
|
|
87
|
+
*/
|
|
88
|
+
loadEventMeetings(eventId: string, page?: number, size?: number): Observable<EventMeetingDetailResponse>;
|
|
89
|
+
/**
|
|
90
|
+
* Merges a freshly loaded page of child meetings onto the matching event in
|
|
91
|
+
* the `upcomingEvents` list, refreshing the event's `meetings`,
|
|
92
|
+
* `meetingCount` (from the backend `totalRecords`), and
|
|
93
|
+
* `openForAttendanceCount`. Leaves all other events untouched.
|
|
94
|
+
* @param {string} eventId - The event to merge meetings onto.
|
|
95
|
+
* @param {MeetingRow[]} meetings - The mapped child meetings for the page.
|
|
96
|
+
* @param {number} totalRecords - The event's total meeting count from the backend.
|
|
97
|
+
* @return {void}
|
|
98
|
+
* @memberof DashboardService
|
|
99
|
+
*/
|
|
100
|
+
private mergeEventMeetings;
|
|
101
|
+
/**
|
|
102
|
+
* Eagerly fetches each EVENT's total meeting count and open-for-attendance
|
|
103
|
+
* count by requesting a large first page of its child meetings, then merging
|
|
104
|
+
* only the counts (not the rows) so the collapsed card summaries are accurate
|
|
105
|
+
* before the user expands. Standalone meetings are skipped. Failures per event
|
|
106
|
+
* are swallowed so one failing count never breaks the list.
|
|
107
|
+
* @param {UpcomingEvent[]} events - The loaded events to fetch counts for.
|
|
108
|
+
* @return {void}
|
|
68
109
|
* @memberof DashboardService
|
|
69
110
|
*/
|
|
70
|
-
|
|
111
|
+
private loadEventCounts;
|
|
112
|
+
/**
|
|
113
|
+
* Merges only the meeting counts onto the matching event, leaving its
|
|
114
|
+
* `meetings` rows untouched (used by the eager count prefetch).
|
|
115
|
+
* @param {string} eventId - The event to update.
|
|
116
|
+
* @param {number} totalRecords - The event's total meeting count.
|
|
117
|
+
* @param {number} openForAttendanceCount - The open-for-attendance count.
|
|
118
|
+
* @return {void}
|
|
119
|
+
* @memberof DashboardService
|
|
120
|
+
*/
|
|
121
|
+
private mergeEventCounts;
|
|
122
|
+
/**
|
|
123
|
+
* Builds and posts the `meetingsDetails` request for a single event page,
|
|
124
|
+
* returning the raw response envelope. Shared by {@link loadEventMeetings} and
|
|
125
|
+
* the eager count prefetch.
|
|
126
|
+
* @param {string} eventId - The event whose meetings to fetch.
|
|
127
|
+
* @param {number} page - The one-based page to request.
|
|
128
|
+
* @param {number} size - The page size.
|
|
129
|
+
* @return {Observable<EventMeetingDetailResponse>} The child-meetings response.
|
|
130
|
+
* @memberof DashboardService
|
|
131
|
+
*/
|
|
132
|
+
private fetchEventMeetingsPage;
|
|
71
133
|
/**
|
|
72
134
|
* Loads the user's groups, driving the groups section through
|
|
73
135
|
* LOADING → LOADED/EMPTY on success and leaving the caller to set ERROR on
|
|
@@ -77,7 +139,18 @@ export declare class DashboardService {
|
|
|
77
139
|
* @return {Observable<DashboardListResponse<GroupRow[]>>} The groups response envelope.
|
|
78
140
|
* @memberof DashboardService
|
|
79
141
|
*/
|
|
80
|
-
loadGroups(): Observable<DashboardListResponse<
|
|
142
|
+
loadGroups(): Observable<DashboardListResponse<MyGroupsView>>;
|
|
143
|
+
/**
|
|
144
|
+
* Maps a backend {@link MyGroupView} to the table-facing {@link GroupRow}.
|
|
145
|
+
* Mirrors the My Groups profile tab: the type falls back to "Unassigned" when
|
|
146
|
+
* `groupTypeName` is null, affiliations are comma-joined, empty officer role /
|
|
147
|
+
* affiliation render as a placeholder, and a blank member level becomes
|
|
148
|
+
* "Unassigned" (rendered as the warning pill by the Your Groups component).
|
|
149
|
+
* @param {MyGroupView} group - The backend group view.
|
|
150
|
+
* @return {GroupRow}
|
|
151
|
+
* @memberof DashboardService
|
|
152
|
+
*/
|
|
153
|
+
private mapGroup;
|
|
81
154
|
/**
|
|
82
155
|
* Logs attendance for a meeting. Marks the meeting in-flight (retaining the
|
|
83
156
|
* prior displayed state), posts through `HttpService`, applies the
|
|
@@ -114,6 +187,16 @@ export declare class DashboardService {
|
|
|
114
187
|
* @memberof DashboardService
|
|
115
188
|
*/
|
|
116
189
|
private seedAttendanceStates;
|
|
190
|
+
/**
|
|
191
|
+
* Seeds the attendance-state map from a list of meeting rows, using each
|
|
192
|
+
* meeting's `attendanceState` (defaulting to `NOT_ATTENDING`) without
|
|
193
|
+
* overwriting ids absent from the new list. Shared by the list load and the
|
|
194
|
+
* per-event expand so freshly loaded child meetings pick up their state.
|
|
195
|
+
* @param {MeetingRow[]} meetings - The meeting rows to seed from.
|
|
196
|
+
* @return {void}
|
|
197
|
+
* @memberof DashboardService
|
|
198
|
+
*/
|
|
199
|
+
private seedAttendanceStatesFromMeetings;
|
|
117
200
|
static ɵfac: i0.ɵɵFactoryDeclaration<DashboardService, never>;
|
|
118
201
|
static ɵprov: i0.ɵɵInjectableDeclaration<DashboardService>;
|
|
119
202
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure luxon date/time formatting helpers for the dashboard library.
|
|
3
|
+
*
|
|
4
|
+
* The real "events & meetings" backend returns date-times as ISO-8601 strings
|
|
5
|
+
* (e.g. "2026-01-01T00:00:00") together with a display timezone string
|
|
6
|
+
* (e.g. "(UTC-04:00) America/New_York"). These helpers parse the ISO value and
|
|
7
|
+
* render it in the item's own zone (never moment). A numeric epoch-milliseconds
|
|
8
|
+
* value is also accepted for backward compatibility with fixtures/tests. All
|
|
9
|
+
* helpers fall back gracefully to an empty string when the value is missing or
|
|
10
|
+
* unparseable.
|
|
11
|
+
*/
|
|
12
|
+
import { DateTime } from 'luxon';
|
|
13
|
+
/**
|
|
14
|
+
* Extracts a luxon-usable IANA zone from a backend timezone string such as
|
|
15
|
+
* "(UTC-04:00) America/New_York" or "America/New_York". Returns `undefined`
|
|
16
|
+
* when no usable zone can be derived so luxon falls back to the local zone.
|
|
17
|
+
* @param {string | undefined} timezone - The backend timezone string.
|
|
18
|
+
* @return {string | undefined} The IANA zone id, or undefined.
|
|
19
|
+
*/
|
|
20
|
+
export declare function extractIanaZone(timezone: string | undefined): string | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Parses a backend date-time value — either an ISO-8601 string
|
|
23
|
+
* (e.g. "2026-01-01T00:00:00") or an epoch-milliseconds number — into a luxon
|
|
24
|
+
* {@link DateTime} in the supplied timezone. The ISO value is treated as a wall
|
|
25
|
+
* time in the item's zone so the rendered time matches the backend's intent.
|
|
26
|
+
* Returns an invalid DateTime when the value is missing/unparseable.
|
|
27
|
+
* @param {string | number | undefined | null} value - The ISO string or epoch ms.
|
|
28
|
+
* @param {string | undefined} timezone - The backend timezone string.
|
|
29
|
+
* @return {DateTime} The parsed luxon DateTime (may be invalid).
|
|
30
|
+
*/
|
|
31
|
+
export declare function parseBackendDateTime(value: string | number | undefined | null, timezone?: string): DateTime;
|
|
32
|
+
/**
|
|
33
|
+
* Formats a backend date-time value (ISO string or epoch ms) with luxon using
|
|
34
|
+
* the supplied format token, honouring the supplied timezone. Returns an empty
|
|
35
|
+
* string when the value is missing or invalid.
|
|
36
|
+
* @param {string | number | undefined | null} value - The ISO string or epoch ms.
|
|
37
|
+
* @param {string} format - The luxon `toFormat` token.
|
|
38
|
+
* @param {string | undefined} timezone - The backend timezone string.
|
|
39
|
+
* @return {string} The formatted value, or an empty string.
|
|
40
|
+
*/
|
|
41
|
+
export declare function formatBackendDateTime(value: string | number | undefined | null, format: string, timezone?: string): string;
|
|
42
|
+
/**
|
|
43
|
+
* Backward-compatible alias kept for existing callers. Accepts ISO strings or
|
|
44
|
+
* epoch ms and formats them in the item's zone.
|
|
45
|
+
* @param {string | number | undefined | null} value - The ISO string or epoch ms.
|
|
46
|
+
* @param {string} format - The luxon `toFormat` token.
|
|
47
|
+
* @param {string | undefined} timezone - The backend timezone string.
|
|
48
|
+
* @return {string} The formatted value, or an empty string.
|
|
49
|
+
*/
|
|
50
|
+
export declare function formatEpoch(value: string | number | undefined | null, format: string, timezone?: string): string;
|
|
51
|
+
/**
|
|
52
|
+
* Computes a human "Day X of Y" indicator for a multi-day event from its start
|
|
53
|
+
* and end date-times, relative to "now". Returns an empty string when the dates
|
|
54
|
+
* are missing/invalid or the event spans a single day.
|
|
55
|
+
* @param {string | number | undefined | null} start - Event start (ISO or epoch ms).
|
|
56
|
+
* @param {string | number | undefined | null} end - Event end (ISO or epoch ms).
|
|
57
|
+
* @param {string | undefined} timezone - The backend timezone string.
|
|
58
|
+
* @return {string} The "Day X of Y" label, or an empty string.
|
|
59
|
+
*/
|
|
60
|
+
export declare function computeDayIndicator(start: string | number | undefined | null, end: string | number | undefined | null, timezone?: string): string;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure mappers converting the raw "events & meetings" backend list/detail items
|
|
3
|
+
* into the dashboard view models. No Angular / service dependencies so they are
|
|
4
|
+
* trivially unit-testable and shared by {@link DashboardService}.
|
|
5
|
+
*
|
|
6
|
+
* Backend dates are epoch milliseconds; callers format them with luxon
|
|
7
|
+
* `DateTime.fromMillis` at render time. The list mapper enforces the dashboard
|
|
8
|
+
* rule that STANDALONE_MEETING rows always sort LAST within the section.
|
|
9
|
+
*/
|
|
10
|
+
import { EventMeetingDetailItem, EventMeetingListItem } from '../models/event-meeting-list-item.model';
|
|
11
|
+
import { MeetingRow } from '../models/meeting-row.model';
|
|
12
|
+
import { UpcomingEvent, UpcomingItemKind } from '../models/upcoming-event.model';
|
|
13
|
+
/**
|
|
14
|
+
* Determines whether a raw list item is an EVENT (owns child meetings) or a
|
|
15
|
+
* STANDALONE_MEETING. An item is an EVENT when the backend flags it with
|
|
16
|
+
* `isMeetingEvent === true` or `hasChildren === true`.
|
|
17
|
+
* @param {EventMeetingListItem} item - The raw list item.
|
|
18
|
+
* @return {UpcomingItemKind} The resolved render kind.
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveItemKind(item: EventMeetingListItem): UpcomingItemKind;
|
|
21
|
+
/**
|
|
22
|
+
* Maps a raw backend list item to the {@link UpcomingEvent} view model. EVENT
|
|
23
|
+
* rows start with an empty `meetings` array (child meetings are lazily loaded on
|
|
24
|
+
* expand); STANDALONE_MEETING rows carry their own group/location fields.
|
|
25
|
+
* @param {EventMeetingListItem} item - The raw list item.
|
|
26
|
+
* @return {UpcomingEvent} The mapped view model.
|
|
27
|
+
*/
|
|
28
|
+
export declare function mapListItemToUpcomingEvent(item: EventMeetingListItem): UpcomingEvent;
|
|
29
|
+
/**
|
|
30
|
+
* Maps a raw backend list of events & meetings into the dashboard view models,
|
|
31
|
+
* enforcing that STANDALONE_MEETING rows always sort LAST while preserving the
|
|
32
|
+
* backend's within-group ordering for each partition (stable sort).
|
|
33
|
+
* @param {EventMeetingListItem[]} items - The raw list items.
|
|
34
|
+
* @return {UpcomingEvent[]} The mapped, standalone-last ordered view models.
|
|
35
|
+
*/
|
|
36
|
+
export declare function mapEventMeetingList(items: EventMeetingListItem[]): UpcomingEvent[];
|
|
37
|
+
/**
|
|
38
|
+
* Maps a raw backend child-meeting detail item to the {@link MeetingRow} view
|
|
39
|
+
* model used by the event block's expanded meeting list.
|
|
40
|
+
* @param {EventMeetingDetailItem} item - The raw child-meeting item.
|
|
41
|
+
* @return {MeetingRow} The mapped meeting row.
|
|
42
|
+
*/
|
|
43
|
+
export declare function mapDetailItemToMeetingRow(item: EventMeetingDetailItem): MeetingRow;
|
|
44
|
+
/**
|
|
45
|
+
* Maps a raw backend list of child-meeting detail items to {@link MeetingRow}
|
|
46
|
+
* view models.
|
|
47
|
+
* @param {EventMeetingDetailItem[]} items - The raw child-meeting items.
|
|
48
|
+
* @return {MeetingRow[]} The mapped meeting rows.
|
|
49
|
+
*/
|
|
50
|
+
export declare function mapEventMeetingDetails(items: EventMeetingDetailItem[]): MeetingRow[];
|
package/package.json
CHANGED
package/public-api.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ export * from './lib/models/page-change.model';
|
|
|
14
14
|
export * from './lib/models/dashboard-user-info.model';
|
|
15
15
|
export * from './lib/models/meeting-row.model';
|
|
16
16
|
export * from './lib/models/upcoming-event.model';
|
|
17
|
+
export * from './lib/models/event-meeting-list-item.model';
|
|
18
|
+
export * from './lib/models/event-meeting-list-payload.model';
|
|
17
19
|
export * from './lib/models/group-row.model';
|
|
18
20
|
export * from './lib/models/attendance-action-permissions.model';
|
|
19
21
|
export * from './lib/models/dashboard-list-response.model';
|